Merge "Create non updatable system server stubs"
diff --git a/Android.bp b/Android.bp
index 6a0bdc3..88ed676 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,6 +25,44 @@
 //
 // READ ME: ########################################################
 
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// 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",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 filegroup {
     name: "framework-core-sources",
     srcs: [
@@ -363,6 +401,7 @@
         ":framework-statsd-sources",
         ":framework-tethering-srcs",
         ":framework-wifi-updatable-sources",
+        ":ike-srcs",
         ":updatable-media-srcs",
     ],
     visibility: ["//visibility:private"],
@@ -371,6 +410,7 @@
 java_library {
     name: "framework-updatable-stubs-module_libs_api",
     static_libs: [
+        "android.net.ipsec.ike.stubs.module_lib",
         "framework-media.stubs.module_lib",
         "framework-mediaprovider.stubs.module_lib",
         "framework-permission.stubs.module_lib",
@@ -387,6 +427,7 @@
     name: "framework-all",
     installable: false,
     static_libs: [
+        "android.net.ipsec.ike.impl",
         "framework-minus-apex",
         "framework-mediaprovider.impl",
         "framework-permission.impl",
@@ -484,7 +525,8 @@
         "android.hardware.vibrator-V1.3-java",
         "android.security.apc-java",
         "android.security.authorization-java",
-        "android.system.keystore2-java",
+        "android.security.usermanager-java",
+        "android.system.keystore2-V1-java",
         "android.system.suspend.control.internal-java",
         "devicepolicyprotosnano",
 
@@ -678,6 +720,7 @@
     srcs: [
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
+        ":libtombstone_proto-src",
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
     ],
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 6afed7a..6cece60 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -79,12 +79,13 @@
         "android.hardware.vibrator-V1.3-java",
         "framework-protos",
         "stable.core.platform.api.stubs",
-        // 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.
-        "sdk_system_30_android",
+        // 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",
     ],
     high_mem: true, // Lots of sources => high memory use, see b/170701554
     installable: false,
@@ -302,6 +303,7 @@
     name: "android_stubs_current",
     srcs: [ ":api-stubs-docs-non-updatable" ],
     static_libs: [
+        "android.net.ipsec.ike.stubs",
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-media.stubs",
@@ -321,6 +323,7 @@
     name: "android_system_stubs_current",
     srcs: [ ":system-api-stubs-docs-non-updatable" ],
     static_libs: [
+        "android.net.ipsec.ike.stubs.system",
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-media.stubs.system",
@@ -356,6 +359,7 @@
     static_libs: [
         // Modules do not have test APIs, but we want to include their SystemApis, like we include
         // the SystemApi of framework-non-updatable-sources.
+        "android.net.ipsec.ike.stubs.system",
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-media.stubs.system",
@@ -392,7 +396,11 @@
         "android_defaults_stubs_current",
         "android_stubs_dists_default",
     ],
-    libs: ["sdk_system_29_android"],
+    libs: [
+        "sdk_system_current_android",
+        // NOTE: The below can be removed once the prebuilt stub contains IKE.
+        "sdk_system_current_android.net.ipsec.ike",
+    ],
     static_libs: ["art.module.public.api.stubs"],
     dist: {
         dir: "apistubs/android/module-lib",
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 65c28fb..82e29da 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"],
diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp
index be5072c..1b0b078 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"],
@@ -25,4 +34,4 @@
   platform_apis: true,
   test_suites: ["device-tests"],
   certificate: "platform",
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index 984893a..277ad7e 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/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: "CorePerfTests",
 
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/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 d160d48..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",
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/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 04432f2..91e2074 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"],
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/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index 17033e0..dbb8a2e 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",
 
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/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 49952dc..ce57bd5 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"],
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/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index f02cbcf..1d78f65 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"],
diff --git a/apex/Android.bp b/apex/Android.bp
index 1876110..f3a9362 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -14,190 +14,10 @@
 
 package {
     default_visibility: [":__subpackages__"],
-}
-
-mainline_stubs_args =
-    "--error UnhiddenSystemApi " +
-    "--hide BroadcastBehavior " +
-    "--hide CallbackInterface " +
-    "--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" +
-    "\\)" +
-    " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
-    "\\) "
-
-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,
-
-    // Prevent dependencies that do not specify an sdk_version from accessing the
-    // implementation library by default and force them to use stubs instead.
-    default_to_stubs: true,
-
-    // 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",
-    },
-
-    // installable implies we'll create a non-apex (platform) variant, which
-    // we shouldn't ordinarily need (and it can create issues), so disable that.
-    installable: false,
-
-    // Configure framework module specific metalava options.
-    droiddoc_options: [mainline_stubs_args],
-
-    annotations_enabled: true,
-
-    // Allow access to the stubs from anywhere
-    visibility: ["//visibility:public"],
-    stubs_library_visibility: ["//visibility:public"],
-
-    // Hide impl library and stub sources
-    impl_library_visibility: [
-        ":__pkg__",
-        "//frameworks/base", // For framework-all
-    ],
-    stubs_source_visibility: ["//visibility:private"],
-
-    defaults_visibility: ["//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_visibility: [
-        ":__subpackages__",
-        "//frameworks/base/libs/hwui",
-        "//frameworks/base/wifi",
-        "//packages/modules:__subpackages__",
-        "//packages/providers/MediaProvider:__subpackages__",
-    ],
-}
-
-// 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",
-    },
-    defaults_visibility: [
-        ":__subpackages__",
-        "//packages/modules:__subpackages__",
-    ],
-}
-
-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",
-    },
+    // 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
index bde2bec..b3e81b9 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,8 +1 @@
-# Mainline modularization team
-
-andreionea@google.com
-dariofreni@google.com
-hansson@google.com
-mathewi@google.com
-pedroql@google.com
-satayev@google.com
+file:platform/packages/modules/common:/OWNERS
diff --git a/apex/blobstore/framework/Android.bp b/apex/blobstore/framework/Android.bp
index 3499553..1cb295b 100644
--- a/apex/blobstore/framework/Android.bp
+++ b/apex/blobstore/framework/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"],
+}
+
 filegroup {
     name: "framework-blobstore-sources",
     srcs: [
diff --git a/apex/blobstore/service/Android.bp b/apex/blobstore/service/Android.bp
index f6cbac1..49cfd07 100644
--- a/apex/blobstore/service/Android.bp
+++ b/apex/blobstore/service/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"],
+}
+
 java_library {
     name: "service-blobstore",
     installable: true,
diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp
index 23f5614f..70f7fe9 100644
--- a/apex/jobscheduler/framework/Android.bp
+++ b/apex/jobscheduler/framework/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"],
+}
+
 filegroup {
     name: "framework-jobscheduler-sources",
     srcs: [
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 6ddba69..bb86341 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -1,5 +1,14 @@
 // Job Scheduler Service jar, which will eventually be put in the jobscheduler mainline apex.
 // service-jobscheduler needs to be added to PRODUCT_SYSTEM_SERVER_JARS.
+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: "service-jobscheduler",
     installable: true,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index bb94275..15052f8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -16,7 +16,6 @@
 
 package com.android.server.job.controllers;
 
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 
@@ -325,7 +324,7 @@
         if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
             final long bandwidth = capabilities.getLinkDownstreamBandwidthKbps();
             // If we don't know the bandwidth, all we can do is hope the job finishes in time.
-            if (bandwidth != LINK_BANDWIDTH_UNSPECIFIED) {
+            if (bandwidth > 0) {
                 // Divide by 8 to convert bits to bytes.
                 final long estimatedMillis = ((downloadBytes * DateUtils.SECOND_IN_MILLIS)
                         / (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
@@ -343,7 +342,7 @@
         if (uploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
             final long bandwidth = capabilities.getLinkUpstreamBandwidthKbps();
             // If we don't know the bandwidth, all we can do is hope the job finishes in time.
-            if (bandwidth != LINK_BANDWIDTH_UNSPECIFIED) {
+            if (bandwidth > 0) {
                 // Divide by 8 to convert bits to bytes.
                 final long estimatedMillis = ((uploadBytes * DateUtils.SECOND_IN_MILLIS)
                         / (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
@@ -373,18 +372,16 @@
 
     private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
-        final NetworkCapabilities required;
         // A restricted job that's out of quota MUST use an unmetered network.
         if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
                 && !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
-            required = new NetworkCapabilities(
+            final NetworkCapabilities required = new NetworkCapabilities.Builder(
                     jobStatus.getJob().getRequiredNetwork().networkCapabilities)
-                    .addCapability(NET_CAPABILITY_NOT_METERED);
+                    .addCapability(NET_CAPABILITY_NOT_METERED).build();
+            return required.satisfiedByNetworkCapabilities(capabilities);
         } else {
-            required = jobStatus.getJob().getRequiredNetwork().networkCapabilities;
+            return jobStatus.getJob().getRequiredNetwork().canBeSatisfiedBy(capabilities);
         }
-
-        return required.satisfiedByNetworkCapabilities(capabilities);
     }
 
     private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
@@ -395,9 +392,9 @@
         }
 
         // See if we match after relaxing any unmetered request
-        final NetworkCapabilities relaxed = new NetworkCapabilities(
+        final NetworkCapabilities relaxed = new NetworkCapabilities.Builder(
                 jobStatus.getJob().getRequiredNetwork().networkCapabilities)
-                        .removeCapability(NET_CAPABILITY_NOT_METERED);
+                        .removeCapability(NET_CAPABILITY_NOT_METERED).build();
         if (relaxed.satisfiedByNetworkCapabilities(capabilities)) {
             // TODO: treat this as "maybe" response; need to check quotas
             return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
index 5f1bd37..308741a 100644
--- a/apex/media/Android.bp
+++ b/apex/media/Android.bp
@@ -17,4 +17,10 @@
         "//frameworks/av/apex",
         "//frameworks/av/apex/testing",
     ],
+    // 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/media/aidl/Android.bp b/apex/media/aidl/Android.bp
index 409a048..5bf3271 100644
--- a/apex/media/aidl/Android.bp
+++ b/apex/media/aidl/Android.bp
@@ -14,6 +14,15 @@
 // 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: "stable-mediasession2-aidl-srcs",
     srcs: ["stable/**/*.aidl"],
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 0ff6d44..65f07c2 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/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"],
+}
+
 java_library {
     name: "updatable-media",
 
diff --git a/api/Android.bp b/api/Android.bp
index fdfef4c..2c2bb65 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -14,6 +14,14 @@
 
 package {
     default_visibility: ["//visibility:private"],
+    // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
 }
 
 genrule {
@@ -28,6 +36,7 @@
 genrule {
     name: "frameworks-base-api-current.txt",
     srcs: [
+        ":android.net.ipsec.ike{.public.api.txt}",
         ":art.module.public.api{.public.api.txt}",
         ":conscrypt.module.public.api{.public.api.txt}",
         ":framework-media{.public.api.txt}",
@@ -59,8 +68,25 @@
 }
 
 genrule {
+    name: "frameworks-base-api-current-compat",
+    srcs: [
+        ":android.api.public.latest",
+        ":android-incompatibilities.api.public.latest",
+        ":frameworks-base-api-current.txt",
+    ],
+    out: ["stdout.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 " +
+        "--check-compatibility:api:released $(location :android.api.public.latest) " +
+        "--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " +
+        "$(location :frameworks-base-api-current.txt) " +
+        "> $(genDir)/stdout.txt",
+}
+
+genrule {
     name: "frameworks-base-api-current.srcjar",
     srcs: [
+        ":android.net.ipsec.ike{.public.stubs.source}",
         ":api-stubs-docs-non-updatable",
         ":art.module.public.api{.public.stubs.source}",
         ":conscrypt.module.public.api{.public.stubs.source}",
@@ -82,6 +108,7 @@
 genrule {
     name: "frameworks-base-api-removed.txt",
     srcs: [
+        ":android.net.ipsec.ike{.public.removed-api.txt}",
         ":art.module.public.api{.public.removed-api.txt}",
         ":conscrypt.module.public.api{.public.removed-api.txt}",
         ":framework-media{.public.removed-api.txt}",
@@ -114,6 +141,7 @@
 genrule {
     name: "frameworks-base-api-system-current.txt",
     srcs: [
+        ":android.net.ipsec.ike{.system.api.txt}",
         ":framework-media{.system.api.txt}",
         ":framework-mediaprovider{.system.api.txt}",
         ":framework-permission{.system.api.txt}",
@@ -142,8 +170,27 @@
 }
 
 genrule {
+    name: "frameworks-base-api-system-current-compat",
+    srcs: [
+        ":android.api.system.latest",
+        ":android-incompatibilities.api.system.latest",
+        ":frameworks-base-api-current.txt",
+        ":frameworks-base-api-system-current.txt",
+    ],
+    out: ["stdout.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 " +
+        "--check-compatibility:api:released $(location :android.api.system.latest) " +
+        "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
+        "--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " +
+        "$(location :frameworks-base-api-system-current.txt) " +
+        "> $(genDir)/stdout.txt",
+}
+
+genrule {
     name: "frameworks-base-api-system-removed.txt",
     srcs: [
+        ":android.net.ipsec.ike{.system.removed-api.txt}",
         ":framework-media{.system.removed-api.txt}",
         ":framework-mediaprovider{.system.removed-api.txt}",
         ":framework-permission{.system.removed-api.txt}",
@@ -174,6 +221,7 @@
 genrule {
     name: "frameworks-base-api-module-lib-current.txt",
     srcs: [
+        ":android.net.ipsec.ike{.module-lib.api.txt}",
         ":framework-media{.module-lib.api.txt}",
         ":framework-mediaprovider{.module-lib.api.txt}",
         ":framework-permission{.module-lib.api.txt}",
@@ -201,8 +249,30 @@
 }
 
 genrule {
+    name: "frameworks-base-api-module-lib-current-compat",
+    srcs: [
+        ":android.api.module-lib.latest",
+        ":android-incompatibilities.api.module-lib.latest",
+        ":frameworks-base-api-current.txt",
+        ":frameworks-base-api-module-lib-current.txt",
+    ],
+    out: ["stdout.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 " +
+        "--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
+        // Note: having "public" be the base of module-lib is not perfect -- it should
+        // ideally be a merged public+system), but this will  help when migrating from
+        // MODULE_LIBS -> public.
+        "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
+        "--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
+        "$(location :frameworks-base-api-module-lib-current.txt) " +
+        "> $(genDir)/stdout.txt",
+}
+
+genrule {
     name: "frameworks-base-api-module-lib-removed.txt",
     srcs: [
+        ":android.net.ipsec.ike{.module-lib.removed-api.txt}",
         ":framework-media{.module-lib.removed-api.txt}",
         ":framework-mediaprovider{.module-lib.removed-api.txt}",
         ":framework-permission{.module-lib.removed-api.txt}",
diff --git a/boot/Android.bp b/boot/Android.bp
index dd4066a..4f7c44e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -12,6 +12,17 @@
 // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 boot_image {
     name: "framework-boot-image",
     image_name: "boot",
diff --git a/cmds/am/Android.bp b/cmds/am/Android.bp
index ed73d55..7bb9675 100644
--- a/cmds/am/Android.bp
+++ b/cmds/am/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2008 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_am_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_am_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_host_static {
     name: "libinstrumentation",
     srcs: ["**/*.proto"],
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 14ebb71..4e5b3ba 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_app_process_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_app_process_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "app_process",
 
diff --git a/cmds/appops/Android.bp b/cmds/appops/Android.bp
index 9f330fa..80f8ec6 100644
--- a/cmds/appops/Android.bp
+++ b/cmds/appops/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2014 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_appops_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_appops_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 sh_binary {
     name: "appops",
     src: "appops",
diff --git a/cmds/appwidget/Android.bp b/cmds/appwidget/Android.bp
index 487d3e1..8049038 100644
--- a/cmds/appwidget/Android.bp
+++ b/cmds/appwidget/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2014 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_appwidget_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_appwidget_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "appwidget",
     wrapper: "appwidget",
diff --git a/cmds/backup/Android.bp b/cmds/backup/Android.bp
index 287c23b..5e2a56e 100644
--- a/cmds/backup/Android.bp
+++ b/cmds/backup/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2009 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_backup_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_backup_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "btool",
 
diff --git a/cmds/bmgr/Android.bp b/cmds/bmgr/Android.bp
index b64923b..14beb55 100644
--- a/cmds/bmgr/Android.bp
+++ b/cmds/bmgr/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2007 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_bmgr_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_bmgr_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "bmgr",
     wrapper: "bmgr",
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 757c2b2..2ecbd75 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/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_defaults {
     name: "bootanimation_defaults",
 
diff --git a/cmds/bu/Android.bp b/cmds/bu/Android.bp
index 0866ee0..5b4ec31 100644
--- a/cmds/bu/Android.bp
+++ b/cmds/bu/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2011 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_bu_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_bu_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "bu",
     wrapper: "bu",
diff --git a/cmds/content/Android.bp b/cmds/content/Android.bp
index 96d1469..c70d01e 100644
--- a/cmds/content/Android.bp
+++ b/cmds/content/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2012 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_content_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_content_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "content",
     wrapper: "content",
diff --git a/cmds/device_config/Android.bp b/cmds/device_config/Android.bp
index 67e014a..69572d8 100644
--- a/cmds/device_config/Android.bp
+++ b/cmds/device_config/Android.bp
@@ -1,6 +1,17 @@
 // Copyright 2018 The Android Open Source Project
 //
 
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 sh_binary {
     name: "device_config",
     src: "device_config",
diff --git a/cmds/dpm/Android.bp b/cmds/dpm/Android.bp
index 753121e..665abcd 100644
--- a/cmds/dpm/Android.bp
+++ b/cmds/dpm/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2014 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_dpm_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_dpm_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "dpm",
     wrapper: "dpm",
diff --git a/cmds/hid/Android.bp b/cmds/hid/Android.bp
index 54c8bf3..295c71c 100644
--- a/cmds/hid/Android.bp
+++ b/cmds/hid/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2015 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_hid_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_hid_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "hid",
     wrapper: "hid",
diff --git a/cmds/hid/OWNERS b/cmds/hid/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/cmds/hid/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/cmds/hid/jni/Android.bp b/cmds/hid/jni/Android.bp
index 2c07de0..11d9290 100644
--- a/cmds/hid/jni/Android.bp
+++ b/cmds/hid/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_cmds_hid_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_cmds_hid_license"],
+}
+
 cc_library_shared {
     name: "libhidcommand_jni",
 
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index e21a6b2..5212d80 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/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"],
+}
+
 cc_defaults {
     name: "idmap2_defaults",
     tidy: true,
@@ -26,10 +35,24 @@
     tidy_checks_as_errors: [
         "modernize-*",
         "-modernize-avoid-c-arrays",
+        "-modernize-pass-by-value",
+        "-modernize-replace-disallow-copy-and-assign-macro",
+        "-modernize-use-equals-default",
+        "-modernize-use-nodiscard",
+        "-modernize-use-override",
         "-modernize-use-trailing-return-type",
+        "-modernize-use-using",
         "android-*",
         "misc-*",
+        "-misc-non-private-member-variables-in-classes",
         "readability-*",
+        "-readability-braces-around-statements",
+        "-readability-const-return-type",
+        "-readability-convert-member-functions-to-static",
+        "-readability-else-after-return",
+        "-readability-named-parameter",
+        "-readability-redundant-access-specifiers",
+        "-readability-uppercase-literal-suffix",
     ],
     tidy_flags: [
         "-system-headers",
@@ -132,9 +155,6 @@
         "tests/XmlParserTests.cpp",
         "tests/ZipFileTests.cpp",
     ],
-    required: [
-        "idmap2",
-    ],
     static_libs: ["libgmock"],
     target: {
         android: {
@@ -163,9 +183,19 @@
             shared_libs: [
                 "libz",
             ],
+            data: [
+                ":libz",
+                ":idmap2",
+            ],
         },
     },
-    data: ["tests/data/**/*.apk"],
+    data: [
+        "tests/data/**/*.apk",
+    ],
+    compile_multilib: "first",
+    test_options: {
+        unit_test: true,
+    },
 }
 
 cc_binary {
diff --git a/cmds/idmap2/AndroidTest.xml b/cmds/idmap2/AndroidTest.xml
deleted file mode 100644
index 5147f4e..0000000
--- a/cmds/idmap2/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Config for idmap2_tests">
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push" value="idmap2_tests->/data/local/tmp/idmap2_tests" />
-    </target_preparer>
-    <option name="test-suite-tag" value="idmap2_tests" />
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="idmap2_tests" />
-    </test>
-</configuration>
diff --git a/cmds/ime/Android.bp b/cmds/ime/Android.bp
index 76a16c8..6dd3ba1 100644
--- a/cmds/ime/Android.bp
+++ b/cmds/ime/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2007 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_ime_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_ime_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 sh_binary {
     name: "ime",
     src: "ime",
diff --git a/cmds/incident/Android.bp b/cmds/incident/Android.bp
index 94855aa..147885f 100644
--- a/cmds/incident/Android.bp
+++ b/cmds/incident/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"],
+}
+
 cc_binary {
     name: "incident",
 
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index f07743e..5b819eb 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/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"],
+}
+
 java_binary {
     name: "incident-helper-cmd",
     wrapper: "incident_helper_cmd",
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index c47526a..b0b23f5 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -16,6 +16,15 @@
 // incidentd
 // =========
 
+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_binary {
     name: "incidentd",
 
diff --git a/cmds/input/Android.bp b/cmds/input/Android.bp
index a0ebde6..f41a95e 100644
--- a/cmds/input/Android.bp
+++ b/cmds/input/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2008 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_input_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_input_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "input",
     wrapper: "input",
diff --git a/cmds/interrupter/Android.bp b/cmds/interrupter/Android.bp
index d68e7fe..d7f744d 100644
--- a/cmds/interrupter/Android.bp
+++ b/cmds/interrupter/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: "interrupter",
     host_supported: true,
diff --git a/cmds/locksettings/Android.bp b/cmds/locksettings/Android.bp
index 59ccc5c..3869c8f 100644
--- a/cmds/locksettings/Android.bp
+++ b/cmds/locksettings/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"],
+}
+
 java_binary {
     name: "locksettings",
     wrapper: "locksettings",
diff --git a/cmds/pm/Android.bp b/cmds/pm/Android.bp
index 0644f6e..847dbab 100644
--- a/cmds/pm/Android.bp
+++ b/cmds/pm/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2007 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_pm_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_pm_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 sh_binary {
     name: "pm",
     src: "pm",
diff --git a/cmds/requestsync/Android.bp b/cmds/requestsync/Android.bp
index ef2a8a6..57e8dd3 100644
--- a/cmds/requestsync/Android.bp
+++ b/cmds/requestsync/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2012 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_requestsync_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_requestsync_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "requestsync",
     wrapper: "requestsync",
diff --git a/cmds/screencap/Android.bp b/cmds/screencap/Android.bp
index 248c675..7b61bef 100644
--- a/cmds/screencap/Android.bp
+++ b/cmds/screencap/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_binary {
     name: "screencap",
 
diff --git a/cmds/settings/Android.bp b/cmds/settings/Android.bp
index 8a78e54..cc73006 100644
--- a/cmds/settings/Android.bp
+++ b/cmds/settings/Android.bp
@@ -1,6 +1,17 @@
 // Copyright 2011 The Android Open Source Project
 //
 
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 sh_binary {
     name: "settings",
     src: "settings",
diff --git a/cmds/sm/Android.bp b/cmds/sm/Android.bp
index 11e4e72..ecfacae 100644
--- a/cmds/sm/Android.bp
+++ b/cmds/sm/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2015 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_sm_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_sm_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "sm",
     wrapper: "sm",
diff --git a/cmds/svc/Android.bp b/cmds/svc/Android.bp
index 68b48f1..41a3ebd 100644
--- a/cmds/svc/Android.bp
+++ b/cmds/svc/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2007 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_svc_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_svc_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "svc",
     wrapper: "svc",
diff --git a/cmds/telecom/Android.bp b/cmds/telecom/Android.bp
index 56e147c..4da79c5 100644
--- a/cmds/telecom/Android.bp
+++ b/cmds/telecom/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2015 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_telecom_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_telecom_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "telecom",
     wrapper: "telecom",
diff --git a/cmds/uiautomator/Android.bp b/cmds/uiautomator/Android.bp
index f9cb3dd..a0bf624 100644
--- a/cmds/uiautomator/Android.bp
+++ b/cmds/uiautomator/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"],
+}
+
 genrule {
     name: "uiautomator-last-released-api",
     srcs: ["api/*.txt"],
diff --git a/cmds/uiautomator/cmds/uiautomator/Android.bp b/cmds/uiautomator/cmds/uiautomator/Android.bp
index 68cc5a3..56e2e70 100644
--- a/cmds/uiautomator/cmds/uiautomator/Android.bp
+++ b/cmds/uiautomator/cmds/uiautomator/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_binary {
     name: "uiautomator",
     wrapper: "uiautomator",
diff --git a/cmds/uiautomator/instrumentation/Android.bp b/cmds/uiautomator/instrumentation/Android.bp
index 477f0d1..50e2234 100644
--- a/cmds/uiautomator/instrumentation/Android.bp
+++ b/cmds/uiautomator/instrumentation/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_test {
     name: "uiautomator-instrumentation",
 
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 14b74da..469b452 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/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"],
+}
+
 droidstubs {
     name: "uiautomator-stubs",
     srcs: [
diff --git a/cmds/vr/Android.bp b/cmds/vr/Android.bp
index cb129bd..8936491 100644
--- a/cmds/vr/Android.bp
+++ b/cmds/vr/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2017 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_vr_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_vr_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "vr",
     wrapper: "vr",
diff --git a/cmds/wm/Android.bp b/cmds/wm/Android.bp
index 609f84b..cf6b019 100644
--- a/cmds/wm/Android.bp
+++ b/cmds/wm/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2013 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_wm_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_wm_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 sh_binary {
     name: "wm",
     src: "wm",
diff --git a/config/Android.bp b/config/Android.bp
index 8dd409b..6a6f848 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_base_config_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_config_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "copyright-header",
+    ],
+}
+
 filegroup {
     name: "preloaded-classes-denylist",
     srcs: ["preloaded-classes-denylist"],
diff --git a/config/preloaded-classes-denylist b/config/preloaded-classes-denylist
index 8ab5273..2360ef12 100644
--- a/config/preloaded-classes-denylist
+++ b/config/preloaded-classes-denylist
@@ -4,4 +4,3 @@
 android.os.NullVibrator
 android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.widget.Magnifier
-com.android.server.BootReceiver$2
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 00b9019..170febb 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -14,6 +14,14 @@
 
 package {
     default_visibility: ["//visibility:private"],
+    // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
 }
 
 filegroup {
diff --git a/core/api/current.txt b/core/api/current.txt
index f453cca..cfb5037 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9140,7 +9140,7 @@
     method public boolean getIncludeTxPowerLevel();
     method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
     method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
-    method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
+    method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
     method public java.util.List<android.os.ParcelUuid> getServiceUuids();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
@@ -11922,6 +11922,7 @@
     method public void setAutoRevokePermissionsMode(boolean);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
+    method public void setInstallScenario(int);
     method public void setMultiPackage();
     method public void setOriginatingUid(int);
     method public void setOriginatingUri(@Nullable android.net.Uri);
@@ -12134,6 +12135,9 @@
     field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
     field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
+    field public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
+    field public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY = "android.hardware.keystore.limited_use_key";
+    field public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY = "android.hardware.keystore.single_use_key";
     field public static final String FEATURE_LEANBACK = "android.software.leanback";
     field public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
     field public static final String FEATURE_LIVE_TV = "android.software.live_tv";
@@ -12234,6 +12238,10 @@
     field public static final int INSTALL_REASON_POLICY = 1; // 0x1
     field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
     field public static final int INSTALL_REASON_USER = 4; // 0x4
+    field public static final int INSTALL_SCENARIO_BULK = 2; // 0x2
+    field public static final int INSTALL_SCENARIO_BULK_SECONDARY = 3; // 0x3
+    field public static final int INSTALL_SCENARIO_DEFAULT = 0; // 0x0
+    field public static final int INSTALL_SCENARIO_FAST = 1; // 0x1
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_APEX = 1073741824; // 0x40000000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
@@ -26090,6 +26098,55 @@
 
 }
 
+package android.net.vcn {
+
+  public final class VcnConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Set<android.net.vcn.VcnGatewayConnectionConfig> getGatewayConnectionConfigs();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnConfig> CREATOR;
+  }
+
+  public static final class VcnConfig.Builder {
+    ctor public VcnConfig.Builder(@NonNull android.content.Context);
+    method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig);
+    method @NonNull public android.net.vcn.VcnConfig build();
+  }
+
+  public abstract class VcnControlPlaneConfig {
+  }
+
+  public final class VcnControlPlaneIkeConfig extends android.net.vcn.VcnControlPlaneConfig {
+    ctor public VcnControlPlaneIkeConfig(@NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.TunnelModeChildSessionParams);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams getChildSessionParams();
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams getIkeSessionParams();
+  }
+
+  public final class VcnGatewayConnectionConfig {
+    method @NonNull public int[] getExposedCapabilities();
+    method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
+    method @NonNull public int[] getRequiredUnderlyingCapabilities();
+    method @NonNull public long[] getRetryInterval();
+  }
+
+  public static final class VcnGatewayConnectionConfig.Builder {
+    ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addRequiredUnderlyingCapability(int);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeRequiredUnderlyingCapability(int);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) int);
+    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryInterval(@NonNull long[]);
+  }
+
+  public class VcnManager {
+    method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException;
+    method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException;
+  }
+
+}
+
 package android.nfc {
 
   public class FormatException extends java.lang.Exception {
@@ -29602,8 +29659,8 @@
   }
 
   public final class BugreportManager {
-    method public void cancelBugreport();
-    method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+    method @WorkerThread public void cancelBugreport();
+    method @WorkerThread public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
   public abstract static class BugreportManager.BugreportCallback {
@@ -34323,6 +34380,43 @@
     field public static final String PATH_SETTING_INTENT = "intent";
   }
 
+  public final class SimPhonebookContract {
+    field public static final String AUTHORITY = "com.android.simphonebook";
+    field @NonNull public static final android.net.Uri AUTHORITY_URI;
+  }
+
+  public static final class SimPhonebookContract.ElementaryFiles {
+    method @NonNull public static android.net.Uri getItemUri(int, int);
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-elementary-file";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-elementary-file";
+    field @NonNull public static final android.net.Uri CONTENT_URI;
+    field public static final int EF_ADN = 1; // 0x1
+    field public static final int EF_FDN = 2; // 0x2
+    field public static final int EF_SDN = 3; // 0x3
+    field public static final String EF_TYPE = "ef_type";
+    field public static final int EF_UNKNOWN = 0; // 0x0
+    field public static final String MAX_RECORDS = "max_records";
+    field public static final String NAME_MAX_LENGTH = "name_max_length";
+    field public static final String PHONE_NUMBER_MAX_LENGTH = "phone_number_max_length";
+    field public static final String RECORD_COUNT = "record_count";
+    field public static final String SLOT_INDEX = "slot_index";
+    field public static final String SUBSCRIPTION_ID = "subscription_id";
+  }
+
+  public static final class SimPhonebookContract.SimRecords {
+    method @NonNull public static android.net.Uri getContentUri(int, int);
+    method @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
+    method @NonNull public static android.net.Uri getItemUri(int, int, int);
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-contact_v2";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-contact_v2";
+    field public static final String ELEMENTARY_FILE_TYPE = "elementary_file_type";
+    field public static final int ERROR_NAME_UNSUPPORTED = -1; // 0xffffffff
+    field public static final String NAME = "name";
+    field public static final String PHONE_NUMBER = "phone_number";
+    field public static final String RECORD_NUMBER = "record_number";
+    field public static final String SUBSCRIPTION_ID = "subscription_id";
+  }
+
   public class SyncStateContract {
     ctor public SyncStateContract();
   }
@@ -35919,6 +36013,19 @@
 
 package android.security {
 
+  public final class AppUriAuthenticationPolicy implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,java.util.Map<android.net.Uri,java.lang.String>> getAppAndUriMappings();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.AppUriAuthenticationPolicy> CREATOR;
+  }
+
+  public static final class AppUriAuthenticationPolicy.Builder {
+    ctor public AppUriAuthenticationPolicy.Builder();
+    method @NonNull public android.security.AppUriAuthenticationPolicy.Builder addAppAndUriMapping(@NonNull String, @NonNull android.net.Uri, @NonNull String);
+    method @NonNull public android.security.AppUriAuthenticationPolicy build();
+  }
+
   public final class AttestedKeyPair {
     ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @NonNull java.util.List<java.security.cert.Certificate>);
     method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
@@ -35966,6 +36073,7 @@
     method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String);
     method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String);
     method @NonNull public static android.content.Intent createInstallIntent();
+    method @NonNull public static android.content.Intent createManageCredentialsIntent(@NonNull android.security.AppUriAuthenticationPolicy);
     method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
@@ -36192,6 +36300,7 @@
 
   public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
     method @Nullable public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method @Nullable public String getAttestKeyAlias();
     method public byte[] getAttestationChallenge();
     method @NonNull public String[] getBlockModes();
     method @NonNull public java.util.Date getCertificateNotAfter();
@@ -36205,6 +36314,7 @@
     method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
     method @Nullable public java.util.Date getKeyValidityStart();
     method @NonNull public String getKeystoreAlias();
+    method public int getMaxUsageCount();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
@@ -36225,6 +36335,7 @@
     ctor public KeyGenParameterSpec.Builder(@NonNull String, int);
     method @NonNull public android.security.keystore.KeyGenParameterSpec build();
     method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(@NonNull java.security.spec.AlgorithmParameterSpec);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestKeyAlias(@Nullable String);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(@NonNull java.util.Date);
@@ -36241,6 +36352,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -36263,6 +36375,7 @@
     method public String getKeystoreAlias();
     method public int getOrigin();
     method public int getPurposes();
+    method public int getRemainingUsageCount();
     method public int getSecurityLevel();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
@@ -36320,6 +36433,7 @@
     field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8
     field public static final int ORIGIN_UNKNOWN = 4; // 0x4
     field public static final int PURPOSE_AGREE_KEY = 64; // 0x40
+    field public static final int PURPOSE_ATTEST_KEY = 128; // 0x80
     field public static final int PURPOSE_DECRYPT = 2; // 0x2
     field public static final int PURPOSE_ENCRYPT = 1; // 0x1
     field public static final int PURPOSE_SIGN = 4; // 0x4
@@ -36332,6 +36446,7 @@
     field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
     field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
     field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
+    field public static final int UNRESTRICTED_USAGE_COUNT = -1; // 0xffffffff
   }
 
   public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
@@ -36341,6 +36456,7 @@
     method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
     method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
     method @Nullable public java.util.Date getKeyValidityStart();
+    method public int getMaxUsageCount();
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationType();
@@ -36366,6 +36482,7 @@
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
     method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
@@ -39679,6 +39796,7 @@
     field public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL = "ims.enable_presence_group_subscribe_bool";
     field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool";
     field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool";
+    field public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = "ims.non_rcs_capabilities_cache_expiration_sec_int";
     field public static final String KEY_PREFIX = "ims.";
     field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool";
     field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
@@ -41155,7 +41273,9 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
+    method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, long);
+    method public void setSubscriptionOverrideUnmetered(int, boolean, @NonNull int[], long);
     method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, @NonNull android.app.PendingIntent);
     field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
@@ -41914,7 +42034,11 @@
   }
 
   public class ImsRcsManager {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
     field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
   }
 
@@ -42102,6 +42226,15 @@
     field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
   }
 
+  public final class ImsRegistrationAttributes implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAttributeFlags();
+    method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
+    method public int getTransportType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
+  }
+
   public class RcsUceAdapter {
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
   }
@@ -42118,8 +42251,10 @@
 
   public static class RegistrationManager.RegistrationCallback {
     ctor public RegistrationManager.RegistrationCallback();
-    method public void onRegistered(int);
-    method public void onRegistering(int);
+    method @Deprecated public void onRegistered(int);
+    method public void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
+    method @Deprecated public void onRegistering(int);
+    method public void onRegistering(@NonNull android.telephony.ims.ImsRegistrationAttributes);
     method public void onTechnologyChangeFailed(int, @NonNull android.telephony.ims.ImsReasonInfo);
     method public void onUnregistered(@NonNull android.telephony.ims.ImsReasonInfo);
   }
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ab9799f..374c1c7 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -15,6 +15,7 @@
   }
 
   public class ConnectivityManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
   }
@@ -35,6 +36,14 @@
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
+  public class NetworkWatchlistManager {
+    method @Nullable public byte[] getWatchlistConfigHash();
+  }
+
+  public final class Proxy {
+    method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
+  }
+
   public final class TcpRepairWindow {
     ctor public TcpRepairWindow(int, int, int, int, int, int);
     field public final int maxWindow;
@@ -59,6 +68,7 @@
     method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
     method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
     method public void teardownTestNetwork(@NonNull android.net.Network);
+    field public static final String TEST_TAP_PREFIX = "testtap";
   }
 
   public final class UnderlyingNetworkInfo implements android.os.Parcelable {
@@ -71,6 +81,14 @@
     field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
   }
 
+  public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+    ctor public VpnTransportInfo(int);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+    field public final int type;
+  }
+
 }
 
 package android.os {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 72fcc72..4e7fc29 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -74,6 +74,7 @@
     field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
     field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
     field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
+    field public static final String CONTROL_OEM_PAID_NETWORK_PREFERENCE = "android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE";
     field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
     field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
     field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
@@ -238,6 +239,7 @@
     field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
+    field public static final String UWB_PRIVILEGED = "android.permission.UWB_PRIVILEGED";
     field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
     field public static final String WIFI_ACCESS_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS";
@@ -1429,7 +1431,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
     field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
     field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
@@ -1544,6 +1546,10 @@
     field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
   }
 
+  public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile {
+    method @RequiresPermission(android.Manifest.permission.SEND_SMS) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
+  }
+
   public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
     method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
@@ -1576,6 +1582,7 @@
     field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
     field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
     field public static final int HEADSET_CLIENT = 16; // 0x10
+    field public static final int MAP_CLIENT = 18; // 0x12
     field public static final int PAN = 5; // 0x5
     field public static final int PBAP_CLIENT = 17; // 0x11
     field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
@@ -1613,6 +1620,7 @@
     field public static final int UUID_BYTES_128_BIT = 16; // 0x10
     field public static final int UUID_BYTES_16_BIT = 2; // 0x2
     field public static final int UUID_BYTES_32_BIT = 4; // 0x4
+    field @NonNull public static final android.os.ParcelUuid VOLUME_CONTROL;
   }
 
   public final class BufferConstraint implements android.os.Parcelable {
@@ -1628,7 +1636,7 @@
   public final class BufferConstraints implements android.os.Parcelable {
     ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
     method public int describeContents();
-    method @Nullable public android.bluetooth.BufferConstraint getCodec(int);
+    method @Nullable public android.bluetooth.BufferConstraint forCodec(int);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
     field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
@@ -2131,6 +2139,7 @@
     field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
     field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
     field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
+    field public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION = "android.hardware.telephony.ims.singlereg";
     field public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = -268435456; // 0xf0000000
     field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
     field public static final int FLAG_PERMISSION_AUTO_REVOKED = 131072; // 0x20000
@@ -6004,11 +6013,15 @@
     method public long getExpiryTimeMillis();
     method public long getRefreshTimeMillis();
     method @Nullable public android.net.Uri getUserPortalUrl();
+    method public int getUserPortalUrlSource();
     method @Nullable public String getVenueFriendlyName();
     method @Nullable public android.net.Uri getVenueInfoUrl();
+    method public int getVenueInfoUrlSource();
     method public boolean isCaptive();
     method public boolean isSessionExtendable();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
+    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
     field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
   }
 
@@ -6022,8 +6035,10 @@
     method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
     method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
     method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
     method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
     method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
   }
 
   public class ConnectivityManager {
@@ -6037,6 +6052,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -6058,6 +6074,10 @@
     field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
   }
 
+  public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
+    method public void onComplete();
+  }
+
   @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
     ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
     method @Deprecated public void onTetheringFailed();
@@ -6142,6 +6162,7 @@
     method public void close();
     method @NonNull public String getInterfaceName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
   }
 
   public static class IpSecTransform.Builder {
@@ -6285,6 +6306,7 @@
     method @NonNull public int[] getAdministratorUids();
     method @Nullable public String getSsid();
     method @NonNull public int[] getTransportTypes();
+    method public boolean isPrivateDnsBroken();
     method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
     field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
     field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
@@ -6299,6 +6321,7 @@
     method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
     method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
     method @NonNull public android.net.NetworkCapabilities build();
+    method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
     method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
     method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
@@ -6414,6 +6437,26 @@
     ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
   }
 
+  public final class OemNetworkPreferences implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR;
+    field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1
+    field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2
+    field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3
+    field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4
+    field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0
+  }
+
+  public static final class OemNetworkPreferences.Builder {
+    ctor public OemNetworkPreferences.Builder();
+    ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences);
+    method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int);
+    method @NonNull public android.net.OemNetworkPreferences build();
+    method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
+  }
+
   public abstract class QosCallback {
     ctor public QosCallback();
     method public void onError(@NonNull android.net.QosCallbackException);
@@ -6807,6 +6850,28 @@
 
 }
 
+package android.net.vcn {
+
+  public class VcnManager {
+    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties);
+    method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+  }
+
+  public static interface VcnManager.VcnNetworkPolicyListener {
+    method public void onPolicyChanged();
+  }
+
+  public final class VcnNetworkPolicyResult implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+    method public boolean isTeardownRequested();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnNetworkPolicyResult> CREATOR;
+  }
+
+}
+
 package android.net.wifi {
 
   public final class WifiMigration {
@@ -7147,7 +7212,7 @@
 
   public final class BugreportManager {
     method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
-    method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+    method @RequiresPermission(android.Manifest.permission.DUMP) @WorkerThread public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
   public final class BugreportParams {
@@ -7502,6 +7567,7 @@
   public class SystemConfigManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+    method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
   }
 
   public class SystemProperties {
@@ -7592,6 +7658,7 @@
     method @NonNull public static String formatUid(int);
     method public static int getAppId(int);
     method public int getIdentifier();
+    method public static int getUid(@NonNull android.os.UserHandle, int);
     method @Deprecated public boolean isOwner();
     method public boolean isSystem();
     method public static int myUserId();
@@ -8289,6 +8356,10 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean);
   }
 
+  public static final class SimPhonebookContract.SimRecords {
+    field public static final String QUERY_ARG_PIN2 = "android:query-arg-pin2";
+  }
+
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
     field public static final int CARRIER_EDITED = 4; // 0x4
@@ -8408,14 +8479,21 @@
   }
 
   public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method @Nullable public int[] getAttestationIds();
     method public int getNamespace();
   }
 
   public static final class KeyGenParameterSpec.Builder {
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationIds(@NonNull int[]);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
     method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
   }
 
+  public abstract class KeyProperties {
+    field public static final int NAMESPACE_APPLICATION = -1; // 0xffffffff
+    field public static final int NAMESPACE_WIFI = 102; // 0x66
+  }
+
 }
 
 package android.security.keystore.recovery {
@@ -10704,35 +10782,6 @@
 
 package android.telephony.data {
 
-  public final class ApnThrottleStatus implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getApnType();
-    method public int getRetryType();
-    method public int getSlotIndex();
-    method public long getThrottleExpiryTimeMillis();
-    method public int getThrottleType();
-    method public int getTransportType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ApnThrottleStatus> CREATOR;
-    field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
-    field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
-    field public static final int RETRY_TYPE_NONE = 1; // 0x1
-    field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
-    field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
-  }
-
-  public static final class ApnThrottleStatus.Builder {
-    ctor public ApnThrottleStatus.Builder();
-    method @NonNull public android.telephony.data.ApnThrottleStatus build();
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setApnType(int);
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setNoThrottle();
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setRetryType(int);
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setSlotIndex(int);
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
-    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setTransportType(int);
-    field public static final long NO_THROTTLE_EXPIRY_TIME = -1L; // 0xffffffffffffffffL
-  }
-
   public final class DataCallResponse implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -10902,7 +10951,7 @@
     ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
     method public abstract void close();
     method public final int getSlotIndex();
-    method public void reportApnThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ApnThrottleStatus>);
+    method public void reportThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ThrottleStatus>);
     method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
   }
 
@@ -10932,6 +10981,34 @@
     method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
   }
 
+  public final class ThrottleStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getApnType();
+    method public int getRetryType();
+    method public int getSlotIndex();
+    method public long getThrottleExpiryTimeMillis();
+    method public int getThrottleType();
+    method public int getTransportType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ThrottleStatus> CREATOR;
+    field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
+    field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
+    field public static final int RETRY_TYPE_NONE = 1; // 0x1
+    field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
+    field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
+  }
+
+  public static final class ThrottleStatus.Builder {
+    ctor public ThrottleStatus.Builder();
+    method @NonNull public android.telephony.data.ThrottleStatus build();
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setApnType(int);
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setNoThrottle();
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setRetryType(int);
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setSlotIndex(int);
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
+    method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int);
+  }
+
 }
 
 package android.telephony.euicc {
@@ -11519,12 +11596,35 @@
 
   @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
     ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
+    method @Deprecated public void onRegistered(int);
+    method @Deprecated public void onRegistering(int);
+  }
+
+  public class ImsRcsManager {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnAvailabilityChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnAvailabilityChangedListener(@NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener);
+  }
+
+  public static interface ImsRcsManager.OnAvailabilityChangedListener {
+    method public void onAvailabilityChanged(int);
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
     field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
   }
 
+  public final class ImsRegistrationAttributes implements android.os.Parcelable {
+    method public int getRegistrationTechnology();
+  }
+
+  public static final class ImsRegistrationAttributes.Builder {
+    ctor public ImsRegistrationAttributes.Builder(int);
+    method @NonNull public android.telephony.ims.ImsRegistrationAttributes build();
+    method @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setFeatureTags(@NonNull java.util.Set<java.lang.String>);
+  }
+
   public class ImsService extends android.app.Service {
     ctor public ImsService();
     method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
@@ -12161,20 +12261,39 @@
     ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
     method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+    method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
+    method public boolean queryCapabilityConfiguration(int, int);
+    method @NonNull public final android.telephony.ims.feature.RcsFeature.RcsImsCapabilities queryCapabilityStatus();
     method public void removeCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
   }
 
+  public static class RcsFeature.RcsImsCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
+    ctor public RcsFeature.RcsImsCapabilities(int);
+    method public void addCapabilities(int);
+    method public boolean isCapable(int);
+    method public void removeCapabilities(int);
+    field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+    field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
+  }
+
 }
 
 package android.telephony.ims.stub {
 
   public interface CapabilityExchangeEventListener {
+    method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException;
     method public void onRequestPublishCapabilities(int) throws android.telephony.ims.ImsException;
     method public void onUnpublish() throws android.telephony.ims.ImsException;
   }
 
+  public static interface CapabilityExchangeEventListener.OptionsRequestCallback {
+    method public default void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean);
+    method public void onRespondToCapabilityRequestWithError(@IntRange(from=100, to=699) int, @NonNull String);
+  }
+
   public interface DelegateConnectionMessageCallback {
     method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage);
     method public void onMessageSendFailure(@NonNull String, int);
@@ -12295,7 +12414,9 @@
     ctor public ImsRegistrationImplBase();
     method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
     method public final void onRegistered(int);
+    method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
     method public final void onRegistering(int);
+    method public final void onRegistering(@NonNull android.telephony.ims.ImsRegistrationAttributes);
     method public final void onSubscriberAssociatedUriChanged(android.net.Uri[]);
     method public final void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo);
     method public void triggerFullNetworkRegistration(@IntRange(from=100, to=699) int, @Nullable String);
@@ -12358,6 +12479,7 @@
   public class RcsCapabilityExchangeImplBase {
     ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
     method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
+    method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
     method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
     field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
     field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
@@ -12372,14 +12494,21 @@
     field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
   }
 
+  public static interface RcsCapabilityExchangeImplBase.OptionsResponseCallback {
+    method public void onCommandError(int) throws android.telephony.ims.ImsException;
+    method public void onNetworkResponse(int, @NonNull String, @NonNull java.util.List<java.lang.String>) throws android.telephony.ims.ImsException;
+  }
+
   public static interface RcsCapabilityExchangeImplBase.PublishResponseCallback {
     method public void onCommandError(int) throws android.telephony.ims.ImsException;
     method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
+    method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String, @IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
   }
 
   public static interface RcsCapabilityExchangeImplBase.SubscribeResponseCallback {
     method public void onCommandError(int) throws android.telephony.ims.ImsException;
     method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
+    method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String, @IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
     method public void onNotifyCapabilitiesUpdate(@NonNull java.util.List<java.lang.String>) throws android.telephony.ims.ImsException;
     method public void onResourceTerminated(@NonNull java.util.List<android.util.Pair<android.net.Uri,java.lang.String>>) throws android.telephony.ims.ImsException;
     method public void onTerminated(@NonNull String, long) throws android.telephony.ims.ImsException;
@@ -12606,10 +12735,10 @@
   }
 
   public final class RangingSession implements java.lang.AutoCloseable {
-    method public void close();
-    method public void reconfigure(@NonNull android.os.PersistableBundle);
-    method public void start(@NonNull android.os.PersistableBundle);
-    method public void stop();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void close();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void reconfigure(@NonNull android.os.PersistableBundle);
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void start(@NonNull android.os.PersistableBundle);
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void stop();
   }
 
   public static interface RangingSession.Callback {
@@ -12645,18 +12774,18 @@
   }
 
   public final class UwbManager {
-    method public long elapsedRealtimeResolutionNanos();
-    method public int getAngleOfArrivalSupport();
-    method public int getMaxRemoteDevicesPerInitiatorSession();
-    method public int getMaxRemoteDevicesPerResponderSession();
-    method public int getMaxSimultaneousSessions();
-    method @NonNull public android.os.PersistableBundle getSpecificationInfo();
-    method @NonNull public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
-    method @NonNull public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
-    method public boolean isRangingSupported();
-    method @NonNull public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
-    method public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
-    method public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getAngleOfArrivalSupport();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerInitiatorSession();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerResponderSession();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxSimultaneousSessions();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public boolean isRangingSupported();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
+    method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
     field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2
     field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3
     field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 546e72b..6872141 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -12,12 +12,14 @@
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
+    field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
     field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
     field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
     field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
+    field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
@@ -988,6 +990,12 @@
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
+  public class NetworkPolicyManager {
+    method public boolean getRestrictBackground();
+    method @NonNull public static String resolveNetworkId(@NonNull android.net.wifi.WifiConfiguration);
+    method public void setRestrictBackground(boolean);
+  }
+
   public class NetworkStack {
     method public static void setServiceForTest(@Nullable android.os.IBinder);
   }
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index f5ab40a..b3636b9 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -483,6 +483,8 @@
     
 GetterSetterNames: android.location.LocationRequest#isLowPowerMode():
     
+GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground():
+    Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground`
 GetterSetterNames: android.os.IncidentReportArgs#isAll():
     
 GetterSetterNames: android.service.notification.NotificationStats#setDirectReplied():
diff --git a/core/java/Android.bp b/core/java/Android.bp
index fb27f74..2fdf9c1 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -1,3 +1,14 @@
+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
+    //   SPDX-license-identifier-BSD
+    //   legacy_unencumbered
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "IKeyAttestationApplicationIdProvider.aidl",
     srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
@@ -7,3 +18,8 @@
     name: "IDropBoxManagerService.aidl",
     srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
 }
+
+filegroup {
+    name: "ITracingServiceProxy.aidl",
+    srcs: ["android/tracing/ITracingServiceProxy.aidl"],
+}
diff --git a/core/java/android/accounts/OWNERS b/core/java/android/accounts/OWNERS
index ea5fd36..8dcc04a 100644
--- a/core/java/android/accounts/OWNERS
+++ b/core/java/android/accounts/OWNERS
@@ -3,7 +3,6 @@
 sandrakwan@google.com
 hackbod@google.com
 svetoslavganov@google.com
-moltmann@google.com
 fkupolov@google.com
 yamasani@google.com
 omakoto@google.com
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bfde2d5..b99d5cd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -88,7 +88,6 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.inputmethodservice.InputMethodService;
 import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
 import android.net.Proxy;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -6546,25 +6545,6 @@
         HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE);
         HardwareRenderer.setPackageName(data.appInfo.packageName);
 
-        /**
-         * Initialize the default http proxy in this process for the reasons we set the time zone.
-         */
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
-        final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
-        if (b != null) {
-            // In pre-boot mode (doing initial launch to collect password), not
-            // all system is up.  This includes the connectivity service, so don't
-            // crash if we can't get it.
-            final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-            try {
-                Proxy.setHttpProxySystemProperty(service.getProxyForNetwork(null));
-            } catch (RemoteException e) {
-                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                throw e.rethrowFromSystemServer();
-            }
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
         // Instrumentation info affects the class loader, so load it before
         // setting up the app context.
         final InstrumentationInfo ii;
@@ -6603,6 +6583,23 @@
         updateLocaleListFromAppContext(appContext,
                 mResourcesManager.getConfiguration().getLocales());
 
+        // Initialize the default http proxy in this process.
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
+        try {
+            // In pre-boot mode (doing initial launch to collect password), not all system is up.
+            // This includes the connectivity service, so trying to obtain ConnectivityManager at
+            // that point would return null. Check whether the ConnectivityService is available, and
+            // avoid crashing with a NullPointerException if it is not.
+            final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+            if (b != null) {
+                final ConnectivityManager cm =
+                        appContext.getSystemService(ConnectivityManager.class);
+                Proxy.setHttpProxyConfiguration(cm.getDefaultProxy());
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+        }
+
         if (!Process.isIsolated()) {
             final int oldMask = StrictMode.allowThreadDiskWritesMask();
             try {
@@ -7429,8 +7426,8 @@
     }
 
     public static void updateHttpProxy(@NonNull Context context) {
-        final ConnectivityManager cm = ConnectivityManager.from(context);
-        Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
+        final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
+        Proxy.setHttpProxyConfiguration(cm.getDefaultProxy());
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 31ab224..797253af 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1136,9 +1136,16 @@
     // TODO: Add as AppProtoEnums
     public static final int OP_RECORD_AUDIO_HOTWORD = 102;
 
+    /**
+     * Manage credentials in the system KeyChain.
+     *
+     * @hide
+     */
+    public static final int OP_MANAGE_CREDENTIALS = AppProtoEnums.APP_OP_MANAGE_CREDENTIALS;
+
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 104;
+    public static final int _NUM_OP = 105;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1485,6 +1492,13 @@
      */
     public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword";
 
+    /**
+     * Manage credentials in the system KeyChain.
+     *
+     * @hide
+     */
+    public static final String OPSTR_MANAGE_CREDENTIALS = "android:manage_credentials";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1679,6 +1693,7 @@
             OP_PHONE_CALL_CAMERA,               // OP_PHONE_CALL_CAMERA
             OP_RECORD_AUDIO_HOTWORD,            // RECORD_AUDIO_HOTWORD
             OP_MANAGE_ONGOING_CALLS,            // MANAGE_ONGOING_CALLS
+            OP_MANAGE_CREDENTIALS,              // MANAGE_CREDENTIALS
     };
 
     /**
@@ -1789,6 +1804,7 @@
             OPSTR_PHONE_CALL_CAMERA,
             OPSTR_RECORD_AUDIO_HOTWORD,
             OPSTR_MANAGE_ONGOING_CALLS,
+            OPSTR_MANAGE_CREDENTIALS,
     };
 
     /**
@@ -1900,6 +1916,7 @@
             "PHONE_CALL_CAMERA",
             "RECORD_AUDIO_HOTWORD",
             "MANAGE_ONGOING_CALLS",
+            "MANAGE_CREDENTIALS",
     };
 
     /**
@@ -2012,6 +2029,7 @@
             null, // no permission for OP_PHONE_CALL_CAMERA
             null, // no permission for OP_RECORD_AUDIO_HOTWORD
             Manifest.permission.MANAGE_ONGOING_CALLS,
+            null, // no permission for OP_MANAGE_CREDENTIALS
     };
 
     /**
@@ -2124,6 +2142,7 @@
             null, // PHONE_CALL_MICROPHONE
             null, // RECORD_AUDIO_HOTWORD
             null, // MANAGE_ONGOING_CALLS
+            null, // MANAGE_CREDENTIALS
     };
 
     /**
@@ -2235,6 +2254,7 @@
             null, // PHONE_CALL_CAMERA
             null, // RECORD_AUDIO_HOTWORD
             null, // MANAGE_ONGOING_CALLS
+            null, // MANAGE_CREDENTIALS
     };
 
     /**
@@ -2345,6 +2365,7 @@
             AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
             AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
             AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
+            AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
     };
 
     /**
@@ -2459,6 +2480,7 @@
             false, // PHONE_CALL_CAMERA
             false, // RECORD_AUDIO_HOTWORD
             true, // MANAGE_ONGOING_CALLS
+            false, // MANAGE_CREDENTIALS
     };
 
     /**
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 69d5c8d..854f5a4 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -428,6 +428,13 @@
      */
     private IAppTraceRetriever mAppTraceRetriever;
 
+    /**
+     * ParcelFileDescriptor pointing to a native tombstone.
+     *
+     * @see #getTraceInputStream
+     */
+    private IParcelFileDescriptorRetriever mNativeTombstoneRetriever;
+
     /** @hide */
     @IntDef(prefix = { "REASON_" }, value = {
         REASON_UNKNOWN,
@@ -603,22 +610,38 @@
      * prior to the death of the process; typically it'll be available when
      * the reason is {@link #REASON_ANR}, though if the process gets an ANR
      * but recovers, and dies for another reason later, this trace will be included
-     * in the record of {@link ApplicationExitInfo} still.
+     * in the record of {@link ApplicationExitInfo} still. Beginning with API 31,
+     * tombstone traces will be returned for
+     * {@link #REASON_CRASH_NATIVE}, with an InputStream containing a protobuf with
+     * <a href="https://android.googlesource.com/platform/system/core/+/refs/heads/master/debuggerd/proto/tombstone.proto">this schema</a>.
+     * Note thatbecause these traces are kept in a separate global circular buffer, crashes may be
+     * overwritten by newer crashes (including from other applications), so this may still return
+     * null.
      *
      * @return The input stream to the traces that was taken by the system
      *         prior to the death of the process.
      */
     public @Nullable InputStream getTraceInputStream() throws IOException {
-        if (mAppTraceRetriever == null) {
+        if (mAppTraceRetriever == null && mNativeTombstoneRetriever == null) {
             return null;
         }
+
         try {
-            final ParcelFileDescriptor fd = mAppTraceRetriever.getTraceFileDescriptor(
-                    mPackageName, mPackageUid, mPid);
-            if (fd == null) {
-                return null;
+            if (mNativeTombstoneRetriever != null) {
+                final ParcelFileDescriptor pfd = mNativeTombstoneRetriever.getPfd();
+                if (pfd == null) {
+                    return null;
+                }
+
+                return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            } else {
+                final ParcelFileDescriptor fd = mAppTraceRetriever.getTraceFileDescriptor(
+                        mPackageName, mPackageUid, mPid);
+                if (fd == null) {
+                    return null;
+                }
+                return new GZIPInputStream(new ParcelFileDescriptor.AutoCloseInputStream(fd));
             }
-            return new GZIPInputStream(new ParcelFileDescriptor.AutoCloseInputStream(fd));
         } catch (RemoteException e) {
             return null;
         }
@@ -849,6 +872,15 @@
         mAppTraceRetriever = retriever;
     }
 
+    /**
+     * @see mNativeTombstoneRetriever
+     *
+     * @hide
+     */
+    public void setNativeTombstoneRetriever(final IParcelFileDescriptorRetriever retriever) {
+        mNativeTombstoneRetriever = retriever;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -878,6 +910,12 @@
         } else {
             dest.writeInt(0);
         }
+        if (mNativeTombstoneRetriever != null) {
+            dest.writeInt(1);
+            dest.writeStrongBinder(mNativeTombstoneRetriever.asBinder());
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** @hide */
@@ -906,6 +944,7 @@
         mState = other.mState;
         mTraceFile = other.mTraceFile;
         mAppTraceRetriever = other.mAppTraceRetriever;
+        mNativeTombstoneRetriever = other.mNativeTombstoneRetriever;
     }
 
     private ApplicationExitInfo(@NonNull Parcel in) {
@@ -928,6 +967,10 @@
         if (in.readInt() == 1) {
             mAppTraceRetriever = IAppTraceRetriever.Stub.asInterface(in.readStrongBinder());
         }
+        if (in.readInt() == 1) {
+            mNativeTombstoneRetriever = IParcelFileDescriptorRetriever.Stub.asInterface(
+                    in.readStrongBinder());
+        }
     }
 
     public @NonNull static final Creator<ApplicationExitInfo> CREATOR =
@@ -986,6 +1029,7 @@
         sb.append(" state=").append(ArrayUtils.isEmpty(mState)
                 ? "empty" : Integer.toString(mState.length) + " bytes");
         sb.append(" trace=").append(mTraceFile);
+
         return sb.toString();
     }
 
diff --git a/tools/hiddenapi/Android.bp b/core/java/android/app/IParcelFileDescriptorRetriever.aidl
similarity index 67%
rename from tools/hiddenapi/Android.bp
rename to core/java/android/app/IParcelFileDescriptorRetriever.aidl
index e0eb06cb..7e808e7 100644
--- a/tools/hiddenapi/Android.bp
+++ b/core/java/android/app/IParcelFileDescriptorRetriever.aidl
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-python_binary_host {
-	name: "merge_csv",
-	main: "merge_csv.py",
-	srcs: ["merge_csv.py"],
-	version: {
-		py2: {
-			enabled: false,
-		},
-		py3: {
-			enabled: true,
-			embedded_launcher: true
-		},
-	},
+package android.app;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * An interface used to lazily provide a ParcelFileDescriptor to apps.
+ *
+ * @hide
+ */
+interface IParcelFileDescriptorRetriever {
+    /**
+     * Retrieve the ParcelFileDescriptor.
+     */
+    ParcelFileDescriptor getPfd();
 }
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index e6aa7a7..1ff64db 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -59,7 +59,7 @@
 per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
 
 # ResourcesManager
-per-file ResourcesManager.java = rtmitchell@google.com, toddke@google.com
+per-file ResourcesManager.java = file:RESOURCES_OWNERS
 
 # VoiceInteraction
 per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/android/app/RESOURCES_OWNERS b/core/java/android/app/RESOURCES_OWNERS
new file mode 100644
index 0000000..21c39a8
--- /dev/null
+++ b/core/java/android/app/RESOURCES_OWNERS
@@ -0,0 +1,2 @@
+rtmitchell@google.com
+toddke@google.com
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d151526..331a0b1 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -43,6 +43,7 @@
 import android.app.usage.NetworkStatsManager;
 import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageStatsManager;
+import android.apphibernation.AppHibernationManager;
 import android.appwidget.AppWidgetManager;
 import android.bluetooth.BluetoothManager;
 import android.companion.CompanionDeviceManager;
@@ -116,11 +117,13 @@
 import android.net.IEthernetManager;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.IVpnManager;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.NetworkWatchlistManager;
 import android.net.TetheringManager;
+import android.net.VpnManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
@@ -358,6 +361,15 @@
                         ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
             }});
 
+        registerService(Context.VPN_MANAGEMENT_SERVICE, VpnManager.class,
+                new CachedServiceFetcher<VpnManager>() {
+            @Override
+            public VpnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE);
+                IVpnManager service = IVpnManager.Stub.asInterface(b);
+                return new VpnManager(ctx, service);
+            }});
+
         registerService(Context.VCN_MANAGEMENT_SERVICE, VcnManager.class,
                 new CachedServiceFetcher<VcnManager>() {
             @Override
@@ -1284,6 +1296,13 @@
                         IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE);
                         return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b));
                     }});
+        registerService(Context.APP_HIBERNATION_SERVICE, AppHibernationManager.class,
+                new CachedServiceFetcher<AppHibernationManager>() {
+                    @Override
+                    public AppHibernationManager createService(ContextImpl ctx) {
+                        IBinder b = ServiceManager.getService(Context.APP_HIBERNATION_SERVICE);
+                        return b == null ? null : new AppHibernationManager(ctx);
+                    }});
         registerService(Context.DREAM_SERVICE, DreamManager.class,
                 new CachedServiceFetcher<DreamManager>() {
                     @Override
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index 28b7340..ab38832 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -20,8 +20,16 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.IPlatformCompat;
+
+import java.util.Map;
+
 /**
  * CompatChanges APIs - to be used by platform code only (including mainline
  * modules).
@@ -89,4 +97,25 @@
         return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid));
     }
 
+    /**
+     * Set an app compat override for a given package. This will check whether the caller is allowed
+     * to perform this operation on the given apk and build. Only the installer package is allowed
+     * to set overrides on a non-debuggable final build and a non-test apk.
+     *
+     * @param packageName The package name of the app in question.
+     * @param overrides A map from changeId to the override applied for this change id.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG)
+    public static void setPackageOverride(String packageName,
+            Map<Long, PackageOverride> overrides) {
+        IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+        CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides);
+        try {
+            platformCompat.setOverridesFromInstaller(config, packageName);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/compat/OWNERS b/core/java/android/app/compat/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/core/java/android/app/compat/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
new file mode 100644
index 0000000..9f97cd4
--- /dev/null
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -0,0 +1,211 @@
+/*
+ * 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.compat;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An app compat override applied to a given package and change id pairing.
+ *
+ * A package override contains a list of version ranges with the desired boolean value of
+ * the override for the app in this version range. Ranges can be open ended in either direction.
+ * An instance of PackageOverride gets created via {@link Builder} and is immutable once created.
+ *
+ * @hide
+ */
+public class PackageOverride implements Parcelable {
+
+    @IntDef({
+            VALUE_UNDEFINED,
+            VALUE_ENABLED,
+            VALUE_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    /** @hide */
+    public @interface EvaluatedOverride {
+    }
+
+    /**
+     * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+     * this PackageOverride does not define the value of the override for the given version.
+     * @hide
+     */
+    public static final int VALUE_UNDEFINED = 0;
+    /**
+     * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+     * the override evaluates to {@code true} for the given version.
+     * @hide
+     */
+    public static final int VALUE_ENABLED = 1;
+    /**
+     * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+     * the override evaluates to {@code fakse} for the given version.
+     * @hide
+     */
+    public static final int VALUE_DISABLED = 2;
+
+    private final long mMinVersionCode;
+    private final long mMaxVersionCode;
+    private final boolean mEnabled;
+
+    private PackageOverride(long minVersionCode,
+            long maxVersionCode,
+            boolean enabled) {
+        this.mMinVersionCode = minVersionCode;
+        this.mMaxVersionCode = maxVersionCode;
+        this.mEnabled = enabled;
+    }
+
+    private PackageOverride(Parcel in) {
+        this(in.readLong(), in.readLong(), in.readBoolean());
+    }
+
+    /**
+     * Evaluate the override for the given {@code versionCode}. If no override is defined for
+     * the specified version code, {@link #VALUE_UNDEFINED} is returned.
+     * @hide
+     */
+    public @EvaluatedOverride int evaluate(long versionCode) {
+        if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) {
+            return mEnabled ? VALUE_ENABLED : VALUE_DISABLED;
+        }
+        return VALUE_UNDEFINED;
+    }
+
+    /**
+     * Evaluate the override independent of version code, i.e. only return an evaluated value if
+     * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned.
+     * @hide
+     */
+    public int evaluateForAllVersions() {
+        if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
+            return mEnabled ? VALUE_ENABLED : VALUE_DISABLED;
+        }
+        return VALUE_UNDEFINED;
+    }
+
+    /** Returns the minimum version code the override applies to. */
+    public long getMinVersionCode() {
+        return mMinVersionCode;
+    }
+
+    /** Returns the minimum version code the override applies from. */
+    public long getMaxVersionCode() {
+        return mMaxVersionCode;
+    }
+
+    /** Returns the enabled value for the override. */
+    public boolean getEnabled() {
+        return mEnabled;
+    }
+
+    /** @hide */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mMinVersionCode);
+        dest.writeLong(mMaxVersionCode);
+        dest.writeBoolean(mEnabled);
+    }
+
+    /** @hide */
+    @Override
+    public String toString() {
+        if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
+            return Boolean.toString(mEnabled);
+        }
+        return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled);
+    }
+
+    /** @hide */
+    public static final Creator<PackageOverride> CREATOR =
+            new Creator<PackageOverride>() {
+
+                @Override
+                public PackageOverride createFromParcel(Parcel in) {
+                    return new PackageOverride(in);
+                }
+
+                @Override
+                public PackageOverride[] newArray(int size) {
+                    return new PackageOverride[size];
+                }
+            };
+
+    /**
+     * Builder to construct a PackageOverride.
+     */
+    public static class Builder {
+        private long mMinVersionCode = Long.MIN_VALUE;
+        private long mMaxVersionCode = Long.MAX_VALUE;
+        private boolean mEnabled;
+
+        /**
+         * Sets the minimum version code the override should apply from.
+         *
+         * default value: {@code Long.MIN_VALUE}.
+         */
+        public Builder setMinVersionCode(long minVersionCode) {
+            mMinVersionCode = minVersionCode;
+            return this;
+        }
+
+        /**
+         * Sets the maximum version code the override should apply to.
+         *
+         * default value: {@code Long.MAX_VALUE}.
+         */
+        public Builder setMaxVersionCode(long maxVersionCode) {
+            mMaxVersionCode = maxVersionCode;
+            return this;
+        }
+
+        /**
+         * Sets whether the override should be enabled for the given version range.
+         *
+         * default value: {@code false}.
+         */
+        public Builder setEnabled(boolean enabled) {
+            mEnabled = enabled;
+            return this;
+        }
+
+        /**
+         * Build the {@link PackageOverride}.
+         *
+         * @throws IllegalArgumentException if {@code minVersionCode} is larger than
+         *                                  {@code maxVersionCode}.
+         */
+        public PackageOverride build() {
+            if (mMinVersionCode > mMaxVersionCode) {
+                throw new IllegalArgumentException("minVersionCode must not be larger than "
+                        + "maxVersionCode");
+            }
+            return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled);
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index cd91aa9..53aaae0 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -943,12 +943,13 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
-        if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+    public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
+            int value) {
+        if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()) {
-                return service.setBufferMillis(codec, value);
+                return service.setBufferLengthMillis(codec, value);
             }
             if (service == null) Log.w(TAG, "Proxy not attached to service");
             return false;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b7203e3..cc0b22a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3565,12 +3565,12 @@
         }
 
         @Override
-        public void onDeviceDisconnected(BluetoothDevice device) {
+        public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
             for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
                     mBluetoothConnectionCallbackExecutorMap.entrySet()) {
                 BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
                 Executor executor = callbackExecutorEntry.getValue();
-                executor.execute(() -> callback.onDeviceDisconnected(device));
+                executor.execute(() -> callback.onDeviceDisconnected(device, hciReason));
             }
         }
     };
@@ -3665,7 +3665,7 @@
      *
      * @hide
      */
-    public abstract class BluetoothConnectionCallback {
+    public abstract static class BluetoothConnectionCallback {
         /**
          * Callback triggered when a bluetooth device (classic or BLE) is connected
          * @param device is the connected bluetooth device
@@ -3675,8 +3675,155 @@
         /**
          * Callback triggered when a bluetooth device (classic or BLE) is disconnected
          * @param device is the disconnected bluetooth device
+         * @param reason is the disconnect reason
          */
-        public void onDeviceDisconnected(BluetoothDevice device) {}
+        public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {}
+
+        /**
+         * @hide
+         */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = { "REASON_" }, value = {
+                REASON_UNKNOWN,
+                REASON_LOCAL_REQUEST,
+                REASON_REMOTE_REQUEST,
+                REASON_LOCAL_ERROR,
+                REASON_REMOTE_ERROR,
+                REASON_TIMEOUT,
+                REASON_SECURITY,
+                REASON_SYSTEM_POLICY,
+                REASON_RESOURCE_LIMIT_REACHED,
+                REASON_CONNECTION_EXISTS,
+                REASON_BAD_PARAMETERS})
+        public @interface DisconnectReason {}
+
+        /**
+         * Indicates that the ACL disconnected due to an unknown reason.
+         */
+        public static final int REASON_UNKNOWN = 0;
+
+        /**
+         * Indicates that the ACL disconnected due to an explicit request from the local device.
+         * <p>
+         * Example cause: This is a normal disconnect reason, e.g., user/app initiates
+         * disconnection.
+         */
+        public static final int REASON_LOCAL_REQUEST = 1;
+
+        /**
+         * Indicates that the ACL disconnected due to an explicit request from the remote device.
+         * <p>
+         * Example cause: This is a normal disconnect reason, e.g., user/app initiates
+         * disconnection.
+         * <p>
+         * Example solution: The app can also prompt the user to check their remote device.
+         */
+        public static final int REASON_REMOTE_REQUEST = 2;
+
+        /**
+         * Generic disconnect reason indicating the ACL disconnected due to an error on the local
+         * device.
+         * <p>
+         * Example solution: Prompt the user to check their local device (e.g., phone, car
+         * headunit).
+         */
+        public static final int REASON_LOCAL_ERROR = 3;
+
+        /**
+         * Generic disconnect reason indicating the ACL disconnected due to an error on the remote
+         * device.
+         * <p>
+         * Example solution: Prompt the user to check their remote device (e.g., headset, car
+         * headunit, watch).
+         */
+        public static final int REASON_REMOTE_ERROR = 4;
+
+        /**
+         * Indicates that the ACL disconnected due to a timeout.
+         * <p>
+         * Example cause: remote device might be out of range.
+         * <p>
+         * Example solution: Prompt user to verify their remote device is on or in
+         * connection/pairing mode.
+         */
+        public static final int REASON_TIMEOUT = 5;
+
+        /**
+         * Indicates that the ACL disconnected due to link key issues.
+         * <p>
+         * Example cause: Devices are either unpaired or remote device is refusing our pairing
+         * request.
+         * <p>
+         * Example solution: Prompt user to unpair and pair again.
+         */
+        public static final int REASON_SECURITY = 6;
+
+        /**
+         * Indicates that the ACL disconnected due to the local device's system policy.
+         * <p>
+         * Example cause: privacy policy, power management policy, permissions, etc.
+         * <p>
+         * Example solution: Prompt the user to check settings, or check with their system
+         * administrator (e.g. some corp-managed devices do not allow OPP connection).
+         */
+        public static final int REASON_SYSTEM_POLICY = 7;
+
+        /**
+         * Indicates that the ACL disconnected due to resource constraints, either on the local
+         * device or the remote device.
+         * <p>
+         * Example cause: controller is busy, memory limit reached, maximum number of connections
+         * reached.
+         * <p>
+         * Example solution: The app should wait and try again. If still failing, prompt the user
+         * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device.
+         */
+        public static final int REASON_RESOURCE_LIMIT_REACHED = 8;
+
+        /**
+         * Indicates that the ACL disconnected because another ACL connection already exists.
+         */
+        public static final int REASON_CONNECTION_EXISTS = 9;
+
+        /**
+         * Indicates that the ACL disconnected due to incorrect parameters passed in from the app.
+         * <p>
+         * Example solution: Change parameters and try again. If error persists, the app can report
+         * telemetry and/or log the error in a bugreport.
+         */
+        public static final int REASON_BAD_PARAMETERS = 10;
+
+        /**
+         * Returns human-readable strings corresponding to {@link DisconnectReason}.
+         */
+        public static String disconnectReasonText(@DisconnectReason int reason) {
+            switch (reason) {
+                case REASON_UNKNOWN:
+                    return "Reason unknown";
+                case REASON_LOCAL_REQUEST:
+                    return "Local request";
+                case REASON_REMOTE_REQUEST:
+                    return "Remote request";
+                case REASON_LOCAL_ERROR:
+                    return "Local error";
+                case REASON_REMOTE_ERROR:
+                    return "Remote error";
+                case REASON_TIMEOUT:
+                    return "Timeout";
+                case REASON_SECURITY:
+                    return "Security";
+                case REASON_SYSTEM_POLICY:
+                    return "System policy";
+                case REASON_RESOURCE_LIMIT_REACHED:
+                    return "Resource constrained";
+                case REASON_CONNECTION_EXISTS:
+                    return "Connection already exists";
+                case REASON_BAD_PARAMETERS:
+                    return "Bad parameters";
+                default:
+                    return "Unrecognized disconnect reason: " + reason;
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index ff6cffb..0312a21 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -18,7 +18,9 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -30,6 +32,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -37,44 +40,60 @@
  *
  * @hide
  */
+@SystemApi
 public final class BluetoothMapClient implements BluetoothProfile {
 
     private static final String TAG = "BluetoothMapClient";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
 
+    /** @hide */
     public static final String ACTION_CONNECTION_STATE_CHANGED =
             "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
+    /** @hide */
     public static final String ACTION_MESSAGE_RECEIVED =
             "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED";
     /* Actions to be used for pending intents */
+    /** @hide */
     public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY =
             "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY";
+    /** @hide */
     public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
             "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
 
     /**
      * Action to notify read status changed
+     *
+     * @hide
      */
     public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
             "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
 
     /**
      * Action to notify deleted status changed
+     *
+     * @hide
      */
     public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
             "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
 
-    /* Extras used in ACTION_MESSAGE_RECEIVED intent.
-     * NOTE: HANDLE is only valid for a single session with the device. */
+    /**
+     * Extras used in ACTION_MESSAGE_RECEIVED intent.
+     * NOTE: HANDLE is only valid for a single session with the device.
+     */
+    /** @hide */
     public static final String EXTRA_MESSAGE_HANDLE =
             "android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE";
+    /** @hide */
     public static final String EXTRA_MESSAGE_TIMESTAMP =
             "android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP";
+    /** @hide */
     public static final String EXTRA_MESSAGE_READ_STATUS =
             "android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS";
+    /** @hide */
     public static final String EXTRA_SENDER_CONTACT_URI =
             "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI";
+    /** @hide */
     public static final String EXTRA_SENDER_CONTACT_NAME =
             "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
 
@@ -84,6 +103,8 @@
      * Possible values are:
      * true: deleted
      * false: undeleted
+     *
+     * @hide
      */
     public static final String EXTRA_MESSAGE_DELETED_STATUS =
             "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS";
@@ -93,24 +114,42 @@
      * Possible values are:
      * 0: failure
      * 1: success
+     *
+     * @hide
      */
     public static final String EXTRA_RESULT_CODE =
             "android.bluetooth.device.extra.RESULT_CODE";
 
-    /** There was an error trying to obtain the state */
+    /**
+     * There was an error trying to obtain the state
+     * @hide
+     */
     public static final int STATE_ERROR = -1;
 
+    /** @hide */
     public static final int RESULT_FAILURE = 0;
+    /** @hide */
     public static final int RESULT_SUCCESS = 1;
-    /** Connection canceled before completion. */
+    /**
+     * Connection canceled before completion.
+     * @hide
+     */
     public static final int RESULT_CANCELED = 2;
-
+    /** @hide */
     private static final int UPLOADING_FEATURE_BITMASK = 0x08;
 
-    /** Parameters in setMessageStatus */
+    /*
+     * UNREAD, READ, UNDELETED, DELETED are passed as parameters
+     * to setMessageStatus to indicate the messages new state.
+     */
+
+    /** @hide */
     public static final int UNREAD = 0;
+    /** @hide */
     public static final int READ = 1;
+    /** @hide */
     public static final int UNDELETED = 2;
+    /** @hide */
     public static final int DELETED = 3;
 
     private BluetoothAdapter mAdapter;
@@ -132,19 +171,12 @@
         mProfileConnector.connect(context, listener);
     }
 
-    protected void finalize() throws Throwable {
-        try {
-            close();
-        } finally {
-            super.finalize();
-        }
-    }
-
     /**
      * Close the connection to the backing service.
      * Other public functions of BluetoothMap will return default error
      * results once close() has been called. Multiple invocations of close()
      * are ok.
+     * @hide
      */
     public void close() {
         mProfileConnector.disconnect();
@@ -158,6 +190,7 @@
      * Returns true if the specified Bluetooth device is connected.
      * Returns false if not connected, or if this proxy object is not
      * currently connected to the Map service.
+     * @hide
      */
     public boolean isConnected(BluetoothDevice device) {
         if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
@@ -225,6 +258,7 @@
      * Get the list of connected devices. Currently at most one.
      *
      * @return list of connected devices
+     * @hide
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
@@ -246,6 +280,7 @@
      * Get the list of devices matching specified states. Currently at most one.
      *
      * @return list of matching devices
+     * @hide
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -267,6 +302,7 @@
      * Get connection state of device
      *
      * @return device connection state
+     * @hide
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
@@ -383,11 +419,44 @@
      * Send an SMS message to either the contacts primary number or the telephone number specified.
      *
      * @param device Bluetooth device
+     * @param contacts Uri Collection of the contacts
+     * @param message Message to be sent
+     * @param sentIntent intent issued when message is sent
+     * @param deliveredIntent intent issued when message is delivered
+     * @return true if the message is enqueued, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.SEND_SMS)
+    public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts,
+            @NonNull String message, @Nullable PendingIntent sentIntent,
+            @Nullable PendingIntent deliveredIntent) {
+        if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
+        final IBluetoothMapClient service = getService();
+        if (service != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return service.sendMessage(device, contacts.toArray(new Uri[contacts.size()]),
+                        message, sentIntent, deliveredIntent);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        return false;
+    }
+
+     /**
+     * Send a message.
+     *
+     * Send an SMS message to either the contacts primary number or the telephone number specified.
+     *
+     * @param device Bluetooth device
      * @param contacts Uri[] of the contacts
      * @param message Message to be sent
      * @param sentIntent intent issued when message is sent
      * @param deliveredIntent intent issued when message is delivered
      * @return true if the message is enqueued, false on error
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
@@ -410,6 +479,7 @@
      *
      * @param device Bluetooth device
      * @return true if the message is enqueued, false on error
+     * @hide
      */
     public boolean getUnreadMessages(BluetoothDevice device) {
         if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
@@ -431,6 +501,7 @@
      * @param device The Bluetooth device to get this value for.
      * @return Returns true if the Uploading bit value in SDP record's
      *         MapSupportedFeatures field is set. False is returned otherwise.
+     * @hide
      */
     public boolean isUploadingSupported(BluetoothDevice device) {
         final IBluetoothMapClient service = getService();
@@ -457,7 +528,7 @@
      *            "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for
      *            "deleted", otherwise return error
      * @return <code>true</code> if request has been sent, <code>false</code> on error
-     *
+     * @hide
      */
     @RequiresPermission(Manifest.permission.READ_SMS)
     public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index c31b04e..201d6c4 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -186,6 +186,7 @@
      *
      * @hide
      */
+    @SystemApi
     int MAP_CLIENT = 18;
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c0736a6..d82cf19 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -167,6 +167,11 @@
     /** @hide */
     @NonNull
     @SystemApi
+    public static final ParcelUuid VOLUME_CONTROL =
+            ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
 
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
index 7e5ec1e..97d9723 100644
--- a/core/java/android/bluetooth/BufferConstraints.java
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -90,7 +90,7 @@
      * @hide
      */
     @SystemApi
-    public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+    public @Nullable BufferConstraint forCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
         return mBufferConstraints.get(codec);
     }
 }
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index 573b932..fa7ac2b 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -44,7 +44,7 @@
     @Nullable
     private final List<ParcelUuid> mServiceUuids;
 
-    @Nullable
+    @NonNull
     private final List<ParcelUuid> mServiceSolicitationUuids;
 
     private final SparseArray<byte[]> mManufacturerSpecificData;
@@ -77,7 +77,7 @@
     /**
      * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect.
      */
-    @Nullable
+    @NonNull
     public List<ParcelUuid> getServiceSolicitationUuids() {
         return mServiceSolicitationUuids;
     }
@@ -221,7 +221,7 @@
     public static final class Builder {
         @Nullable
         private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
-        @Nullable
+        @NonNull
         private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
         private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
         private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
diff --git a/core/java/android/content/AutofillOptions.java b/core/java/android/content/AutofillOptions.java
index 80a7b16..0581ed5 100644
--- a/core/java/android/content/AutofillOptions.java
+++ b/core/java/android/content/AutofillOptions.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.os.Parcel;
@@ -62,6 +63,7 @@
      * List of allowlisted activities.
      */
     @Nullable
+    @SuppressLint("NullableCollection")
     public ArraySet<ComponentName> whitelistedActivitiesForAugmentedAutofill;
 
     /**
@@ -73,6 +75,7 @@
      * The disabled Activities of the package. key is component name string, value is when they
      * will be enabled.
      */
+    @SuppressLint("NullableCollection")
     @Nullable
     public ArrayMap<String, Long> disabledActivities;
 
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index ef49e02..c296bb5 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.os.Parcel;
@@ -73,6 +74,7 @@
      * for all acitivites in the package).
      */
     @Nullable
+    @SuppressLint("NullableCollection")
     public final ArraySet<ComponentName> whitelistedComponents;
 
     /**
@@ -96,6 +98,7 @@
      */
     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
             int textChangeFlushingFrequencyMs, int logHistorySize,
+            @SuppressLint("NullableCollection")
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
         this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
                 textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a6089c3..32aa037 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -64,7 +64,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.system.Int32Ref;
+import android.system.Int64Ref;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -4040,7 +4040,7 @@
         // Convert to Point, since that's what the API is defined as
         final Bundle opts = new Bundle();
         opts.putParcelable(EXTRA_SIZE, Point.convert(size));
-        final Int32Ref orientation = new Int32Ref(0);
+        final Int64Ref orientation = new Int64Ref(0);
 
         Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
             final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 005c7ce..08d8da3 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1990,6 +1990,13 @@
             this.forceQueryableOverride = true;
         }
 
+        /**
+         * Sets the install scenario for this session, which describes the expected user journey.
+         */
+        public void setInstallScenario(@InstallScenario int installScenario) {
+            this.installScenario = installScenario;
+        }
+
         /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 31beb6e..443ae35 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -59,6 +59,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.Bundle;
@@ -71,6 +72,12 @@
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.permission.PermissionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.gba.GbaService;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.SipDelegateManager;
 import android.util.AndroidException;
 import android.util.Log;
 
@@ -1052,15 +1059,11 @@
 
     /**
      * A value to indicate the lack of CUJ information, disabling all installation scenario logic.
-     *
-     * @hide
      */
     public static final int INSTALL_SCENARIO_DEFAULT = 0;
 
     /**
      * Installation scenario providing the fastest “install button to launch" experience possible.
-     *
-     * @hide
      */
     public static final int INSTALL_SCENARIO_FAST = 1;
 
@@ -1077,8 +1080,6 @@
      * less optimized applications.  The device state (e.g. memory usage or battery status) should
      * not be considered when making this decision as those factors are taken into account by the
      * Package Manager when acting on the installation scenario.
-     *
-     * @hide
      */
     public static final int INSTALL_SCENARIO_BULK = 2;
 
@@ -1089,8 +1090,6 @@
      * operation that are marked BULK_SECONDARY, the faster the entire bulk operation will be.
      *
      * See the comments for INSTALL_SCENARIO_BULK for more information.
-     *
-     * @hide
      */
     public static final int INSTALL_SCENARIO_BULK_SECONDARY = 3;
 
@@ -2602,6 +2601,37 @@
     public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+     * supports a single IMS registration as defined by carrier networks in the IMS service
+     * implementation using the {@link ImsService} API, {@link GbaService} API, and IRadio 1.6 HAL.
+     * <p>
+     * When set, the device must fully support the following APIs for an application to implement
+     * IMS single registration:
+     * <ul>
+     * <li> Updating RCS provisioning status using the {@link ProvisioningManager} API to supply an
+     * RCC.14 defined XML and notify IMS applications of Auto Configuration Server (ACS) or
+     * proprietary server provisioning updates.</li>
+     * <li>Opening a delegate in the device IMS service to forward SIP traffic to the carrier's
+     * network using the {@link SipDelegateManager} API</li>
+     * <li>Listening to EPS dedicated bearer establishment via the
+     * {@link ConnectivityManager#registerQosCallback}
+     * API to indicate to the application when to start/stop media traffic.</li>
+     * <li>Implementing Generic Bootstrapping Architecture (GBA) and providing the associated
+     * authentication keys to applications
+     * requesting this information via the {@link TelephonyManager#bootstrapAuthenticationRequest}
+     * API</li>
+     * <li>Implementing RCS User Capability Exchange using the {@link RcsUceAdapter} API</li>
+     * </ul>
+     * <p>
+     * This feature should only be defined if {@link #FEATURE_TELEPHONY_IMS} is also defined.
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION =
+            "android.hardware.telephony.ims.singlereg";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device is capable of communicating with
      * other devices via ultra wideband.
@@ -3224,6 +3254,33 @@
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
 
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+     * a Keystore implementation that can only enforce limited use key in hardware with max usage
+     * count equals to 1.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY =
+            "android.hardware.keystore.single_use_key";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+     * a Keystore implementation that can enforce limited use key in hardware with any max usage
+     * count (including count equals to 1).
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY =
+            "android.hardware.keystore.limited_use_key";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+     * a Keystore implementation that can create application-specific attestation keys.
+     * See {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias}.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY =
+            "android.hardware.keystore.app_attest_key";
+
     /** @hide */
     public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
 
@@ -4945,7 +5002,7 @@
      *
      * @hide
      */
-    @SuppressWarnings("HiddenAbstractMethod")
+    @SuppressWarnings({"HiddenAbstractMethod", "NullableCollection"})
     @TestApi
     public abstract @Nullable String[] getNamesForUids(int[] uids);
 
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 982fce9..8b65d24 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,17 +22,26 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.jar.StrictJarFile;
+import android.util.JsonReader;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.zip.ZipEntry;
 
 /**
  * Helper class used to compute and validate the location of dex metadata files.
@@ -40,6 +49,12 @@
  * @hide
  */
 public class DexMetadataHelper {
+    public static final String TAG = "DexMetadataHelper";
+    /** $> adb shell 'setprop log.tag.DexMetadataHelper VERBOSE' */
+    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    /** $> adb shell 'setprop pm.dexopt.dm.require_manifest true' */
+    private static String PROPERTY_DM_JSON_MANIFEST_REQUIRED = "pm.dexopt.dm.require_manifest";
+
     private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
 
     private DexMetadataHelper() {}
@@ -147,14 +162,31 @@
 
     /**
      * Validate that the given file is a dex metadata archive.
-     * This is just a validation that the file is a zip archive.
+     * This is just a validation that the file is a zip archive that contains a manifest.json
+     * with the package name and version code.
      *
      * @throws PackageParserException if the file is not a .dm file.
      */
-    public static void validateDexMetadataFile(String dmaPath) throws PackageParserException {
+    public static void validateDexMetadataFile(String dmaPath, String packageName, long versionCode)
+            throws PackageParserException {
+        validateDexMetadataFile(dmaPath, packageName, versionCode,
+               SystemProperties.getBoolean(PROPERTY_DM_JSON_MANIFEST_REQUIRED, false));
+    }
+
+    @VisibleForTesting
+    public static void validateDexMetadataFile(String dmaPath, String packageName, long versionCode,
+            boolean requireManifest) throws PackageParserException {
         StrictJarFile jarFile = null;
+
+        if (DEBUG) {
+            Log.v(TAG, "validateDexMetadataFile: " + dmaPath + ", " + packageName +
+                    ", " + versionCode);
+        }
+
         try {
             jarFile = new StrictJarFile(dmaPath, false, false);
+            validateDexMetadataManifest(dmaPath, jarFile, packageName, versionCode,
+                    requireManifest);
         } catch (IOException e) {
             throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
                     "Error opening " + dmaPath, e);
@@ -168,6 +200,72 @@
         }
     }
 
+    /** Ensure that packageName and versionCode match the manifest.json in the .dm file */
+    private static void validateDexMetadataManifest(String dmaPath, StrictJarFile jarFile,
+            String packageName, long versionCode, boolean requireManifest)
+            throws IOException, PackageParserException {
+        if (!requireManifest) {
+            if (DEBUG) {
+                Log.v(TAG, "validateDexMetadataManifest: " + dmaPath
+                        + " manifest.json check skipped");
+            }
+            return;
+        }
+
+        ZipEntry zipEntry = jarFile.findEntry("manifest.json");
+        if (zipEntry == null) {
+              throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                      "Missing manifest.json in " + dmaPath);
+        }
+        InputStream inputStream = jarFile.getInputStream(zipEntry);
+
+        JsonReader reader;
+        try {
+          reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                    "Error opening manifest.json in " + dmaPath, e);
+        }
+        String jsonPackageName = null;
+        long jsonVersionCode = -1;
+
+        reader.beginObject();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            if (name.equals("packageName")) {
+                jsonPackageName = reader.nextString();
+            } else if (name.equals("versionCode")) {
+                jsonVersionCode = reader.nextLong();
+            } else {
+                reader.skipValue();
+            }
+        }
+        reader.endObject();
+
+        if (jsonPackageName == null || jsonVersionCode == -1) {
+            throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                    "manifest.json in " + dmaPath
+                    + " is missing 'packageName' and/or 'versionCode'");
+        }
+
+        if (!jsonPackageName.equals(packageName)) {
+            throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                    "manifest.json in " + dmaPath + " has invalid packageName: " + jsonPackageName
+                    + ", expected: " + packageName);
+        }
+
+        if (versionCode != jsonVersionCode) {
+            throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                    "manifest.json in " + dmaPath + " has invalid versionCode: " + jsonVersionCode
+                    + ", expected: " + versionCode);
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, "validateDexMetadataManifest: " + dmaPath + ", " + packageName +
+                    ", " + versionCode + ": successful");
+        }
+    }
+
     /**
      * Validates that all dex metadata paths in the given list have a matching apk.
      * (for any foo.dm there should be either a 'foo' of a 'foo.apk' file).
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
index cde7b2a..d302b0a 100644
--- a/core/java/android/content/pm/permission/OWNERS
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -3,7 +3,6 @@
 toddke@android.com
 toddke@google.com
 patb@google.com
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
 zhanghai@google.com
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 3295042..2b4e4a1 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -3,3 +3,6 @@
 
 # Sensor Privacy
 per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
+
+# Sensors framework
+per-file *Sensor*,*Trigger* = file:platform/frameworks/native:/services/sensorservice/OWNERS
diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS
index 25e02e1..c390b33 100644
--- a/core/java/android/hardware/input/OWNERS
+++ b/core/java/android/hardware/input/OWNERS
@@ -1,6 +1,3 @@
 # Bug component: 136048
 
 include /services/core/java/com/android/server/input/OWNERS
-
-michaelwr@google.com
-svv@google.com
diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS
index 383321b..bd40409 100644
--- a/core/java/android/hardware/location/OWNERS
+++ b/core/java/android/hardware/location/OWNERS
@@ -4,3 +4,6 @@
 wyattriley@google.com
 etn@google.com
 weiwa@google.com
+
+# ContextHub team
+per-file *ContextHub*,*NanoApp* = file:platform/system/chre:/OWNERS
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8f2b39d..8f5c2a0 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,4 +1,3 @@
 # Bug component: 175220
 
-moltmann@google.com
 badhri@google.com
diff --git a/core/java/android/inputmethodservice/OWNERS b/core/java/android/inputmethodservice/OWNERS
index e6a04da..d7db7c7 100644
--- a/core/java/android/inputmethodservice/OWNERS
+++ b/core/java/android/inputmethodservice/OWNERS
@@ -2,3 +2,5 @@
 set noparent
 
 include /services/core/java/com/android/server/inputmethod/OWNERS
+
+per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl
rename to core/java/android/net/ConnectivityMetricsEvent.aidl
diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java
index 0ac8f7e7..b06d515 100644
--- a/core/java/android/net/DataUsageRequest.java
+++ b/core/java/android/net/DataUsageRequest.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.Nullable;
 import android.net.NetworkTemplate;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -95,7 +96,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof DataUsageRequest == false) return false;
         DataUsageRequest that = (DataUsageRequest) obj;
         return that.requestId == this.requestId
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index ef0a436..82ba156 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -160,7 +160,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
 
         if (!(obj instanceof DhcpResults)) return false;
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index d6774d4..933256a 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -58,6 +58,9 @@
             in LinkAddress localAddr,
             in String callingPackage);
 
+    void setNetworkForTunnelInterface(
+            int tunnelResourceId, in Network underlyingNetwork, in String callingPackage);
+
     void deleteTunnelInterface(int resourceId, in String callingPackage);
 
     IpSecTransformResponse createTransform(
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index fe9141c..dfb1e99 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -23,6 +23,6 @@
     void onMeteredIfacesChanged(in String[] meteredIfaces);
     void onRestrictBackgroundChanged(boolean restrictBackground);
     void onUidPoliciesChanged(int uid, int uidPolicies);
-    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue);
+    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes);
     void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans);
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 29a3fdf..b016ed6 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -76,10 +76,11 @@
     SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
     void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
     String getSubscriptionPlansOwner(int subId);
-    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage);
+    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long timeoutMillis, String callingPackage);
 
     void factoryReset(String subscriber);
 
     boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
     boolean isUidRestrictedOnMeteredNetworks(int uid);
+    boolean checkUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered, boolean isBackgroundRestricted);
 }
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
similarity index 70%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
index 46bc4ab..7979afc 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
@@ -1,11 +1,12 @@
-/*
- * Copyright 2020 The Android Open Source Project
+/**
+ *
+ * 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
+ *     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,
@@ -14,7 +15,9 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.net;
 
-parcelable ApnThrottleStatus;
+/** @hide */
+oneway interface IOnSetOemNetworkPreferenceListener {
+    void onComplete();
+}
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
new file mode 100644
index 0000000..271efe4
--- /dev/null
+++ b/core/java/android/net/IVpnManager.aidl
@@ -0,0 +1,62 @@
+/**
+ * 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.net;
+
+import android.net.Network;
+
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+
+/**
+ * Interface that manages VPNs.
+ */
+/** {@hide} */
+interface IVpnManager {
+    /** VpnService APIs */
+    boolean prepareVpn(String oldPackage, String newPackage, int userId);
+    void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
+    ParcelFileDescriptor establishVpn(in VpnConfig config);
+    boolean addVpnAddress(String address, int prefixLength);
+    boolean removeVpnAddress(String address, int prefixLength);
+    boolean setUnderlyingNetworksForVpn(in Network[] networks);
+
+    /** VpnManager APIs */
+    boolean provisionVpnProfile(in VpnProfile profile, String packageName);
+    void deleteVpnProfile(String packageName);
+    void startVpnProfile(String packageName);
+    void stopVpnProfile(String packageName);
+
+    /** Always-on VPN APIs */
+    boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
+    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
+            in List<String> lockdownAllowlist);
+    String getAlwaysOnVpnPackage(int userId);
+    boolean isVpnLockdownEnabled(int userId);
+    List<String> getVpnLockdownAllowlist(int userId);
+    boolean isCallerCurrentAlwaysOnVpnApp();
+    boolean isCallerCurrentAlwaysOnVpnLockdownApp();
+
+    /** Legacy VPN APIs */
+    void startLegacyVpn(in VpnProfile profile);
+    LegacyVpnInfo getLegacyVpnInfo(int userId);
+    boolean updateLockdownVpn();
+
+    /** General system APIs */
+    VpnConfig getVpnConfig(int userId);
+    void factoryReset();
+}
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 63fc5f2..183f500 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -360,7 +360,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof Ikev2VpnProfile)) {
             return false;
         }
diff --git a/packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl b/core/java/android/net/InterfaceConfiguration.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl
rename to core/java/android/net/InterfaceConfiguration.aidl
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 70bca30..98acd98 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -782,6 +782,42 @@
             }
         }
 
+        /**
+         * Update the underlying network for this IpSecTunnelInterface.
+         *
+         * <p>This new underlying network will be used for all transforms applied AFTER this call is
+         * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
+         * this tunnel interface, traffic will still use the old SA, and be routed on the old
+         * underlying network.
+         *
+         * <p>To migrate IPsec tunnel mode traffic, a caller should:
+         *
+         * <ol>
+         *   <li>Update the IpSecTunnelInterface’s underlying network.
+         *   <li>Apply {@link IpSecTransform}(s) with matching addresses to this
+         *       IpSecTunnelInterface.
+         * </ol>
+         *
+         * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
+         *     This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
+         *     this method will throw an {@link IllegalArgumentException}.
+         */
+        // TODO: b/169171001 Update the documentation when transform migration is supported.
+        // The purpose of making updating network and applying transforms separate is to leave open
+        // the possibility to support lossless migration procedures. To do that, Android platform
+        // will need to support multiple inbound tunnel mode transforms, just like it can support
+        // multiple transport mode transforms.
+        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+        public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
+            try {
+                mService.setNetworkForTunnelInterface(
+                        mResourceId, underlyingNetwork, mOpPackageName);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
                 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
                 @NonNull Network underlyingNetwork)
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index aa7811a..b48c1fd 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -19,6 +19,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -150,7 +151,7 @@
     /**
      * Standard equals.
      */
-    public boolean equals(Object other) {
+    public boolean equals(@Nullable Object other) {
         if (this == other) return true;
         if (!(other instanceof IpSecTransform)) return false;
         final IpSecTransform rhs = (IpSecTransform) other;
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index e01e5ae..f7c1c4b 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -19,7 +19,6 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.system.ErrnoException;
-import android.system.Int32Ref;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructLinger;
@@ -65,14 +64,11 @@
         public int available() throws IOException {
             FileDescriptor myFd = fd;
             if (myFd == null) throw new IOException("socket closed");
-
-            Int32Ref avail = new Int32Ref(0);
             try {
-                Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
+                return Os.ioctlInt(myFd, OsConstants.FIONREAD);
             } catch (ErrnoException e) {
                 throw e.rethrowAsIOException();
             }
-            return avail.value;
         }
 
         /** {@inheritDoc} */
@@ -134,7 +130,7 @@
         public void write (byte[] b) throws IOException {
             write(b, 0, b.length);
         }
-        
+
         /** {@inheritDoc} */
         @Override
         public void write (byte[] b, int off, int len) throws IOException {
@@ -255,7 +251,7 @@
     /** note timeout presently ignored */
     protected void connect(LocalSocketAddress address, int timeout)
                         throws IOException
-    {        
+    {
         if (fd == null) {
             throw new IOException("socket not created");
         }
@@ -339,7 +335,7 @@
      * @throws IOException if socket has been closed or cannot be created.
      */
     protected OutputStream getOutputStream() throws IOException
-    { 
+    {
         if (fd == null) {
             throw new IOException("socket not created");
         }
diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java
index 011a04c..9a11be0 100644
--- a/core/java/android/net/MatchAllNetworkSpecifier.java
+++ b/core/java/android/net/MatchAllNetworkSpecifier.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -44,7 +45,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         return o instanceof MatchAllNetworkSpecifier;
     }
 
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 521ed9b..32b19a4 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -18,6 +18,7 @@
 
 import static android.net.ConnectivityManager.TYPE_WIFI;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -31,7 +32,7 @@
 
 /**
  * Network definition that includes strong identity. Analogous to combining
- * {@link NetworkInfo} and an IMSI.
+ * {@link NetworkCapabilities} and an IMSI.
  *
  * @hide
  */
@@ -67,7 +68,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkIdentity) {
             final NetworkIdentity ident = (NetworkIdentity) obj;
             return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
@@ -159,7 +160,7 @@
      */
     public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
             boolean defaultNetwork, @NetworkType int subType) {
-        final int type = state.networkInfo.getType();
+        final int legacyType = state.legacyNetworkType;
 
         String subscriberId = null;
         String networkId = null;
@@ -170,7 +171,7 @@
 
         subscriberId = state.subscriberId;
 
-        if (type == TYPE_WIFI) {
+        if (legacyType == TYPE_WIFI) {
             if (state.networkCapabilities.getSsid() != null) {
                 networkId = state.networkCapabilities.getSsid();
                 if (networkId == null) {
@@ -183,7 +184,7 @@
             }
         }
 
-        return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
+        return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
                 defaultNetwork);
     }
 
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 4f05c9b..8a0211c 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -205,7 +206,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkPolicy) {
             final NetworkPolicy other = (NetworkPolicy) obj;
             return warningBytes == other.warningBytes
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 82b035b..b1bca6e 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -34,6 +35,7 @@
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
+import android.telephony.Annotation;
 import android.telephony.SubscriptionPlan;
 import android.util.DebugUtils;
 import android.util.Pair;
@@ -54,6 +56,7 @@
  *
  * @hide
  */
+@TestApi
 @SystemService(Context.NETWORK_POLICY_SERVICE)
 public class NetworkPolicyManager {
 
@@ -124,6 +127,7 @@
     public static final int RULE_REJECT_ALL = 1 << 6;
     /**
      * Reject traffic on all networks for restricted networking mode.
+     * @hide
      */
     public static final int RULE_REJECT_RESTRICTED_MODE = 1 << 10;
 
@@ -350,6 +354,7 @@
     }
 
     /** @hide */
+    @TestApi
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void setRestrictBackground(boolean restrictBackground) {
         try {
@@ -360,6 +365,7 @@
     }
 
     /** @hide */
+    @TestApi
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean getRestrictBackground() {
         try {
@@ -377,6 +383,8 @@
      * @param overrideMask the bitmask that specifies which of the overrides is being
      *            set or cleared.
      * @param overrideValue the override values to set or clear.
+     * @param networkTypes the network types this override applies to.
+     *            {@see TelephonyManager#getAllNetworkTypes()}
      * @param timeoutMillis the timeout after which the requested override will
      *            be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
@@ -385,11 +393,12 @@
      * @hide
      */
     public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
-            @SubscriptionOverrideMask int overrideValue, long timeoutMillis,
-                    @NonNull String callingPackage) {
+            @SubscriptionOverrideMask int overrideValue,
+            @NonNull @Annotation.NetworkType int[] networkTypes, long timeoutMillis,
+            @NonNull String callingPackage) {
         try {
-            mService.setSubscriptionOverride(subId, overrideMask, overrideValue, timeoutMillis,
-                    callingPackage);
+            mService.setSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes,
+                    timeoutMillis, callingPackage);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -460,6 +469,31 @@
     }
 
     /**
+     * Figure out if networking is blocked for a given set of conditions.
+     *
+     * This is used by ConnectivityService via passing stale copies of conditions, so it must not
+     * take any locks.
+     *
+     * @param uid The target uid.
+     * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
+     * @param isNetworkMetered True if the network is metered.
+     * @param isBackgroundRestricted True if data saver is enabled.
+     *
+     * @return true if networking is blocked for the UID under the specified conditions.
+     *
+     * @hide
+     */
+    public boolean checkUidNetworkingBlocked(int uid, int uidRules,
+            boolean isNetworkMetered, boolean isBackgroundRestricted) {
+        try {
+            return mService.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
+                    isBackgroundRestricted);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Check that the given uid is restricted from doing networking on metered networks.
      *
      * @param uid The target uid.
@@ -477,6 +511,8 @@
 
     /**
      * Get multipath preference for the given network.
+     *
+     * @hide
      */
     public int getMultipathPreference(Network network) {
         try {
@@ -595,7 +631,9 @@
     }
 
     /** @hide */
-    public static String resolveNetworkId(WifiConfiguration config) {
+    @TestApi
+    @NonNull
+    public static String resolveNetworkId(@NonNull WifiConfiguration config) {
         return WifiInfo.sanitizeSsid(config.isPasspoint()
                 ? config.providerFriendlyName : config.SSID);
     }
@@ -613,9 +651,10 @@
          * @param subId the subscriber this override applies to.
          * @param overrideMask a bitmask that specifies which of the overrides is set.
          * @param overrideValue a bitmask that specifies the override values.
+         * @param networkTypes the network types this override applies to.
          */
         public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
-                @SubscriptionOverrideMask int overrideValue) {}
+                @SubscriptionOverrideMask int overrideValue, int[] networkTypes) {}
 
         /**
          * Notify of subscription plans change about a given subscription.
@@ -639,8 +678,8 @@
 
         @Override
         public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
-                @SubscriptionOverrideMask int overrideValue) {
-            mCallback.onSubscriptionOverride(subId, overrideMask, overrideValue);
+                @SubscriptionOverrideMask int overrideValue, int[] networkTypes) {
+            mCallback.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
         }
 
         @Override
@@ -656,7 +695,7 @@
         @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { }
         @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { }
         @Override public void onSubscriptionOverride(int subId, int overrideMask,
-                int overrideValue) { }
+                int overrideValue, int[] networkTypes) { }
         @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { }
     }
 }
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
index 116e39e..caa6e45 100644
--- a/core/java/android/net/NetworkScorerAppData.java
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -110,7 +110,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         NetworkScorerAppData that = (NetworkScorerAppData) o;
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index 79f9e6e..dbb3127 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,9 +15,6 @@
  */
 package android.net;
 
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -26,8 +23,7 @@
 import android.os.IBinder;
 import android.os.ServiceManager;
 
-import java.util.ArrayList;
-import java.util.Arrays;
+import com.android.net.module.util.PermissionUtils;
 /**
  * Constants and utilities for client code communicating with the network stack service.
  * @hide
@@ -79,9 +75,14 @@
      * @param context {@link android.content.Context} for the process.
      *
      * @hide
+     *
+     * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermission} instead.
+     *
+     * TODO: remove this method and let the users call to PermissionUtils directly.
      */
+    @Deprecated
     public static void checkNetworkStackPermission(final @NonNull Context context) {
-        checkNetworkStackPermissionOr(context);
+        PermissionUtils.enforceNetworkStackPermission(context);
     }
 
     /**
@@ -92,31 +93,14 @@
      * @param otherPermissions The set of permissions that could be the candidate permissions , or
      *                         empty string if none of other permissions needed.
      * @hide
+     *
+     * @deprecated Use {@link PermissionUtils#enforceNetworkStackPermissionOr} instead.
+     *
+     * TODO: remove this method and let the users call to PermissionUtils directly.
      */
+    @Deprecated
     public static void checkNetworkStackPermissionOr(final @NonNull Context context,
             final @NonNull String... otherPermissions) {
-        ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
-        permissions.add(NETWORK_STACK);
-        permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
-        enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
+        PermissionUtils.enforceNetworkStackPermissionOr(context, otherPermissions);
     }
-
-    private static void enforceAnyPermissionOf(final @NonNull Context context,
-            final @NonNull String... permissions) {
-        if (!checkAnyPermissionOf(context, permissions)) {
-            throw new SecurityException("Requires one of the following permissions: "
-                + String.join(", ", permissions) + ".");
-        }
-    }
-
-    private static boolean checkAnyPermissionOf(final @NonNull Context context,
-            final @NonNull String... permissions) {
-        for (String permission : permissions) {
-            if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
-                return true;
-            }
-        }
-        return false;
-    }
-
 }
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index e1ef8b5..813fde1 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -40,7 +41,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Network network;
     public final String subscriberId;
-    public final String networkId;
+    public final int legacyNetworkType;
 
     private NetworkState() {
         networkInfo = null;
@@ -48,18 +49,34 @@
         networkCapabilities = null;
         network = null;
         subscriberId = null;
-        networkId = null;
+        legacyNetworkType = 0;
     }
 
+    public NetworkState(int legacyNetworkType, @NonNull LinkProperties linkProperties,
+            @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+            @Nullable String subscriberId) {
+        this(legacyNetworkType, new NetworkInfo(legacyNetworkType, 0, null, null), linkProperties,
+                networkCapabilities, network, subscriberId);
+    }
+
+    // Constructor that used internally in ConnectivityService mainline module.
     public NetworkState(@NonNull NetworkInfo networkInfo, @NonNull LinkProperties linkProperties,
             @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
-            String subscriberId, String networkId) {
+            @Nullable String subscriberId) {
+        this(networkInfo.getType(), networkInfo, linkProperties,
+                networkCapabilities, network, subscriberId);
+    }
+
+    public NetworkState(int legacyNetworkType, @NonNull NetworkInfo networkInfo,
+            @NonNull LinkProperties linkProperties,
+            @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+            @Nullable String subscriberId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
         this.networkCapabilities = networkCapabilities;
         this.network = network;
         this.subscriberId = subscriberId;
-        this.networkId = networkId;
+        this.legacyNetworkType = legacyNetworkType;
 
         // This object is an atomic view of a network, so the various components
         // should always agree on roaming state.
@@ -79,7 +96,7 @@
         networkCapabilities = in.readParcelable(null);
         network = in.readParcelable(null);
         subscriberId = in.readString();
-        networkId = in.readString();
+        legacyNetworkType = in.readInt();
     }
 
     @Override
@@ -94,7 +111,7 @@
         out.writeParcelable(networkCapabilities, flags);
         out.writeParcelable(network, flags);
         out.writeString(subscriberId);
-        out.writeString(networkId);
+        out.writeInt(legacyNetworkType);
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index cf40ce5..d42beae 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -412,7 +412,7 @@
 
         /** @hide */
         @Override
-        public boolean equals(Object o) {
+        public boolean equals(@Nullable Object o) {
             if (o instanceof Entry) {
                 final Entry e = (Entry) o;
                 return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 2322048..aa61e03 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -329,7 +329,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkTemplate) {
             final NetworkTemplate other = (NetworkTemplate) obj;
             return mMatchRule == other.mMatchRule
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
index 49047d3..8f6510e 100644
--- a/core/java/android/net/NetworkWatchlistManager.java
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
@@ -29,6 +31,7 @@
  * Class that manage network watchlist in system.
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 @SystemService(Context.NETWORK_WATCHLIST_SERVICE)
 public class NetworkWatchlistManager {
 
@@ -90,6 +93,7 @@
     /**
      * Get Network Watchlist config file hash.
      */
+    @Nullable
     public byte[] getWatchlistConfigHash() {
         try {
             return mNetworkWatchlistManager.getWatchlistConfigHash();
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index 6a8e3f9..b403455 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -18,22 +18,24 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
 import android.os.Parcelable;
-import android.util.SparseArray;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 
 /** @hide */
+@SystemApi
 public final class OemNetworkPreferences implements Parcelable {
     /**
-     * Use default behavior requesting networks. Equivalent to not setting any preference at all.
+     * Default in case this value is not set. Using it will result in an error.
      */
-    public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
+    public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0;
 
     /**
      * If an unmetered network is available, use it.
@@ -45,31 +47,31 @@
     /**
      * If an unmetered network is available, use it.
      * Otherwise, if a network with the OEM_PAID capability is available, use it.
-     * Otherwise, the app doesn't get a network.
+     * Otherwise, the app doesn't get a default network.
      */
     public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
 
     /**
-     * Prefer only NET_CAPABILITY_OEM_PAID networks.
+     * Use only NET_CAPABILITY_OEM_PAID networks.
      */
     public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3;
 
     /**
-     * Prefer only NET_CAPABILITY_OEM_PRIVATE networks.
+     * Use only NET_CAPABILITY_OEM_PRIVATE networks.
      */
     public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
 
     @NonNull
-    private final SparseArray<List<String>> mNetworkMappings;
+    private final Bundle mNetworkMappings;
 
     @NonNull
-    public SparseArray<List<String>> getNetworkPreferences() {
-        return mNetworkMappings.clone();
+    public Map<String, Integer> getNetworkPreferences() {
+        return convertToUnmodifiableMap(mNetworkMappings);
     }
 
-    private OemNetworkPreferences(@NonNull SparseArray<List<String>> networkMappings) {
+    private OemNetworkPreferences(@NonNull final Bundle networkMappings) {
         Objects.requireNonNull(networkMappings);
-        mNetworkMappings = networkMappings.clone();
+        mNetworkMappings = (Bundle) networkMappings.clone();
     }
 
     @Override
@@ -95,30 +97,47 @@
     /**
      * Builder used to create {@link OemNetworkPreferences} objects.  Specify the preferred Network
      * to package name mappings.
-     *
-     * @hide
      */
     public static final class Builder {
-        private final SparseArray<List<String>> mNetworkMappings;
+        private final Bundle mNetworkMappings;
 
         public Builder() {
-            mNetworkMappings = new SparseArray<>();
+            mNetworkMappings = new Bundle();
+        }
+
+        public Builder(@NonNull final OemNetworkPreferences preferences) {
+            Objects.requireNonNull(preferences);
+            mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone();
         }
 
         /**
-         * Add a network preference for a list of packages.
+         * Add a network preference for a given package. Previously stored values for the given
+         * package will be overwritten.
          *
-         * @param preference the desired network preference to use
-         * @param packages   full package names (e.g.: "com.google.apps.contacts") for apps to use
-         *                   the given preference
+         * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app
+         *                    to use the given preference
+         * @param preference  the desired network preference to use
          * @return The builder to facilitate chaining.
          */
         @NonNull
-        public Builder addNetworkPreference(@OemNetworkPreference final int preference,
-                @NonNull List<String> packages) {
-            Objects.requireNonNull(packages);
-            mNetworkMappings.put(preference,
-                    Collections.unmodifiableList(new ArrayList<>(packages)));
+        public Builder addNetworkPreference(@NonNull final String packageName,
+                @OemNetworkPreference final int preference) {
+            Objects.requireNonNull(packageName);
+            mNetworkMappings.putInt(packageName, preference);
+            return this;
+        }
+
+        /**
+         * Remove a network preference for a given package.
+         *
+         * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app to
+         *                    remove a preference for.
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public Builder clearNetworkPreference(@NonNull final String packageName) {
+            Objects.requireNonNull(packageName);
+            mNetworkMappings.remove(packageName);
             return this;
         }
 
@@ -131,9 +150,17 @@
         }
     }
 
+    private static Map<String, Integer> convertToUnmodifiableMap(@NonNull final Bundle bundle) {
+        final Map<String, Integer> networkPreferences = new HashMap<>();
+        for (final String key : bundle.keySet()) {
+            networkPreferences.put(key, bundle.getInt(key));
+        }
+        return Collections.unmodifiableMap(networkPreferences);
+    }
+
     /** @hide */
     @IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
-            OEM_NETWORK_PREFERENCE_DEFAULT,
+            OEM_NETWORK_PREFERENCE_UNINITIALIZED,
             OEM_NETWORK_PREFERENCE_OEM_PAID,
             OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
             OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
@@ -147,12 +174,14 @@
      *
      * @param value int value of OemNetworkPreference
      * @return string version of OemNetworkPreference
+     *
+     * @hide
      */
     @NonNull
     public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
         switch (value) {
-            case OEM_NETWORK_PREFERENCE_DEFAULT:
-                return "OEM_NETWORK_PREFERENCE_DEFAULT";
+            case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
+                return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
             case OEM_NETWORK_PREFERENCE_OEM_PAID:
                 return "OEM_NETWORK_PREFERENCE_OEM_PAID";
             case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
@@ -168,7 +197,7 @@
 
     @Override
     public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
-        dest.writeSparseArray(mNetworkMappings);
+        dest.writeBundle(mNetworkMappings);
     }
 
     @Override
@@ -187,7 +216,7 @@
                 @Override
                 public OemNetworkPreferences createFromParcel(@NonNull android.os.Parcel in) {
                     return new OemNetworkPreferences(
-                            in.readSparseArray(getClass().getClassLoader()));
+                            in.readBundle(getClass().getClassLoader()));
                 }
             };
 }
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
index 3f2aa17..012410b 100644
--- a/core/java/android/net/StringNetworkSpecifier.java
+++ b/core/java/android/net/StringNetworkSpecifier.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -45,7 +46,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!(o instanceof StringNetworkSpecifier)) return false;
         return TextUtils.equals(specifier, ((StringNetworkSpecifier) o).specifier);
     }
diff --git a/core/java/android/net/TelephonyNetworkSpecifier.java b/core/java/android/net/TelephonyNetworkSpecifier.java
index 33c71d5..3348233 100644
--- a/core/java/android/net/TelephonyNetworkSpecifier.java
+++ b/core/java/android/net/TelephonyNetworkSpecifier.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -74,7 +75,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/UidRange.aidl
rename to core/java/android/net/UidRange.aidl
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index d75c43d..f0e7da7 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -18,8 +18,10 @@
 
 import static android.os.UserHandle.PER_USER_RANGE;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 
 import java.util.Collection;
 
@@ -40,8 +42,12 @@
         stop  = stopUid;
     }
 
-    public static UidRange createForUser(int userId) {
-        return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+    /** Creates a UidRange for the specified user. */
+    public static UidRange createForUser(UserHandle user) {
+        final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1);
+        final int start = UserHandle.getUid(user, 0 /* appId */);
+        final int end = UserHandle.getUid(nextUser, 0) - 1;
+        return new UidRange(start, end);
     }
 
     /** Returns the smallest user Id which is contained in this UidRange */
@@ -81,7 +87,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) {
             return true;
         }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 1cb4fe8..ffe4f3c 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -343,7 +343,7 @@
      * default port explicitly and the other leaves it implicit, they will not
      * be considered equal.
      */
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!(o instanceof Uri)) {
             return false;
         }
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
new file mode 100644
index 0000000..f472ed4
--- /dev/null
+++ b/core/java/android/net/VpnManager.java
@@ -0,0 +1,406 @@
+/*
+ * 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.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.RemoteException;
+
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.GeneralSecurityException;
+import java.util.List;
+
+/**
+ * This class provides an interface for apps to manage platform VPN profiles
+ *
+ * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
+ * further app intermediation. When a VPN profile is present and the app is selected as an always-on
+ * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
+ * app (unlike VpnService).
+ *
+ * <p>VPN apps using supported protocols should preferentially use this API over the {@link
+ * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
+ * the guarantee that VPN network traffic is not subjected to on-device packet interception.
+ *
+ * @see Ikev2VpnProfile
+ */
+public class VpnManager {
+    /** Type representing a lack of VPN @hide */
+    public static final int TYPE_VPN_NONE = -1;
+
+    /**
+     * A VPN created by an app using the {@link VpnService} API.
+     * @hide
+     */
+    public static final int TYPE_VPN_SERVICE = 1;
+
+    /**
+     * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}.
+     * @hide
+     */
+    public static final int TYPE_VPN_PLATFORM = 2;
+
+    /**
+     * An IPsec VPN created by the built-in LegacyVpnRunner.
+     * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead.
+     * @hide
+     */
+    @Deprecated
+    public static final int TYPE_VPN_LEGACY = 3;
+
+    /**
+     * Channel for VPN notifications.
+     * @hide
+     */
+    public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
+
+    /** @hide */
+    @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VpnType {}
+
+    @NonNull private final Context mContext;
+    @NonNull private final IVpnManager mService;
+
+    private static Intent getIntentForConfirmation() {
+        final Intent intent = new Intent();
+        final ComponentName componentName = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(
+                        com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
+        intent.setComponent(componentName);
+        return intent;
+    }
+
+    /**
+     * Create an instance of the VpnManager with the given context.
+     *
+     * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
+     * {@link Context.getSystemService()} method call.
+     *
+     * @hide
+     */
+    public VpnManager(@NonNull Context ctx, @NonNull IVpnManager service) {
+        mContext = checkNotNull(ctx, "missing Context");
+        mService = checkNotNull(service, "missing IVpnManager");
+    }
+
+    /**
+     * Install a VpnProfile configuration keyed on the calling app's package name.
+     *
+     * <p>This method returns {@code null} if user consent has already been granted, or an {@link
+     * Intent} to a system activity. If an intent is returned, the application should launch the
+     * activity using {@link Activity#startActivityForResult} to request user consent. The activity
+     * may pop up a dialog to require user action, and the result will come back via its {@link
+     * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
+     * consented, and the VPN profile can be started.
+     *
+     * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
+     *     stored for this package.
+     * @return an Intent requesting user consent to start the VPN, or null if consent is not
+     *     required based on privileges or previous user consent.
+     */
+    @Nullable
+    public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
+        final VpnProfile internalProfile;
+
+        try {
+            internalProfile = profile.toVpnProfile();
+        } catch (GeneralSecurityException | IOException e) {
+            // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
+            // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
+            // string as required by the VpnProfile.
+            throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
+        }
+
+        try {
+            // Profile can never be null; it either gets set, or an exception is thrown.
+            if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
+                return null;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return getIntentForConfirmation();
+    }
+
+    /**
+     * Delete the VPN profile configuration that was provisioned by the calling app
+     *
+     * @throws SecurityException if this would violate user settings
+     */
+    public void deleteProvisionedVpnProfile() {
+        try {
+            mService.deleteVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request the startup of a previously provisioned VPN.
+     *
+     * @throws SecurityException exception if user or device settings prevent this VPN from being
+     *     setup, or if user consent has not been granted
+     */
+    public void startProvisionedVpnProfile() {
+        try {
+            mService.startVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Tear down the VPN provided by the calling app (if any) */
+    public void stopProvisionedVpnProfile() {
+        try {
+            mService.stopVpnProfile(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the VPN configuration for the given user ID.
+     * @hide
+     */
+    @Nullable
+    public VpnConfig getVpnConfig(@UserIdInt int userId) {
+        try {
+            return mService.getVpnConfig(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Resets all VPN settings back to factory defaults.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void factoryReset() {
+        try {
+            mService.factoryReset();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Prepare for a VPN application.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param oldPackage Package name of the application which currently controls VPN, which will
+     *                   be replaced. If there is no such application, this should should either be
+     *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
+     * @param newPackage Package name of the application which should gain control of VPN, or
+     *                   {@code null} to disable.
+     * @param userId User for whom to prepare the new VPN.
+     *
+     * @hide
+     */
+    public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+            int userId) {
+        try {
+            return mService.prepareVpn(oldPackage, newPackage, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set whether the VPN package has the ability to launch VPNs without user intervention. This
+     * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
+     * class. If the caller is not {@code userId}, {@link
+     * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param packageName The package for which authorization state should change.
+     * @param userId User for whom {@code packageName} is installed.
+     * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
+     *     permissions should be granted. When unauthorizing an app, {@link
+     *     VpnManager.TYPE_VPN_NONE} should be used.
+     * @hide
+     */
+    public void setVpnPackageAuthorization(
+            String packageName, int userId, @VpnManager.VpnType int vpnType) {
+        try {
+            mService.setVpnPackageAuthorization(packageName, userId, vpnType);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks if a VPN app supports always-on mode.
+     *
+     * In order to support the always-on feature, an app has to
+     * <ul>
+     *     <li>target {@link VERSION_CODES#N API 24} or above, and
+     *     <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+     *         meta-data field.
+     * </ul>
+     *
+     * @param userId The identifier of the user for whom the VPN app is installed.
+     * @param vpnPackage The canonical package name of the VPN app.
+     * @return {@code true} if and only if the VPN app exists and supports always-on mode.
+     * @hide
+     */
+    public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
+        try {
+            return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Configures an always-on VPN connection through a specific application.
+     * This connection is automatically granted and persisted after a reboot.
+     *
+     * <p>The designated package should declare a {@link VpnService} in its
+     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+     *    otherwise the call will fail.
+     *
+     * @param userId The identifier of the user to set an always-on VPN for.
+     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+     *                   to remove an existing always-on VPN configuration.
+     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
+     *        {@code false} otherwise.
+     * @param lockdownAllowlist The list of packages that are allowed to access network directly
+     *         when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+     *         this method must be called when a package that should be allowed is installed or
+     *         uninstalled.
+     * @return {@code true} if the package is set as always-on VPN controller;
+     *         {@code false} otherwise.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
+            boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
+        try {
+            return mService.setAlwaysOnVpnPackage(
+                    userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the package name of the currently set always-on VPN application.
+     * If there is no always-on VPN set, or the VPN is provided by the system instead
+     * of by an app, {@code null} will be returned.
+     *
+     * @return Package name of VPN controller responsible for always-on VPN,
+     *         or {@code null} if none is set.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public String getAlwaysOnVpnPackageForUser(int userId) {
+        try {
+            return mService.getAlwaysOnVpnPackage(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return whether always-on VPN is in lockdown mode.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public boolean isVpnLockdownEnabled(int userId) {
+        try {
+            return mService.isVpnLockdownEnabled(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return the list of packages that are allowed to access network when always-on VPN is in
+     * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public List<String> getVpnLockdownAllowlist(int userId) {
+        try {
+            return mService.getVpnLockdownAllowlist(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the legacy VPN information for the specified user ID.
+     * @hide
+     */
+    public LegacyVpnInfo getLegacyVpnInfo(@UserIdInt int userId) {
+        try {
+            return mService.getLegacyVpnInfo(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Starts a legacy VPN.
+     * @hide
+     */
+    public void startLegacyVpn(VpnProfile profile) {
+        try {
+            mService.startLegacyVpn(profile);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Informs the service that legacy lockdown VPN state should be updated (e.g., if its keystore
+     * entry has been updated). If the LockdownVpn mechanism is enabled, updates the vpn
+     * with a reload of its profile.
+     *
+     * <p>This method can only be called by the system UID
+     * @return a boolean indicating success
+     *
+     * @hide
+     */
+    public boolean updateLockdownVpn() {
+        try {
+            return mService.updateLockdownVpn();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/Connectivity/framework/src/android/net/VpnService.java b/core/java/android/net/VpnService.java
similarity index 98%
rename from packages/Connectivity/framework/src/android/net/VpnService.java
rename to core/java/android/net/VpnService.java
index 8e90a119..f90fbaf 100644
--- a/packages/Connectivity/framework/src/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -170,12 +170,11 @@
             "android.net.VpnService.SUPPORTS_ALWAYS_ON";
 
     /**
-     * Use IConnectivityManager since those methods are hidden and not
-     * available in ConnectivityManager.
+     * Use IVpnManager since those methods are hidden and not available in VpnManager.
      */
-    private static IConnectivityManager getService() {
-        return IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+    private static IVpnManager getService() {
+        return IVpnManager.Stub.asInterface(
+                ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE));
     }
 
     /**
@@ -226,15 +225,15 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.CONTROL_VPN)
     public static void prepareAndAuthorize(Context context) {
-        IConnectivityManager cm = getService();
+        IVpnManager vm = getService();
         String packageName = context.getPackageName();
         try {
             // Only prepare if we're not already prepared.
             int userId = context.getUserId();
-            if (!cm.prepareVpn(packageName, null, userId)) {
-                cm.prepareVpn(null, packageName, userId);
+            if (!vm.prepareVpn(packageName, null, userId)) {
+                vm.prepareVpn(null, packageName, userId);
             }
-            cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
+            vm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
         } catch (RemoteException e) {
             // ignore
         }
@@ -597,7 +596,8 @@
                     }
                 }
             }
-            mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null));
+            mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null,
+                RouteInfo.RTN_UNICAST));
             mConfig.updateAllowedFamilies(address);
             return this;
         }
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 4f293ee..6a3cb42 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -18,6 +18,7 @@
 
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
+import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
@@ -33,4 +34,7 @@
     void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
     void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
     VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
+
+    void registerVcnStatusCallback(in ParcelUuid subscriptionGroup, in IVcnStatusCallback callback, in String opPkgName);
+    void unregisterVcnStatusCallback(in IVcnStatusCallback callback);
 }
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
new file mode 100644
index 0000000..555e9b5
--- /dev/null
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.net.vcn;
+
+/** @hide */
+interface IVcnStatusCallback {
+    void onEnteredSafeMode();
+    void onGatewayConnectionError(
+            in int[] gatewayNetworkCapabilities,
+            int errorCode,
+            in String exceptionClass,
+            in String exceptionMessage);
+}
\ No newline at end of file
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 5eb4ba6..52cc218 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.NetworkRequest;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -41,7 +42,6 @@
  * brought up on demand based on active {@link NetworkRequest}(s).
  *
  * @see VcnManager for more information on the Virtual Carrier Network feature
- * @hide
  */
 public final class VcnConfig implements Parcelable {
     @NonNull private static final String TAG = VcnConfig.class.getSimpleName();
@@ -56,7 +56,8 @@
             @NonNull String packageName,
             @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs) {
         mPackageName = packageName;
-        mGatewayConnectionConfigs = Collections.unmodifiableSet(gatewayConnectionConfigs);
+        mGatewayConnectionConfigs =
+                Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs));
 
         validate();
     }
@@ -96,11 +97,7 @@
         return mPackageName;
     }
 
-    /**
-     * Retrieves the set of configured tunnels.
-     *
-     * @hide
-     */
+    /** Retrieves the set of configured GatewayConnection(s). */
     @NonNull
     public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() {
         return Collections.unmodifiableSet(mGatewayConnectionConfigs);
@@ -168,11 +165,7 @@
                 }
             };
 
-    /**
-     * This class is used to incrementally build {@link VcnConfig} objects.
-     *
-     * @hide
-     */
+    /** This class is used to incrementally build {@link VcnConfig} objects. */
     public static final class Builder {
         @NonNull private final String mPackageName;
 
@@ -190,7 +183,6 @@
          *
          * @param gatewayConnectionConfig the configuration for an individual gateway connection
          * @return this {@link Builder} instance, for chaining
-         * @hide
          */
         @NonNull
         public Builder addGatewayConnectionConfig(
@@ -205,7 +197,6 @@
          * Builds and validates the VcnConfig.
          *
          * @return an immutable VcnConfig instance
-         * @hide
          */
         @NonNull
         public VcnConfig build() {
diff --git a/core/java/android/net/vcn/VcnControlPlaneConfig.java b/core/java/android/net/vcn/VcnControlPlaneConfig.java
new file mode 100644
index 0000000..92f6c44
--- /dev/null
+++ b/core/java/android/net/vcn/VcnControlPlaneConfig.java
@@ -0,0 +1,112 @@
+/*
+ * 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.net.vcn;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * This class represents a control plane configuration for a Virtual Carrier Network connection.
+ *
+ * <p>Each {@link VcnGatewayConnectionConfig} must have a {@link VcnControlPlaneConfig}, containing
+ * all connection, authentication and authorization parameters required to establish a Gateway
+ * Connection with a remote endpoint.
+ *
+ * <p>A {@link VcnControlPlaneConfig} object can be shared by multiple {@link
+ * VcnGatewayConnectionConfig}(s) if they will used for connecting with the same remote endpoint.
+ *
+ * @see VcnManager
+ * @see VcnGatewayConnectionConfig
+ */
+public abstract class VcnControlPlaneConfig {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CONFIG_TYPE_IKE})
+    public @interface ConfigType {}
+
+    /** @hide */
+    public static final int CONFIG_TYPE_IKE = 1;
+
+    private static final String CONFIG_TYPE_KEY = "mConfigType";
+    @ConfigType private final int mConfigType;
+
+    /**
+     * Package private constructor.
+     *
+     * @hide
+     */
+    VcnControlPlaneConfig(int configType) {
+        mConfigType = configType;
+    }
+
+    /**
+     * Constructs a VcnControlPlaneConfig object by deserializing a PersistableBundle.
+     *
+     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneConfig} object
+     * @hide
+     */
+    public static VcnControlPlaneConfig fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        int configType = in.getInt(CONFIG_TYPE_KEY);
+        switch (configType) {
+            case CONFIG_TYPE_IKE:
+                return new VcnControlPlaneIkeConfig(in);
+            default:
+                throw new IllegalStateException("Unrecognized configType: " + configType);
+        }
+    }
+
+    /**
+     * Converts this VcnControlPlaneConfig to a PersistableBundle.
+     *
+     * @hide
+     */
+    @NonNull
+    public PersistableBundle toPersistableBundle() {
+        final PersistableBundle result = new PersistableBundle();
+        result.putInt(CONFIG_TYPE_KEY, mConfigType);
+        return result;
+    }
+
+    /** @hide */
+    @Override
+    public int hashCode() {
+        return Objects.hash(mConfigType);
+    }
+
+    /** @hide */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof VcnControlPlaneConfig)) {
+            return false;
+        }
+
+        return mConfigType == ((VcnControlPlaneConfig) o).mConfigType;
+    }
+
+    /**
+     * Returns a deep copy of this object.
+     *
+     * @hide
+     */
+    public abstract VcnControlPlaneConfig copy();
+}
diff --git a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
new file mode 100644
index 0000000..de086f6
--- /dev/null
+++ b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
@@ -0,0 +1,150 @@
+/*
+ * 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.net.vcn;
+
+import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import java.util.Objects;
+
+/**
+ * This class is an IKEv2 control plane configuration for a Virtual Carrier Network connection.
+ *
+ * <p>This class is an extension of the {@link VcnControlPlaneConfig}, containing IKEv2-specific
+ * configuration, authentication and authorization parameters.
+ *
+ * @see VcnControlPlaneConfig
+ */
+public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
+    private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName();
+
+    // STOPSHIP: b/163604823 Make mIkeParams and mChildParams @NonNull when it is supported to
+    // construct mIkeParams and mChildParams from PersistableBundles.
+
+    private static final String IKE_PARAMS_KEY = "mIkeParams";
+    @Nullable private final IkeSessionParams mIkeParams;
+
+    private static final String CHILD_PARAMS_KEY = "mChildParams";
+    @Nullable private final TunnelModeChildSessionParams mChildParams;
+
+    private static final ArraySet<String> BUNDLE_KEY_SET = new ArraySet<>();
+
+    {
+        BUNDLE_KEY_SET.add(IKE_PARAMS_KEY);
+        BUNDLE_KEY_SET.add(CHILD_PARAMS_KEY);
+    }
+
+    /**
+     * Constructs a VcnControlPlaneIkeConfig object.
+     *
+     * @param ikeParams the IKE Session negotiation parameters
+     * @param childParams the tunnel mode Child Session negotiation parameters
+     */
+    public VcnControlPlaneIkeConfig(
+            @NonNull IkeSessionParams ikeParams,
+            @NonNull TunnelModeChildSessionParams childParams) {
+        super(CONFIG_TYPE_IKE);
+        mIkeParams = ikeParams;
+        mChildParams = childParams;
+        validate();
+    }
+
+    /**
+     * Constructs a VcnControlPlaneIkeConfig object by deserializing a PersistableBundle.
+     *
+     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneIkeConfig} object
+     * @hide
+     */
+    public VcnControlPlaneIkeConfig(@NonNull PersistableBundle in) {
+        super(CONFIG_TYPE_IKE);
+        final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY);
+        final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY);
+
+        // STOPSHIP: b/163604823 Support constructing mIkeParams and mChildParams from
+        // PersistableBundles.
+
+        mIkeParams = null;
+        mChildParams = null;
+    }
+
+    private void validate() {
+        Objects.requireNonNull(mIkeParams, "mIkeParams was null");
+        Objects.requireNonNull(mChildParams, "mChildParams was null");
+    }
+
+    /**
+     * Converts this VcnControlPlaneConfig to a PersistableBundle.
+     *
+     * @hide
+     */
+    @Override
+    @NonNull
+    public PersistableBundle toPersistableBundle() {
+        final PersistableBundle result = super.toPersistableBundle();
+
+        // STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to
+        // PersistableBundles.
+        return result;
+    }
+
+    /** Retrieves the IKE Session configuration. */
+    @NonNull
+    public IkeSessionParams getIkeSessionParams() {
+        return mIkeParams;
+    }
+
+    /** Retrieves the tunnel mode Child Session configuration. */
+    @NonNull
+    public TunnelModeChildSessionParams getChildSessionParams() {
+        return mChildParams;
+    }
+
+    /** @hide */
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mIkeParams, mChildParams);
+    }
+
+    /** @hide */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof VcnControlPlaneIkeConfig)) {
+            return false;
+        }
+
+        VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o;
+
+        // STOPSHIP: b/163604823 Also check mIkeParams and mChildParams when it is supported to
+        // construct mIkeParams and mChildParams from PersistableBundles. They are not checked
+        // now so that VcnGatewayConnectionConfigTest and VcnConfigTest can pass.
+        return super.equals(o);
+    }
+
+    /** @hide */
+    @Override
+    public VcnControlPlaneConfig copy() {
+        return new VcnControlPlaneIkeConfig(
+                new IkeSessionParams.Builder(mIkeParams).build(),
+                new TunnelModeChildSessionParams.Builder(mChildParams).build());
+    }
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index cead2f1..9f83b21 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -21,6 +21,8 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
@@ -55,28 +57,23 @@
  * subscription group under which this configuration is registered (see {@link
  * VcnManager#setVcnConfig}).
  *
- * <p>Services that can be provided by a VCN network, or required for underlying networks are
- * limited to services provided by cellular networks:
+ * <p>As an abstraction of a cellular network, services that can be provided by a VCN network, or
+ * required for underlying networks are limited to services provided by cellular networks:
  *
  * <ul>
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_MMS}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_SUPL}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_DUN}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_FOTA}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_IMS}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_CBS}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_IA}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_RCS}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_XCAP}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_EIMS}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET}
- *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_SUPL}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_DUN}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_FOTA}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IMS}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_CBS}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IA}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_RCS}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_XCAP}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_EIMS}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_INTERNET}
+ *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MCX}
  * </ul>
- *
- * <p>The meteredness and roaming of the VCN {@link Network} will be determined by that of the
- * underlying Network(s).
- *
- * @hide
  */
 public final class VcnGatewayConnectionConfig {
     // TODO: Use MIN_MTU_V6 once it is public, @hide
@@ -153,14 +150,15 @@
                 TimeUnit.MINUTES.toMillis(15)
             };
 
+    private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig";
+    @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig;
+
     private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
     @NonNull private final SortedSet<Integer> mExposedCapabilities;
 
     private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities";
     @NonNull private final SortedSet<Integer> mUnderlyingCapabilities;
 
-    // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig
-
     private static final String MAX_MTU_KEY = "mMaxMtu";
     private final int mMaxMtu;
 
@@ -169,10 +167,12 @@
 
     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
     private VcnGatewayConnectionConfig(
+            @NonNull VcnControlPlaneConfig ctrlPlaneConfig,
             @NonNull Set<Integer> exposedCapabilities,
             @NonNull Set<Integer> underlyingCapabilities,
             @NonNull long[] retryIntervalsMs,
             @IntRange(from = MIN_MTU_V6) int maxMtu) {
+        mCtrlPlaneConfig = ctrlPlaneConfig;
         mExposedCapabilities = new TreeSet(exposedCapabilities);
         mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
         mRetryIntervalsMs = retryIntervalsMs;
@@ -184,11 +184,16 @@
     /** @hide */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
+        final PersistableBundle ctrlPlaneConfigBundle =
+                in.getPersistableBundle(CTRL_PLANE_CONFIG_KEY);
+        Objects.requireNonNull(ctrlPlaneConfigBundle, "ctrlPlaneConfigBundle was null");
+
         final PersistableBundle exposedCapsBundle =
                 in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
         final PersistableBundle underlyingCapsBundle =
                 in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
 
+        mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle);
         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
         mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
@@ -200,6 +205,8 @@
     }
 
     private void validate() {
+        Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null");
+
         Preconditions.checkArgument(
                 mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
                 "exposedCapsBundle was null or empty");
@@ -243,14 +250,23 @@
     }
 
     /**
+     * Returns control plane configuration.
+     *
+     * @hide
+     */
+    @NonNull
+    public VcnControlPlaneConfig getControlPlaneConfig() {
+        return mCtrlPlaneConfig.copy();
+    }
+
+    /**
      * Returns all exposed capabilities.
      *
      * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in
      * ascending numerical order.
      *
      * @see Builder#addExposedCapability(int)
-     * @see Builder#clearExposedCapability(int)
-     * @hide
+     * @see Builder#removeExposedCapability(int)
      */
     @NonNull
     public int[] getExposedCapabilities() {
@@ -278,8 +294,7 @@
      * <p>The returned integer-value capabilities will be sorted in ascending numerical order.
      *
      * @see Builder#addRequiredUnderlyingCapability(int)
-     * @see Builder#clearRequiredUnderlyingCapability(int)
-     * @hide
+     * @see Builder#removeRequiredUnderlyingCapability(int)
      */
     @NonNull
     public int[] getRequiredUnderlyingCapabilities() {
@@ -305,7 +320,6 @@
      * Retrieves the configured retry intervals.
      *
      * @see Builder#setRetryInterval(long[])
-     * @hide
      */
     @NonNull
     public long[] getRetryInterval() {
@@ -317,7 +331,7 @@
      *
      * <p>Left to prevent the need to make major changes while changes are actively in flight.
      *
-     * @deprecated use getRequiredUnderlyingCapabilities() instead
+     * @deprecated use getRetryInterval() instead
      * @hide
      */
     @Deprecated
@@ -329,8 +343,7 @@
     /**
      * Retrieves the maximum MTU allowed for this Gateway Connection.
      *
-     * @see Builder.setMaxMtu(int)
-     * @hide
+     * @see Builder#setMaxMtu(int)
      */
     @IntRange(from = MIN_MTU_V6)
     public int getMaxMtu() {
@@ -347,6 +360,7 @@
     public PersistableBundle toPersistableBundle() {
         final PersistableBundle result = new PersistableBundle();
 
+        final PersistableBundle ctrlPlaneConfigBundle = mCtrlPlaneConfig.toPersistableBundle();
         final PersistableBundle exposedCapsBundle =
                 PersistableBundleUtils.fromList(
                         new ArrayList<>(mExposedCapabilities),
@@ -356,6 +370,7 @@
                         new ArrayList<>(mUnderlyingCapabilities),
                         PersistableBundleUtils.INTEGER_SERIALIZER);
 
+        result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle);
         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
         result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
         result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
@@ -388,10 +403,9 @@
 
     /**
      * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
-     *
-     * @hide
      */
     public static final class Builder {
+        @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig;
         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
         @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
         @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
@@ -402,6 +416,18 @@
         //       when on Cell.
 
         /**
+         * Construct a Builder object.
+         *
+         * @param ctrlPlaneConfig the control plane configuration
+         * @see VcnControlPlaneConfig
+         */
+        public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+            Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null");
+
+            mCtrlPlaneConfig = ctrlPlaneConfig;
+        }
+
+        /**
          * Add a capability that this VCN Gateway Connection will support.
          *
          * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway
@@ -409,7 +435,6 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
-         * @hide
          */
         @NonNull
         public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) {
@@ -427,10 +452,10 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
-         * @hide
          */
         @NonNull
-        public Builder clearExposedCapability(@VcnSupportedCapability int exposedCapability) {
+        @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
+        public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) {
             checkValidCapability(exposedCapability);
 
             mExposedCapabilities.remove(exposedCapability);
@@ -445,7 +470,6 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
-         * @hide
          */
         @NonNull
         public Builder addRequiredUnderlyingCapability(
@@ -468,10 +492,10 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
-         * @hide
          */
         @NonNull
-        public Builder clearRequiredUnderlyingCapability(
+        @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
+        public Builder removeRequiredUnderlyingCapability(
                 @VcnSupportedCapability int underlyingCapability) {
             checkValidCapability(underlyingCapability);
 
@@ -501,7 +525,6 @@
          *     15m]}
          * @return this {@link Builder} instance, for chaining
          * @see VcnManager for additional discussion on fail-safe mode
-         * @hide
          */
         @NonNull
         public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) {
@@ -523,7 +546,6 @@
          * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
          *     the IPv6 minimum MTU of 1280. Defaults to 1500.
          * @return this {@link Builder} instance, for chaining
-         * @hide
          */
         @NonNull
         public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
@@ -538,12 +560,15 @@
          * Builds and validates the VcnGatewayConnectionConfig.
          *
          * @return an immutable VcnGatewayConnectionConfig instance
-         * @hide
          */
         @NonNull
         public VcnGatewayConnectionConfig build() {
             return new VcnGatewayConnectionConfig(
-                    mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu);
+                    mCtrlPlaneConfig,
+                    mExposedCapabilities,
+                    mUnderlyingCapabilities,
+                    mRetryIntervalsMs,
+                    mMaxMtu);
         }
     }
 }
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index fa090f5..729e68a 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -17,19 +17,27 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
+import android.os.Binder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
@@ -37,12 +45,12 @@
 /**
  * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
  *
- * <p>A VCN creates a virtualization layer to allow MVNOs to aggregate heterogeneous physical
+ * <p>A VCN creates a virtualization layer to allow carriers to aggregate heterogeneous physical
  * networks, unifying them as a single carrier network. This enables infrastructure flexibility on
- * the part of MVNOs without impacting user connectivity, abstracting the physical network
+ * the part of carriers without impacting user connectivity, abstracting the physical network
  * technologies as an implementation detail of their public network.
  *
- * <p>Each VCN virtualizes an Carrier's network by building tunnels to a carrier's core network over
+ * <p>Each VCN virtualizes a carrier's network by building tunnels to a carrier's core network over
  * carrier-managed physical links and supports a IP mobility layer to ensure seamless transitions
  * between the underlying networks. Each VCN is configured based on a Subscription Group (see {@link
  * android.telephony.SubscriptionManager}) and aggregates all networks that are brought up based on
@@ -60,16 +68,12 @@
  * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default.
  * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will
  * automatically exit Safe Mode if all active tunnels connect successfully.
- *
- * @hide
  */
 @SystemService(Context.VCN_MANAGEMENT_SERVICE)
 public class VcnManager {
     @NonNull private static final String TAG = VcnManager.class.getSimpleName();
 
-    @VisibleForTesting
-    public static final Map<
-                    VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+    private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
             REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
 
     @NonNull private final Context mContext;
@@ -88,7 +92,18 @@
         mService = requireNonNull(service, "missing service");
     }
 
-    // TODO: Make setVcnConfig(), clearVcnConfig() Public API
+    /**
+     * Get all currently registered VcnNetworkPolicyListeners for testing purposes.
+     *
+     * @hide
+     */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+            getAllPolicyListeners() {
+        return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
+    }
+
     /**
      * Sets the VCN configuration for a given subscription group.
      *
@@ -100,11 +115,10 @@
      *
      * @param subscriptionGroup the subscription group that the configuration should be applied to
      * @param config the configuration parameters for the VCN
-     * @throws SecurityException if the caller does not have carrier privileges, or is not running
-     *     as the primary user
-     * @throws IOException if the configuration failed to be persisted. A caller encountering this
-     *     exception should attempt to retry (possibly after a delay).
-     * @hide
+     * @throws SecurityException if the caller does not have carrier privileges for the provided
+     *     subscriptionGroup, or is not running as the primary user
+     * @throws IOException if the configuration failed to be saved and persisted to disk. This may
+     *     occur due to temporary disk errors, or more permanent conditions such as a full disk.
      */
     @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
     public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config)
@@ -121,7 +135,6 @@
         }
     }
 
-    // TODO: Make setVcnConfig(), clearVcnConfig() Public API
     /**
      * Clears the VCN configuration for a given subscription group.
      *
@@ -132,9 +145,8 @@
      * @param subscriptionGroup the subscription group that the configuration should be applied to
      * @throws SecurityException if the caller does not have carrier privileges, or is not running
      *     as the primary user
-     * @throws IOException if the configuration failed to be cleared. A caller encountering this
-     *     exception should attempt to retry (possibly after a delay).
-     * @hide
+     * @throws IOException if the configuration failed to be cleared from disk. This may occur due
+     *     to temporary disk errors, or more permanent conditions such as a full disk.
      */
     @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
     public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) throws IOException {
@@ -149,22 +161,15 @@
         }
     }
 
-    // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi
+    // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using
+    // the new VcnNetworkPolicyListener API
     /**
      * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
      * can register to receive updates for VCN-underlying Network policies from the System Server.
      *
      * @hide
      */
-    public interface VcnUnderlyingNetworkPolicyListener {
-        /**
-         * Notifies the implementation that the VCN's underlying Network policy has changed.
-         *
-         * <p>After receiving this callback, implementations MUST poll VcnManager for the updated
-         * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy.
-         */
-        void onPolicyChanged();
-    }
+    public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {}
 
     /**
      * Add a listener for VCN-underlying network policy updates.
@@ -173,29 +178,14 @@
      *     Listener
      * @param listener the VcnUnderlyingNetworkPolicyListener to be added
      * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
-     * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is
-     *     already registered
+     * @throws IllegalStateException if the specified VcnUnderlyingNetworkPolicyListener is already
+     *     registered
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public void addVcnUnderlyingNetworkPolicyListener(
             @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
-        requireNonNull(executor, "executor must not be null");
-        requireNonNull(listener, "listener must not be null");
-
-        VcnUnderlyingNetworkPolicyListenerBinder binder =
-                new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
-        if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
-            throw new IllegalArgumentException(
-                    "Attempting to add a listener that is already in use");
-        }
-
-        try {
-            mService.addVcnUnderlyingNetworkPolicyListener(binder);
-        } catch (RemoteException e) {
-            REGISTERED_POLICY_LISTENERS.remove(listener);
-            throw e.rethrowFromSystemServer();
-        }
+        addVcnNetworkPolicyListener(executor, listener);
     }
 
     /**
@@ -208,19 +198,7 @@
      */
     public void removeVcnUnderlyingNetworkPolicyListener(
             @NonNull VcnUnderlyingNetworkPolicyListener listener) {
-        requireNonNull(listener, "listener must not be null");
-
-        VcnUnderlyingNetworkPolicyListenerBinder binder =
-                REGISTERED_POLICY_LISTENERS.remove(listener);
-        if (binder == null) {
-            return;
-        }
-
-        try {
-            mService.removeVcnUnderlyingNetworkPolicyListener(binder);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        removeVcnNetworkPolicyListener(listener);
     }
 
     /**
@@ -255,25 +233,341 @@
     }
 
     /**
-     * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
-     * Server.
+     * VcnNetworkPolicyListener is the interface through which internal system components (e.g.
+     * Network Factories) can register to receive updates for VCN-underlying Network policies from
+     * the System Server.
+     *
+     * <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks
+     * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify
+     * the registrant when VCN Network policies change. Upon receiving this signal, the listener
+     * must check {@link VcnManager} for the current Network policy result for each of its Networks
+     * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface VcnNetworkPolicyListener {
+        /**
+         * Notifies the implementation that the VCN's underlying Network policy has changed.
+         *
+         * <p>After receiving this callback, implementations should get the current {@link
+         * VcnNetworkPolicyResult} via {@link #applyVcnNetworkPolicy(NetworkCapabilities,
+         * LinkProperties)}.
+         */
+        void onPolicyChanged();
+    }
+
+    /**
+     * Add a listener for VCN-underlying Network policy updates.
+     *
+     * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is
+     * registered. No callbacks are guaranteed upon registration.
+     *
+     * @param executor the Executor that will be used for invoking all calls to the specified
+     *     Listener
+     * @param listener the VcnNetworkPolicyListener to be added
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+     * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public void addVcnNetworkPolicyListener(
+            @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) {
+        requireNonNull(executor, "executor must not be null");
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
+        if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
+            throw new IllegalStateException("listener is already registered with VcnManager");
+        }
+
+        try {
+            mService.addVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            REGISTERED_POLICY_LISTENERS.remove(listener);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove the specified VcnNetworkPolicyListener from VcnManager.
+     *
+     * <p>If the specified listener is not currently registered, this is a no-op.
+     *
+     * @param listener the VcnNetworkPolicyListener that will be removed
+     * @hide
+     */
+    @SystemApi
+    public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) {
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                REGISTERED_POLICY_LISTENERS.remove(listener);
+        if (binder == null) {
+            return;
+        }
+
+        try {
+            mService.removeVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Applies the network policy for a {@link android.net.Network} with the given parameters.
+     *
+     * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
+     * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider
+     * MUST poll for the updated Network policy based on that Network's capabilities and properties.
+     *
+     * @param networkCapabilities the NetworkCapabilities to be used in determining the Network
+     *     policy result for this Network.
+     * @param linkProperties the LinkProperties to be used in determining the Network policy result
+     *     for this Network.
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+     * @return the {@link VcnNetworkPolicyResult} to be used for this Network.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public VcnNetworkPolicyResult applyVcnNetworkPolicy(
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties) {
+        requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+        requireNonNull(linkProperties, "linkProperties must not be null");
+
+        final VcnUnderlyingNetworkPolicy policy =
+                getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+        return new VcnNetworkPolicyResult(
+                policy.isTeardownRequested(), policy.getMergedNetworkCapabilities());
+    }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        VCN_ERROR_CODE_INTERNAL_ERROR,
+        VCN_ERROR_CODE_CONFIG_ERROR,
+        VCN_ERROR_CODE_NETWORK_ERROR
+    })
+    public @interface VcnErrorCode {}
+
+    /**
+     * Value indicating that an internal failure occurred in this Gateway Connection.
+     *
+     * @hide
+     */
+    public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0;
+
+    /**
+     * Value indicating that an error with this Gateway Connection's configuration occurred.
+     *
+     * <p>For example, this error code will be returned after authentication failures.
+     *
+     * @hide
+     */
+    public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1;
+
+    /**
+     * Value indicating that a Network error occurred with this Gateway Connection.
+     *
+     * <p>For example, this error code will be returned if an underlying {@link android.net.Network}
+     * for this Gateway Connection is lost, or if an error occurs while resolving the connection
+     * endpoint address.
+     *
+     * @hide
+     */
+    public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2;
+
+    // TODO: make VcnStatusCallback @SystemApi
+    /**
+     * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs.
+     *
+     * <p>VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a
+     * subscription group.
+     *
+     * @hide
+     */
+    public abstract static class VcnStatusCallback {
+        private VcnStatusCallbackBinder mCbBinder;
+
+        /**
+         * Invoked when the VCN for this Callback's subscription group enters safe mode.
+         *
+         * <p>A VCN will be put into safe mode if any of the gateway connections were unable to
+         * establish a connection within a system-determined timeout (while underlying networks were
+         * available).
+         *
+         * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration
+         * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
+         */
+        public abstract void onEnteredSafeMode();
+
+        /**
+         * Invoked when a VCN Gateway Connection corresponding to this callback's subscription
+         * encounters an error.
+         *
+         * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway
+         *     Connection that encountered the error for identification purposes. These will be a
+         *     sorted list with no duplicates, matching one of the {@link
+         *     VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
+         *     group.
+         * @param errorCode {@link VcnErrorCode} to indicate the error that occurred
+         * @param detail Throwable to provide additional information about the error, or {@code
+         *     null} if none
+         */
+        public abstract void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable Throwable detail);
+    }
+
+    /**
+     * Registers the given callback to receive status updates for the specified subscription.
+     *
+     * <p>Callbacks can be registered for a subscription before {@link VcnConfig}s are set for it.
+     *
+     * <p>A {@link VcnStatusCallback} may only be registered for one subscription at a time. {@link
+     * VcnStatusCallback}s may be reused once unregistered.
+     *
+     * <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier
+     * privileges for the specified subscription at the time of invocation.
+     *
+     * @param subscriptionGroup The subscription group to match for callbacks
+     * @param executor The {@link Executor} to be used for invoking callbacks
+     * @param callback The VcnStatusCallback to be registered
+     * @throws IllegalStateException if callback is currently registered with VcnManager
+     * @hide
+     */
+    public void registerVcnStatusCallback(
+            @NonNull ParcelUuid subscriptionGroup,
+            @NonNull Executor executor,
+            @NonNull VcnStatusCallback callback) {
+        requireNonNull(subscriptionGroup, "subscriptionGroup must not be null");
+        requireNonNull(executor, "executor must not be null");
+        requireNonNull(callback, "callback must not be null");
+
+        synchronized (callback) {
+            if (callback.mCbBinder != null) {
+                throw new IllegalStateException("callback is already registered with VcnManager");
+            }
+            callback.mCbBinder = new VcnStatusCallbackBinder(executor, callback);
+
+            try {
+                mService.registerVcnStatusCallback(
+                        subscriptionGroup, callback.mCbBinder, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                callback.mCbBinder = null;
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Unregisters the given callback.
+     *
+     * <p>Once unregistered, the callback will stop receiving status updates for the subscription it
+     * was registered with.
+     *
+     * @param callback The callback to be unregistered
+     * @hide
+     */
+    public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) {
+        requireNonNull(callback, "callback must not be null");
+
+        synchronized (callback) {
+            if (callback.mCbBinder == null) {
+                // no Binder attached to this callback, so it's not currently registered
+                return;
+            }
+
+            try {
+                mService.unregisterVcnStatusCallback(callback.mCbBinder);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            } finally {
+                callback.mCbBinder = null;
+            }
+        }
+    }
+
+    /**
+     * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server.
      *
      * @hide
      */
     private static class VcnUnderlyingNetworkPolicyListenerBinder
             extends IVcnUnderlyingNetworkPolicyListener.Stub {
         @NonNull private final Executor mExecutor;
-        @NonNull private final VcnUnderlyingNetworkPolicyListener mListener;
+        @NonNull private final VcnNetworkPolicyListener mListener;
 
         private VcnUnderlyingNetworkPolicyListenerBinder(
-                Executor executor, VcnUnderlyingNetworkPolicyListener listener) {
+                Executor executor, VcnNetworkPolicyListener listener) {
             mExecutor = executor;
             mListener = listener;
         }
 
         @Override
         public void onPolicyChanged() {
-            mExecutor.execute(() -> mListener.onPolicyChanged());
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> mListener.onPolicyChanged()));
+        }
+    }
+
+    /**
+     * Binder wrapper for VcnStatusCallbacks to receive signals from VcnManagementService.
+     *
+     * @hide
+     */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub {
+        @NonNull private final Executor mExecutor;
+        @NonNull private final VcnStatusCallback mCallback;
+
+        public VcnStatusCallbackBinder(
+                @NonNull Executor executor, @NonNull VcnStatusCallback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onEnteredSafeMode() {
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
+        }
+
+        // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
+        @Override
+        public void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable String exceptionClass,
+                @Nullable String exceptionMessage) {
+            final Throwable cause = createThrowableByClassName(exceptionClass, exceptionMessage);
+
+            Binder.withCleanCallingIdentity(
+                    () ->
+                            mExecutor.execute(
+                                    () ->
+                                            mCallback.onGatewayConnectionError(
+                                                    networkCapabilities, errorCode, cause)));
+        }
+
+        private static Throwable createThrowableByClassName(
+                @Nullable String className, @Nullable String message) {
+            if (className == null) {
+                return null;
+            }
+
+            try {
+                Class<?> c = Class.forName(className);
+                return (Throwable) c.getConstructor(String.class).newInstance(message);
+            } catch (ReflectiveOperationException | ClassCastException e) {
+                return new RuntimeException(className + ": " + message);
+            }
         }
     }
 }
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl
similarity index 82%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to core/java/android/net/vcn/VcnNetworkPolicyResult.aidl
index 46bc4ab..3f13abe 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.net.vcn;
 
-parcelable ApnThrottleStatus;
+/** @hide */
+parcelable VcnNetworkPolicyResult;
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
new file mode 100644
index 0000000..5e93820
--- /dev/null
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
@@ -0,0 +1,114 @@
+/*
+ * 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.net.vcn;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnNetworkPolicyResult represents the Network policy result for a Network transport applying its
+ * VCN policy via {@link VcnManager#applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+ *
+ * <p>Bearers that are bringing up networks capable of acting as a VCN's underlying network should
+ * query for Network policy results upon any capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via {@link VcnManager.VcnNetworkPolicyListener}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VcnNetworkPolicyResult implements Parcelable {
+    private final boolean mIsTearDownRequested;
+    private final NetworkCapabilities mNetworkCapabilities;
+
+    /**
+     * Constructs a VcnNetworkPolicyResult with the specified parameters.
+     *
+     * @hide
+     */
+    public VcnNetworkPolicyResult(
+            boolean isTearDownRequested, @NonNull NetworkCapabilities networkCapabilities) {
+        Objects.requireNonNull(networkCapabilities, "networkCapabilities must be non-null");
+
+        mIsTearDownRequested = isTearDownRequested;
+        mNetworkCapabilities = networkCapabilities;
+    }
+
+    /**
+     * Returns whether this VCN policy result requires that the underlying Network should be torn
+     * down.
+     *
+     * <p>Upon querying for the current Network policy result, the bearer must check this method,
+     * and MUST tear down the corresponding Network if it returns true.
+     */
+    public boolean isTeardownRequested() {
+        return mIsTearDownRequested;
+    }
+
+    /**
+     * Returns the NetworkCapabilities that the bearer should be using for the corresponding
+     * Network.
+     */
+    @NonNull
+    public NetworkCapabilities getNetworkCapabilities() {
+        return mNetworkCapabilities;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsTearDownRequested, mNetworkCapabilities);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof VcnNetworkPolicyResult)) return false;
+        final VcnNetworkPolicyResult that = (VcnNetworkPolicyResult) o;
+
+        return mIsTearDownRequested == that.mIsTearDownRequested
+                && mNetworkCapabilities.equals(that.mNetworkCapabilities);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBoolean(mIsTearDownRequested);
+        dest.writeParcelable(mNetworkCapabilities, flags);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<VcnNetworkPolicyResult> CREATOR =
+            new Creator<VcnNetworkPolicyResult>() {
+                public VcnNetworkPolicyResult createFromParcel(Parcel in) {
+                    return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null));
+                }
+
+                public VcnNetworkPolicyResult[] newArray(int size) {
+                    return new VcnNetworkPolicyResult[size];
+                }
+            };
+}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
index dd7c86d8..b47d564 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -33,8 +33,7 @@
  * @hide
  */
 public final class VcnUnderlyingNetworkPolicy implements Parcelable {
-    private final boolean mIsTearDownRequested;
-    private final NetworkCapabilities mMergedNetworkCapabilities;
+    private final VcnNetworkPolicyResult mVcnNetworkPolicyResult;
 
     /**
      * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
@@ -46,8 +45,13 @@
         Objects.requireNonNull(
                 mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
 
-        mIsTearDownRequested = isTearDownRequested;
-        mMergedNetworkCapabilities = mergedNetworkCapabilities;
+        mVcnNetworkPolicyResult =
+                new VcnNetworkPolicyResult(isTearDownRequested, mergedNetworkCapabilities);
+    }
+
+    private VcnUnderlyingNetworkPolicy(@NonNull VcnNetworkPolicyResult vcnNetworkPolicyResult) {
+        this.mVcnNetworkPolicyResult =
+                Objects.requireNonNull(vcnNetworkPolicyResult, "vcnNetworkPolicyResult");
     }
 
     /**
@@ -55,7 +59,7 @@
      * be torn down.
      */
     public boolean isTeardownRequested() {
-        return mIsTearDownRequested;
+        return mVcnNetworkPolicyResult.isTeardownRequested();
     }
 
     /**
@@ -64,12 +68,12 @@
      */
     @NonNull
     public NetworkCapabilities getMergedNetworkCapabilities() {
-        return mMergedNetworkCapabilities;
+        return mVcnNetworkPolicyResult.getNetworkCapabilities();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+        return Objects.hash(mVcnNetworkPolicyResult);
     }
 
     @Override
@@ -78,8 +82,7 @@
         if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
         final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
 
-        return mIsTearDownRequested == that.mIsTearDownRequested
-                && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+        return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult);
     }
 
     /** {@inheritDoc} */
@@ -91,16 +94,14 @@
     /** {@inheritDoc} */
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeBoolean(mIsTearDownRequested);
-        dest.writeParcelable(mMergedNetworkCapabilities, flags);
+        dest.writeParcelable(mVcnNetworkPolicyResult, flags);
     }
 
     /** Implement the Parcelable interface */
     public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
             new Creator<VcnUnderlyingNetworkPolicy>() {
                 public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
-                    return new VcnUnderlyingNetworkPolicy(
-                            in.readBoolean(), in.readParcelable(null));
+                    return new VcnUnderlyingNetworkPolicy(in.readParcelable(null));
                 }
 
                 public VcnUnderlyingNetworkPolicy[] newArray(int size) {
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
new file mode 100644
index 0000000..a975637
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
@@ -0,0 +1,125 @@
+/*
+ * 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.net.vcn;
+
+import android.annotation.NonNull;
+import android.net.NetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * NetworkSpecifier object for VCN underlying network requests.
+ *
+ * <p>This matches any underlying network with the appropriate subIds.
+ *
+ * @hide
+ */
+public final class VcnUnderlyingNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+    @NonNull private final int[] mSubIds;
+
+    /**
+     * Builds a new VcnUnderlyingNetworkSpecifier with the given list of subIds
+     *
+     * @hide
+     */
+    public VcnUnderlyingNetworkSpecifier(@NonNull int[] subIds) {
+        mSubIds = Objects.requireNonNull(subIds, "subIds were null");
+    }
+
+    /**
+     * Retrieves the list of subIds supported by this VcnUnderlyingNetworkSpecifier
+     *
+     * @hide
+     */
+    @NonNull
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public int[] getSubIds() {
+        return mSubIds;
+    }
+
+    public static final @NonNull Creator<VcnUnderlyingNetworkSpecifier> CREATOR =
+            new Creator<VcnUnderlyingNetworkSpecifier>() {
+                @Override
+                public VcnUnderlyingNetworkSpecifier createFromParcel(Parcel in) {
+                    int[] subIds = in.createIntArray();
+                    return new VcnUnderlyingNetworkSpecifier(subIds);
+                }
+
+                @Override
+                public VcnUnderlyingNetworkSpecifier[] newArray(int size) {
+                    return new VcnUnderlyingNetworkSpecifier[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeIntArray(mSubIds);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(mSubIds);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof VcnUnderlyingNetworkSpecifier)) {
+            return false;
+        }
+
+        VcnUnderlyingNetworkSpecifier lhs = (VcnUnderlyingNetworkSpecifier) obj;
+        return Arrays.equals(mSubIds, lhs.mSubIds);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("VcnUnderlyingNetworkSpecifier [")
+                .append("mSubIds = ").append(Arrays.toString(mSubIds))
+                .append("]")
+                .toString();
+    }
+
+    /** @hide */
+    @Override
+    public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+        if (other instanceof TelephonyNetworkSpecifier) {
+            return ArrayUtils.contains(
+                    mSubIds, ((TelephonyNetworkSpecifier) other).getSubscriptionId());
+        }
+        // TODO(b/180140053): Allow matching against WifiNetworkAgentSpecifier
+
+        // MatchAllNetworkSpecifier matched in NetworkCapabilities.
+        return equals(other);
+    }
+}
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 0185ba4..16d041a 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -547,7 +547,8 @@
         }
 
         try {
-            return transactNative(code, data, reply, flags);
+            boolean replyOwnsNative = (reply == null) ? false : reply.ownsNativeParcelObject();
+            return transactNative(code, data, reply, replyOwnsNative, flags);
         } finally {
             AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
 
@@ -572,7 +573,7 @@
      * Native implementation of transact() for proxies
      */
     public native boolean transactNative(int code, Parcel data, Parcel reply,
-            int flags) throws RemoteException;
+            boolean replyOwnsNativeParcelObject, int flags) throws RemoteException;
     /**
      * See {@link IBinder#linkToDeath(DeathRecipient, int)}
      */
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 305c686..a435ac1 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.WorkerThread;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.util.Log;
@@ -41,7 +42,15 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 
-/** Class that provides a privileged API to capture and consume bugreports. */
+/**
+ * Class that provides a privileged API to capture and consume bugreports.
+ *
+ * <p>This class may only be used by apps that currently have carrier privileges (see {@link
+ * android.telephony.TelephonyManager#hasCarrierPrivileges}) on an active SIM or priv-apps
+ * explicitly allowed by the device manufacturer.
+ *
+ * <p>Only one bugreport can be generated by the system at a time.
+ */
 @SystemService(Context.BUGREPORT_SERVICE)
 public final class BugreportManager {
 
@@ -56,7 +65,12 @@
         mBinder = binder;
     }
 
-    /** An interface describing the callback for bugreport progress and status. */
+    /**
+     * An interface describing the callback for bugreport progress and status.
+     *
+     * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport
+     * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}.
+     */
     public abstract static class BugreportCallback {
         /**
          * Possible error codes taking a bugreport can encounter.
@@ -75,15 +89,18 @@
                 })
         public @interface BugreportErrorCode {}
 
-        /** The input options were invalid */
+        /**
+         * The input options were invalid. For example, the destination file the app provided could
+         * not be written by the system.
+         */
         public static final int BUGREPORT_ERROR_INVALID_INPUT =
                 IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
 
-        /** A runtime error occurred */
+        /** A runtime error occurred. */
         public static final int BUGREPORT_ERROR_RUNTIME =
                 IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
 
-        /** User denied consent to share the bugreport */
+        /** User denied consent to share the bugreport. */
         public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT =
                 IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
 
@@ -149,6 +166,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
+    @WorkerThread
     public void startBugreport(
             @NonNull ParcelFileDescriptor bugreportFd,
             @Nullable ParcelFileDescriptor screenshotFd,
@@ -222,6 +240,7 @@
      * @param callback callback for progress and status updates.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @WorkerThread
     public void startConnectivityBugreport(
             @NonNull ParcelFileDescriptor bugreportFd,
             @NonNull @CallbackExecutor Executor executor,
@@ -247,6 +266,7 @@
      * @throws SecurityException if trying to cancel another app's bugreport in progress
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @WorkerThread
     public void cancelBugreport() {
         try {
             mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 27dc6e0..903bea3 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1902,7 +1902,8 @@
      * Retrieves the PSS memory used by the process as given by the smaps. Optionally supply a long
      * array of up to 3 entries to also receive (up to 3 values in order): the Uss and SwapPss and
      * Rss (only filled in as of {@link android.os.Build.VERSION_CODES#P}) of the process, and
-     * another array to also retrieve the separate memtrack size.
+     * another array to also retrieve the separate memtrack sizes (up to 4 values in order): the
+     * total memtrack reported size, memtrack graphics, memtrack gl and memtrack other.
      *
      * @return The PSS memory usage, or 0 if failed to retrieve (i.e., given pid has gone).
      * @hide
@@ -2551,6 +2552,22 @@
     public static native long getZramFreeKb();
 
     /**
+     * Return total memory size in kilobytes for exported DMA-BUFs or -1 if
+     * the DMA-BUF sysfs stats at /sys/kernel/dmabuf/buffers could not be read.
+     *
+     * @hide
+     */
+    public static native long getDmabufTotalExportedKb();
+
+    /**
+     * Return total memory size in kilobytes for DMA-BUFs exported from the DMA-BUF
+     * heaps frameworks or -1 in the case of an error.
+     *
+     * @hide
+     */
+    public static native long getDmabufHeapTotalExportedKb();
+
+    /**
      * Return memory size in kilobytes allocated for ION heaps or -1 if
      * /sys/kernel/ion/total_heaps_kb could not be read.
      *
@@ -2559,6 +2576,14 @@
     public static native long getIonHeapsSizeKb();
 
     /**
+     * Return memory size in kilobytes allocated for DMA-BUF heap pools or -1 if
+     * /sys/kernel/dma_heap/total_pools_kb could not be read.
+     *
+     * @hide
+     */
+    public static native long getDmabufHeapPoolsSizeKb();
+
+    /**
      * Return memory size in kilobytes allocated for ION pools or -1 if
      * /sys/kernel/ion/total_pools_kb could not be read.
      *
@@ -2567,13 +2592,20 @@
     public static native long getIonPoolsSizeKb();
 
     /**
-     * Return ION memory mapped by processes in kB.
+     * Return GPU DMA buffer usage in kB or -1 on error.
+     *
+     * @hide
+     */
+    public static native long getGpuDmaBufUsageKb();
+
+    /**
+     * Return DMA-BUF memory mapped by processes in kB.
      * Notes:
      *  * Warning: Might impact performance as it reads /proc/<pid>/maps files for each process.
      *
      * @hide
      */
-    public static native long getIonMappedSizeKb();
+    public static native long getDmabufMappedSizeKb();
 
     /**
      * Return memory size in kilobytes used by GPU.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 33dedda..874add5 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -24,7 +24,6 @@
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.UidRange;
-import android.os.INetworkActivityListener;
 
 /**
  * @hide
@@ -294,25 +293,6 @@
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean isBandwidthControlEnabled();
 
-    /**
-     * Sets idletimer for an interface.
-     *
-     * This either initializes a new idletimer or increases its
-     * reference-counting if an idletimer already exists for given
-     * {@code iface}.
-     *
-     * {@code type} is the type of the interface, such as TYPE_MOBILE.
-     *
-     * Every {@code addIdleTimer} should be paired with a
-     * {@link removeIdleTimer} to cleanup when the network disconnects.
-     */
-    void addIdleTimer(String iface, int timeout, int type);
-
-    /**
-     * Removes idletimer for an interface.
-     */
-    void removeIdleTimer(String iface);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
@@ -320,21 +300,6 @@
     void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
     void setFirewallChainEnabled(int chain, boolean enable);
 
-    /**
-     * Start listening for mobile activity state changes.
-     */
-    void registerNetworkActivityListener(INetworkActivityListener listener);
-
-    /**
-     * Stop listening for mobile activity state changes.
-     */
-    void unregisterNetworkActivityListener(INetworkActivityListener listener);
-
-    /**
-     * Check whether the mobile radio is currently active.
-     */
-    boolean isNetworkActive();
-
     void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
 
     /**
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 52f0ce1..4d160da 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -35,4 +35,9 @@
      * @see SystemConfigManager#getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries
      */
     Map getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries();
+
+    /**
+     * @see SystemConfigManager#getSystemPermissionUids
+     */
+    int[] getSystemPermissionUids(String permissionName);
 }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6acdcc4..f0a99ed 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3691,4 +3691,9 @@
     public long getBlobAshmemSize() {
         return nativeGetBlobAshmemSize(mNativePtr);
     }
+
+    /** @hide */
+    /*package*/ boolean ownsNativeParcelObject() {
+        return mOwnsNativeParcelObject;
+    }
 }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 6713de8..43184ea 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -26,6 +26,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
@@ -631,10 +632,15 @@
     /**
      * Prepare to apply an unattended update by asking the user for their Lock Screen Knowledge
      * Factor (LSKF). If supplied, the {@code intentSender} will be called when the system is setup
-     * and ready to apply the OTA. This API is expected to handle requests from multiple clients
-     * simultaneously, e.g. from ota and mainline.
+     * and ready to apply the OTA. <p>
      *
-     * <p> The behavior of multi-client Resume on Reboot works as follows
+     * <p> If the device doesn't setup a lock screen, i.e. by checking
+     * {@link KeyguardManager#isKeyguardSecure()}, this API call will fail and throw an exception.
+     * Callers are expected to use {@link PowerManager#reboot(String)} directly without going
+     * through the RoR flow. <p>
+     *
+     * <p>  This API is expected to handle requests from multiple clients simultaneously, e.g.
+     * from ota and mainline. The behavior of multi-client Resume on Reboot works as follows
      * <li> Each client should call this function to prepare for Resume on Reboot before calling
      *      {@link #rebootAndApply(Context, String, boolean)} </li>
      * <li> One client cannot clear the Resume on Reboot preparation of another client. </li>
@@ -658,6 +664,13 @@
         if (updateToken == null) {
             throw new NullPointerException("updateToken == null");
         }
+
+        KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+        if (keyguardManager == null || !keyguardManager.isDeviceSecure()) {
+            throw new IOException("Failed to request LSKF because the device doesn't have a"
+                    + " lock screen. ");
+        }
+
         RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
         if (!rs.requestLskf(context.getPackageName(), intentSender)) {
             throw new IOException("preparation for update failed");
@@ -958,7 +971,11 @@
             Intent intent = new Intent(ACTION_EUICC_FACTORY_RESET);
             intent.setPackage(packageName);
             PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
-                    context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
+                    context,
+                    0,
+                    intent,
+                    PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+                    UserHandle.SYSTEM);
             IntentFilter filterConsent = new IntentFilter();
             filterConsent.addAction(ACTION_EUICC_FACTORY_RESET);
             HandlerThread euiccHandlerThread = new HandlerThread("euiccWipeFinishReceiverThread");
@@ -1052,7 +1069,11 @@
         Intent intent = new Intent(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
         intent.setPackage(PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);
         PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
-                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
+                context,
+                0,
+                intent,
+                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+                UserHandle.SYSTEM);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
         HandlerThread euiccHandlerThread =
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index 3f0632b..9bfa8ad 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -111,4 +111,22 @@
             return Collections.emptyMap();
         }
     }
+
+    /**
+     * Get uids which have been granted given permission in system configuration.
+     *
+     * The uids and assigning permissions are defined on data/etc/platform.xml
+     *
+     * @param permissionName The target permission.
+     * @return The uids have been granted given permission in system configuration.
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    @NonNull
+    public int[] getSystemPermissionUids(@NonNull String permissionName) {
+        try {
+            return mInterface.getSystemPermissionUids(permissionName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 9c9e499..c8cbc51 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -168,8 +168,10 @@
     }
 
     /**
-     * Set whether application tracing is allowed for this process.  This is intended to be set
-     * once at application start-up time based on whether the application is debuggable.
+     * From Android S, this is no-op.
+     *
+     * Before, set whether application tracing is allowed for this process.  This is intended to be
+     * set once at application start-up time based on whether the application is debuggable.
      *
      * @hide
      */
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index bef876f9..3d539a6 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -295,6 +295,19 @@
     }
 
     /**
+     * Returns the uid that is composed from the userHandle and the appId.
+     *
+     * @param userHandle the UserHandle to compose the uid
+     * @param appId the AppId to compose the uid
+     * @return the uid that is composed from the userHandle and the appId
+     * @hide
+     */
+    @SystemApi
+    public static int getUid(@NonNull UserHandle userHandle, @AppIdInt int appId) {
+        return getUid(userHandle.getIdentifier(), appId);
+    }
+
+    /**
      * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
      * @hide
      */
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index d09f351..b323468 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,6 +1,5 @@
 # Bug component: 137825
 
-moltmann@google.com
 evanseverson@google.com
 ntmyren@google.com
 zhanghai@google.com
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
index d09f351..b323468 100644
--- a/core/java/android/permissionpresenterservice/OWNERS
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -1,6 +1,5 @@
 # Bug component: 137825
 
-moltmann@google.com
 evanseverson@google.com
 ntmyren@google.com
 zhanghai@google.com
diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/print/OWNERS
+++ b/core/java/android/print/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 47273
 
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
diff --git a/core/java/android/print/pdf/OWNERS b/core/java/android/print/pdf/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/print/pdf/OWNERS
+++ b/core/java/android/print/pdf/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 47273
 
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/printservice/OWNERS
+++ b/core/java/android/printservice/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 47273
 
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
diff --git a/core/java/android/printservice/recommendation/OWNERS b/core/java/android/printservice/recommendation/OWNERS
index 72f0983..28a24203 100644
--- a/core/java/android/printservice/recommendation/OWNERS
+++ b/core/java/android/printservice/recommendation/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 47273
 
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
diff --git a/core/java/android/provider/OWNERS b/core/java/android/provider/OWNERS
index cb1509a..cb06515 100644
--- a/core/java/android/provider/OWNERS
+++ b/core/java/android/provider/OWNERS
@@ -1,5 +1,6 @@
 per-file *BlockedNumber* = file:/telephony/OWNERS
 per-file *Telephony* = file:/telephony/OWNERS
+per-file *SimPhonebook* = file:/telephony/OWNERS
 
 per-file *CallLog* = file:platform/packages/providers/ContactsProvider:/OWNERS
 per-file *Contacts* = file:platform/packages/providers/ContactsProvider:/OWNERS
diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java
new file mode 100644
index 0000000..074d5f1
--- /dev/null
+++ b/core/java/android/provider/SimPhonebookContract.java
@@ -0,0 +1,405 @@
+/*
+ * 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.provider;
+
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN_PATH_SEGMENT;
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN_PATH_SEGMENT;
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN_PATH_SEGMENT;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * The contract between the provider of contact records on the device's SIM cards and applications.
+ * Contains definitions of the supported URIs and columns.
+ *
+ * <p>This content provider does not support any of the QUERY_ARG_SQL* bundle arguments. An
+ * IllegalArgumentException will be thrown if these are included.
+ */
+public final class SimPhonebookContract {
+
+    /** The authority for the SIM phonebook provider. */
+    public static final String AUTHORITY = "com.android.simphonebook";
+    /** The content:// style uri to the authority for the SIM phonebook provider. */
+    @NonNull
+    public static final Uri AUTHORITY_URI = Uri.parse("content://com.android.simphonebook");
+    /**
+     * The Uri path element used to indicate that the following path segment is a subscription ID
+     * for the SIM card that will be operated on.
+     *
+     * @hide
+     */
+    public static final String SUBSCRIPTION_ID_PATH_SEGMENT = "subid";
+
+    private SimPhonebookContract() {
+    }
+
+    /**
+     * Returns the Uri path segment used to reference the specified elementary file type for Uris
+     * returned by this API.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String getEfUriPath(@ElementaryFiles.EfType int efType) {
+        switch (efType) {
+            case EF_ADN:
+                return EF_ADN_PATH_SEGMENT;
+            case EF_FDN:
+                return EF_FDN_PATH_SEGMENT;
+            case EF_SDN:
+                return EF_SDN_PATH_SEGMENT;
+            default:
+                throw new IllegalArgumentException("Unsupported EfType " + efType);
+        }
+    }
+
+    /** Constants for the contact records on a SIM card. */
+    public static final class SimRecords {
+
+        /**
+         * The subscription ID of the SIM the record is from.
+         *
+         * @see SubscriptionInfo#getSubscriptionId()
+         */
+        public static final String SUBSCRIPTION_ID = "subscription_id";
+        /**
+         * The type of the elementary file the record is from.
+         *
+         * @see ElementaryFiles#EF_ADN
+         * @see ElementaryFiles#EF_FDN
+         * @see ElementaryFiles#EF_SDN
+         */
+        public static final String ELEMENTARY_FILE_TYPE = "elementary_file_type";
+        /**
+         * The 1-based offset of the record in the elementary file that contains it.
+         *
+         * <p>This can be used to access individual SIM records by appending it to the
+         * elementary file URIs but it is not like a normal database ID because it is not
+         * auto-incrementing and it is not unique across SIM cards or elementary files. Hence, care
+         * should be taken when using it to ensure that it is applied to the correct SIM and EF.
+         *
+         * @see #getItemUri(int, int, int)
+         */
+        public static final String RECORD_NUMBER = "record_number";
+        /**
+         * The name for this record.
+         *
+         * <p>An {@link IllegalArgumentException} will be thrown by insert and update if this
+         * exceeds the maximum supported length. Use
+         * {@link #getEncodedNameLength(ContentResolver, String)} to check how long the name
+         * will be after encoding.
+         *
+         * @see ElementaryFiles#NAME_MAX_LENGTH
+         * @see #getEncodedNameLength(ContentResolver, String)
+         */
+        public static final String NAME = "name";
+        /**
+         * The phone number for this record.
+         *
+         * <p>Only dialable characters are supported.
+         *
+         * <p>An {@link IllegalArgumentException} will be thrown by insert and update if this
+         * exceeds the maximum supported length or contains unsupported characters.
+         *
+         * @see ElementaryFiles#PHONE_NUMBER_MAX_LENGTH
+         * @see android.telephony.PhoneNumberUtils#isDialable(char)
+         */
+        public static final String PHONE_NUMBER = "phone_number";
+
+        /** The MIME type of a CONTENT_URI subdirectory of a single SIM record. */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-contact_v2";
+        /** The MIME type of CONTENT_URI providing a directory of SIM records. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-contact_v2";
+
+        /**
+         * Value returned from {@link #getEncodedNameLength(ContentResolver, String)} when the name
+         * length could not be determined because the name could not be encoded.
+         */
+        public static final int ERROR_NAME_UNSUPPORTED = -1;
+
+        /**
+         * The method name used to get the encoded length of a value for {@link SimRecords#NAME}
+         * column.
+         *
+         * @hide
+         * @see #getEncodedNameLength(ContentResolver, String)
+         * @see ContentResolver#call(String, String, String, Bundle)
+         */
+        public static final String GET_ENCODED_NAME_LENGTH_METHOD_NAME = "get_encoded_name_length";
+
+        /**
+         * Extra key used for an integer value that contains the length in bytes of an encoded
+         * name.
+         *
+         * @hide
+         * @see #getEncodedNameLength(ContentResolver, String)
+         * @see #GET_ENCODED_NAME_LENGTH_METHOD_NAME
+         */
+        public static final String EXTRA_ENCODED_NAME_LENGTH =
+                "android.provider.extra.ENCODED_NAME_LENGTH";
+
+
+        /**
+         * Key for the PIN2 needed to modify FDN record that should be passed in the Bundle
+         * passed to {@link ContentResolver#insert(Uri, ContentValues, Bundle)},
+         * {@link ContentResolver#update(Uri, ContentValues, Bundle)}
+         * and {@link ContentResolver#delete(Uri, Bundle)}.
+         *
+         * <p>Modifying FDN records also requires either
+         * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+         * {@link TelephonyManager#hasCarrierPrivileges()}
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String QUERY_ARG_PIN2 = "android:query-arg-pin2";
+
+        private SimRecords() {
+        }
+
+        /**
+         * Returns the content Uri for the specified elementary file on the specified SIM.
+         *
+         * <p>When queried this Uri will return all of the contact records in the specified
+         * elementary file on the specified SIM. The available subscriptionIds and efTypes can
+         * be discovered by querying {@link ElementaryFiles#CONTENT_URI}.
+         *
+         * <p>If a SIM with the provided subscription ID does not exist or the SIM with the provided
+         * subscription ID doesn't support the specified entity file then queries will return
+         * and empty cursor and inserts will throw an {@link IllegalArgumentException}
+         *
+         * @param subscriptionId the subscriptionId of the SIM card that this Uri will reference
+         * @param efType         the elementary file on the SIM that this Uri will reference
+         * @see ElementaryFiles#EF_ADN
+         * @see ElementaryFiles#EF_FDN
+         * @see ElementaryFiles#EF_SDN
+         */
+        @NonNull
+        public static Uri getContentUri(int subscriptionId, @ElementaryFiles.EfType int efType) {
+            return buildContentUri(subscriptionId, efType).build();
+        }
+
+        /**
+         * Content Uri for the specific SIM record with the provided {@link #RECORD_NUMBER}.
+         *
+         * <p>When queried this will return the record identified by the provided arguments.
+         *
+         * <p>For a non-existent record:
+         * <ul>
+         *     <li>query will return an empty cursor</li>
+         *     <li>update will return 0</li>
+         *     <li>delete will return 0</li>
+         * </ul>
+         *
+         * @param subscriptionId the subscription ID of the SIM containing the record. If no SIM
+         *                       with this subscription ID exists then it will be treated as a
+         *                       non-existent record
+         * @param efType         the elementary file type containing the record. If the specified
+         *                       SIM doesn't support this elementary file then it will be treated
+         *                       as a non-existent record.
+         * @param recordNumber   the record number of the record this Uri should reference. This
+         *                       must be greater than 0. If there is no record with this record
+         *                       number in the specified entity file then it will be treated as a
+         *                       non-existent record.
+         */
+        @NonNull
+        public static Uri getItemUri(
+                int subscriptionId, @ElementaryFiles.EfType int efType, int recordNumber) {
+            // Elementary file record indices are 1-based.
+            Preconditions.checkArgument(recordNumber > 0, "Invalid recordNumber");
+
+            return buildContentUri(subscriptionId, efType)
+                    .appendPath(String.valueOf(recordNumber))
+                    .build();
+        }
+
+        /**
+         * Returns the number of bytes required to encode the specified name when it is stored
+         * on the SIM.
+         *
+         * <p>{@link ElementaryFiles#NAME_MAX_LENGTH} is specified in bytes but the encoded name
+         * may require more than 1 byte per character depending on the characters it contains. So
+         * this method can be used to check whether a name exceeds the max length.
+         *
+         * @return the number of bytes required by the encoded name or
+         * {@link #ERROR_NAME_UNSUPPORTED} if the name could not be encoded.
+         * @throws IllegalStateException if the provider fails to return the length.
+         * @see SimRecords#NAME
+         * @see ElementaryFiles#NAME_MAX_LENGTH
+         */
+        @WorkerThread
+        public static int getEncodedNameLength(
+                @NonNull ContentResolver resolver, @NonNull String name) {
+            Objects.requireNonNull(name);
+            Bundle result = resolver.call(AUTHORITY, GET_ENCODED_NAME_LENGTH_METHOD_NAME, name,
+                    null);
+            if (result == null || !result.containsKey(EXTRA_ENCODED_NAME_LENGTH)) {
+                throw new IllegalStateException("Provider malfunction: no length was returned.");
+            }
+            int length = result.getInt(EXTRA_ENCODED_NAME_LENGTH, ERROR_NAME_UNSUPPORTED);
+            if (length < 0 && length != ERROR_NAME_UNSUPPORTED) {
+                throw new IllegalStateException(
+                        "Provider malfunction: invalid length was returned.");
+            }
+            return length;
+        }
+
+        private static Uri.Builder buildContentUri(
+                int subscriptionId, @ElementaryFiles.EfType int efType) {
+            return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                    .authority(AUTHORITY)
+                    .appendPath(SUBSCRIPTION_ID_PATH_SEGMENT)
+                    .appendPath(String.valueOf(subscriptionId))
+                    .appendPath(getEfUriPath(efType));
+        }
+
+    }
+
+    /** Constants for metadata about the elementary files of the SIM cards in the phone. */
+    public static final class ElementaryFiles {
+
+        /** {@link SubscriptionInfo#getSimSlotIndex()} of the SIM for this row. */
+        public static final String SLOT_INDEX = "slot_index";
+        /** {@link SubscriptionInfo#getSubscriptionId()} of the SIM for this row. */
+        public static final String SUBSCRIPTION_ID = "subscription_id";
+        /**
+         * The elementary file type for this row.
+         *
+         * @see ElementaryFiles#EF_ADN
+         * @see ElementaryFiles#EF_FDN
+         * @see ElementaryFiles#EF_SDN
+         */
+        public static final String EF_TYPE = "ef_type";
+        /** The maximum number of records supported by the elementary file. */
+        public static final String MAX_RECORDS = "max_records";
+        /** Count of the number of records that are currently stored in the elementary file. */
+        public static final String RECORD_COUNT = "record_count";
+        /** The maximum length supported for the name of a record in the elementary file. */
+        public static final String NAME_MAX_LENGTH = "name_max_length";
+        /**
+         * The maximum length supported for the phone number of a record in the elementary file.
+         */
+        public static final String PHONE_NUMBER_MAX_LENGTH = "phone_number_max_length";
+
+        /**
+         * A value for an elementary file that is not recognized.
+         *
+         * <p>Generally this should be ignored. If new values are added then this will be used
+         * for apps that target SDKs where they aren't defined.
+         */
+        public static final int EF_UNKNOWN = 0;
+        /**
+         * Type for accessing records in the "abbreviated dialing number" (ADN) elementary file on
+         * the SIM.
+         *
+         * <p>ADN records are typically user created.
+         */
+        public static final int EF_ADN = 1;
+        /**
+         * Type for accessing records in the "fixed dialing number" (FDN) elementary file on the
+         * SIM.
+         *
+         * <p>FDN numbers are the numbers that are allowed to dialed for outbound calls when FDN is
+         * enabled.
+         *
+         * <p>FDN records cannot be modified by applications. Hence, insert, update and
+         * delete methods operating on this Uri will throw UnsupportedOperationException
+         */
+        public static final int EF_FDN = 2;
+        /**
+         * Type for accessing records in the "service dialing number" (SDN) elementary file on the
+         * SIM.
+         *
+         * <p>Typically SDNs are preset numbers provided by the carrier for common operations (e.g.
+         * voicemail, check balance, etc).
+         *
+         * <p>SDN records cannot be modified by applications. Hence, insert, update and delete
+         * methods operating on this Uri will throw UnsupportedOperationException
+         */
+        public static final int EF_SDN = 3;
+        /** @hide */
+        public static final String EF_ADN_PATH_SEGMENT = "adn";
+        /** @hide */
+        public static final String EF_FDN_PATH_SEGMENT = "fdn";
+        /** @hide */
+        public static final String EF_SDN_PATH_SEGMENT = "sdn";
+        /** The MIME type of CONTENT_URI providing a directory of ADN-like elementary files. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-elementary-file";
+        /** The MIME type of a CONTENT_URI subdirectory of a single ADN-like elementary file. */
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/sim-elementary-file";
+        /**
+         * The Uri path segment used to construct Uris for the metadata defined in this class.
+         *
+         * @hide
+         */
+        public static final String ELEMENTARY_FILES_PATH_SEGMENT = "elementary_files";
+
+        /** Content URI for the ADN-like elementary files available on the device. */
+        @NonNull
+        public static final Uri CONTENT_URI = AUTHORITY_URI
+                .buildUpon()
+                .appendPath(ELEMENTARY_FILES_PATH_SEGMENT).build();
+
+        private ElementaryFiles() {
+        }
+
+        /**
+         * Returns a content uri for a specific elementary file.
+         *
+         * <p>If a SIM with the specified subscriptionId is not present an exception will be thrown.
+         * If the SIM doesn't support the specified elementary file it will return an empty cursor.
+         */
+        @NonNull
+        public static Uri getItemUri(int subscriptionId, @EfType int efType) {
+            return CONTENT_URI.buildUpon().appendPath(SUBSCRIPTION_ID_PATH_SEGMENT)
+                    .appendPath(String.valueOf(subscriptionId))
+                    .appendPath(getEfUriPath(efType))
+                    .build();
+        }
+
+        /**
+         * Annotation for the valid elementary file types.
+         *
+         * @hide
+         */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                prefix = {"EF"},
+                value = {EF_UNKNOWN, EF_ADN, EF_FDN, EF_SDN})
+        public @interface EfType {
+        }
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f994d29..5a89cdf 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -80,6 +80,7 @@
     public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS =
             Tag.MIN_SECONDS_BETWEEN_OPS; // KM_UINT | 403;
     public static final int KM_TAG_MAX_USES_PER_BOOT = Tag.MAX_USES_PER_BOOT; // KM_UINT | 404;
+    public static final int KM_TAG_USAGE_COUNT_LIMIT = Tag.USAGE_COUNT_LIMIT; // KM_UINT | 405;
 
     public static final int KM_TAG_USER_ID = Tag.USER_ID; // KM_UINT | 501;
     public static final int KM_TAG_USER_SECURE_ID = Tag.USER_SECURE_ID; // KM_ULONG_REP | 502;
@@ -129,6 +130,15 @@
     public static final int KM_TAG_ASSOCIATED_DATA = Tag.ASSOCIATED_DATA; // KM_BYTES | 1000;
     public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
     public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
+    public static final int KM_TAG_RESET_SINCE_ID_ROTATION =
+            Tag.RESET_SINCE_ID_ROTATION;     // KM_BOOL | 1004
+    public static final int KM_TAG_CONFIRMATION_TOKEN = Tag.CONFIRMATION_TOKEN; // KM_BYTES | 1005;
+    public static final int KM_TAG_CERTIFICATE_SERIAL = Tag.CERTIFICATE_SERIAL; // KM_UINT | 1006;
+    public static final int KM_TAG_CERTIFICATE_SUBJECT = Tag.CERTIFICATE_SUBJECT; // KM_UINT | 1007;
+    public static final int KM_TAG_CERTIFICATE_NOT_BEFORE =
+            Tag.CERTIFICATE_NOT_BEFORE; // KM_DATE | 1008;
+    public static final int KM_TAG_CERTIFICATE_NOT_AFTER =
+            Tag.CERTIFICATE_NOT_AFTER; // KM_DATE | 1009;
 
     // Algorithm values.
     public static final int KM_ALGORITHM_RSA = Algorithm.RSA;
@@ -178,6 +188,7 @@
     public static final int KM_PURPOSE_VERIFY = KeyPurpose.VERIFY;
     public static final int KM_PURPOSE_WRAP = KeyPurpose.WRAP_KEY;
     public static final int KM_PURPOSE_AGREE_KEY = KeyPurpose.AGREE_KEY;
+    public static final int KM_PURPOSE_ATTEST_KEY = KeyPurpose.ATTEST_KEY;
 
     // Key formats.
     public static final int KM_KEY_FORMAT_X509 = KeyFormat.X509;
@@ -316,6 +327,10 @@
             ErrorCode.HARDWARE_TYPE_UNAVAILABLE; // -68;
     public static final int KM_ERROR_DEVICE_LOCKED =
             ErrorCode.DEVICE_LOCKED; // -72;
+    public static final int KM_ERROR_MISSING_NOT_BEFORE =
+            ErrorCode.MISSING_NOT_BEFORE; // -80;
+    public static final int KM_ERROR_MISSING_NOT_AFTER =
+            ErrorCode.MISSING_NOT_AFTER; // -80;
     public static final int KM_ERROR_UNIMPLEMENTED =
             ErrorCode.UNIMPLEMENTED; // -100;
     public static final int KM_ERROR_VERSION_MISMATCH =
diff --git a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
index 4ebaa96..ad49ffd 100644
--- a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
+++ b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
@@ -87,7 +87,9 @@
      * Implementation for wrapping the opaque blob used for resume-on-reboot prior to
      * reboot. The service should not assume any structure of the blob to be wrapped. The
      * implementation should wrap the opaque blob in a reasonable time or throw {@link IOException}
-     * if it's unable to complete the action.
+     * if it's unable to complete the action due to retry-able errors (e.g network errors)
+     * and {@link IllegalArgumentException} if {@code wrapBlob} fails due to fatal errors
+     * (e.g corrupted blob).
      *
      * @param blob             The opaque blob with size on the order of 100 bytes.
      * @param lifeTimeInMillis The life time of the blob. This must be strictly enforced by the
@@ -95,7 +97,8 @@
      *                         this function after expiration should
      *                         fail.
      * @return Wrapped blob to be persisted across reboot with size on the order of 100 bytes.
-     * @throws IOException if the implementation is unable to wrap the blob successfully.
+     * @throws IOException if the implementation is unable to wrap the blob successfully due to
+     * retry-able errors.
      */
     @NonNull
     public abstract byte[] onWrap(@NonNull byte[] blob, @DurationMillisLong long lifeTimeInMillis)
@@ -106,12 +109,13 @@
      * operation would happen after reboot during direct boot mode (i.e before device is unlocked
      * for the first time). The implementation should unwrap the wrapped blob in a reasonable time
      * and returns the result or throw {@link IOException} if it's unable to complete the action
-     * and {@link IllegalArgumentException} if {@code unwrapBlob} fails because the wrappedBlob is
-     * stale.
+     * due to retry-able errors (e.g network error) and {@link IllegalArgumentException}
+     * if {@code unwrapBlob} fails due to fatal errors (e.g stale or corrupted blob).
      *
      * @param wrappedBlob The wrapped blob with size on the order of 100 bytes.
      * @return Unwrapped blob used for resume-on-reboot with the size on the order of 100 bytes.
-     * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully.
+     * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully
+     * due to retry-able errors.
      */
     @NonNull
     public abstract byte[] onUnwrap(@NonNull byte[] wrappedBlob) throws IOException;
diff --git a/core/java/android/service/wallpaper/Android.bp b/core/java/android/service/wallpaper/Android.bp
index ffbdb03..a527d3d 100644
--- a/core/java/android/service/wallpaper/Android.bp
+++ b/core/java/android/service/wallpaper/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_library {
 
     name: "WallpaperSharedLib",
diff --git a/core/java/android/tracing/ITracingServiceProxy.aidl b/core/java/android/tracing/ITracingServiceProxy.aidl
new file mode 100644
index 0000000..4520db3
--- /dev/null
+++ b/core/java/android/tracing/ITracingServiceProxy.aidl
@@ -0,0 +1,32 @@
+/**
+ * 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.tracing;
+
+/**
+ * Binder interface for the TracingServiceProxy running in system_server.
+ *
+ * {@hide}
+ */
+interface ITracingServiceProxy
+{
+    /**
+     * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+     * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+     * there is no buffer available to dump.
+     */
+    oneway void notifyTraceSessionEnded(boolean sessionStolen);
+}
diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS
new file mode 100644
index 0000000..f5de4eb
--- /dev/null
+++ b/core/java/android/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/core/java/android/uwb/OWNERS b/core/java/android/uwb/OWNERS
index ea41c39..17936ae 100644
--- a/core/java/android/uwb/OWNERS
+++ b/core/java/android/uwb/OWNERS
@@ -1,5 +1,6 @@
 bstack@google.com
 eliptus@google.com
 jsolnit@google.com
+matbev@google.com
 siyuanh@google.com
 zachoverflow@google.com
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index 5ac95d4..c0d8187 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -94,7 +94,8 @@
         synchronized (this) {
             if (!hasSession(sessionHandle)) {
                 Log.w(TAG,
-                        "onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
+                        "onRangingOpenedFailed - received unexpected SessionHandle: "
+                                + sessionHandle);
                 return;
             }
 
@@ -124,7 +125,7 @@
             @RangingChangeReason int reason, PersistableBundle params) {
         synchronized (this) {
             if (!hasSession(sessionHandle)) {
-                Log.w(TAG, "onRangingStartFailed - received unexpected SessionHandle: "
+                Log.w(TAG, "onRangingReconfigureFailed - received unexpected SessionHandle: "
                         + sessionHandle);
                 return;
             }
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index bfa8bf2..52ec5bd 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -16,8 +16,10 @@
 
 package android.uwb;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.PersistableBundle;
@@ -247,6 +249,7 @@
      *
      * @param params configuration parameters for starting the session
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void start(@NonNull PersistableBundle params) {
         if (mState != State.IDLE) {
             throw new IllegalStateException();
@@ -271,6 +274,7 @@
      *
      * @param params the parameters to reconfigure and their new values
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void reconfigure(@NonNull PersistableBundle params) {
         if (mState != State.ACTIVE && mState != State.IDLE) {
             throw new IllegalStateException();
@@ -302,6 +306,7 @@
      * <p>On failure to stop the session,
      * {@link RangingSession.Callback#onStopFailed(int, PersistableBundle)} is invoked.
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void stop() {
         if (mState != State.ACTIVE) {
             throw new IllegalStateException();
@@ -333,6 +338,7 @@
      * {@link #close()}, even if the {@link RangingSession} is already closed.
      */
     @Override
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void close() {
         if (mState == State.CLOSED) {
             mExecutor.execute(() -> mCallback.onClosed(
diff --git a/core/java/android/uwb/SessionHandle.java b/core/java/android/uwb/SessionHandle.java
index 928fcbdc..b23f5ad 100644
--- a/core/java/android/uwb/SessionHandle.java
+++ b/core/java/android/uwb/SessionHandle.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * @hide
  */
@@ -73,6 +75,11 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hashCode(mId);
+    }
+
+    @Override
     public String toString() {
         return "SessionHandle [id=" + mId + "]";
     }
diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING
index 9e50bd6..08ed2c7 100644
--- a/core/java/android/uwb/TEST_MAPPING
+++ b/core/java/android/uwb/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "UwbManagerTests"
+    },
+    {
+      "name": "CtsUwbTestCases"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 8adfe06..2dc0ba0 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -16,9 +16,11 @@
 
 package android.uwb;
 
+import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -154,6 +156,7 @@
      * @param executor an {@link Executor} to execute given callback
      * @param callback user implementation of the {@link AdapterStateCallback}
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull AdapterStateCallback callback) {
         mAdapterStateListener.register(executor, callback);
@@ -168,6 +171,7 @@
      *
      * @param callback user implementation of the {@link AdapterStateCallback}
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
         mAdapterStateListener.unregister(callback);
     }
@@ -181,6 +185,7 @@
      * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
      */
     @NonNull
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public PersistableBundle getSpecificationInfo() {
         try {
             return mUwbAdapter.getSpecificationInfo();
@@ -194,6 +199,7 @@
      *
      * @return true if ranging is supported
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public boolean isRangingSupported() {
         try {
             return mUwbAdapter.isRangingSupported();
@@ -250,6 +256,7 @@
      * @return angle of arrival type supported
      */
     @AngleOfArrivalSupportType
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public int getAngleOfArrivalSupport() {
         try {
             switch (mUwbAdapter.getAngleOfArrivalSupport()) {
@@ -281,6 +288,7 @@
      * @return {@link List} of supported channel numbers ordered by preference
      */
     @NonNull
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public List<Integer> getSupportedChannelNumbers() {
         List<Integer> channels = new ArrayList<>();
         try {
@@ -300,6 +308,7 @@
      * @return {@link List} of supported preamble code indices
      */
     @NonNull
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public Set<Integer> getSupportedPreambleCodeIndices() {
         Set<Integer> preambles = new HashSet<>();
         try {
@@ -320,6 +329,7 @@
      * @return the timestamp resolution in nanoseconds
      */
     @SuppressLint("MethodNameUnits")
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public long elapsedRealtimeResolutionNanos() {
         try {
             return mUwbAdapter.getTimestampResolutionNanos();
@@ -333,6 +343,7 @@
      *
      * @return the maximum allowed number of simultaneously open {@link RangingSession} instances.
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public int getMaxSimultaneousSessions() {
         try {
             return mUwbAdapter.getMaxSimultaneousSessions();
@@ -347,6 +358,7 @@
      *
      * @return the maximum number of remote devices per {@link RangingSession}
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public int getMaxRemoteDevicesPerInitiatorSession() {
         try {
             return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession();
@@ -361,6 +373,7 @@
      *
      * @return the maximum number of remote devices per {@link RangingSession}
      */
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public int getMaxRemoteDevicesPerResponderSession() {
         try {
             return mUwbAdapter.getMaxRemoteDevicesPerResponderSession();
@@ -396,6 +409,7 @@
      *         {@link RangingSession.Callback#onOpened(RangingSession)}.
      */
     @NonNull
+    @RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
     public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull RangingSession.Callback callbacks) {
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index f8500fa..6511a94 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -149,7 +149,7 @@
      * <p>
      * The time value that was used in all the vsync listeners and drawing for
      * the frame (Choreographer frame callbacks, animations,
-     * {@link View#getDrawingTime()}, etc…)
+     * {@link View#getDrawingTime()}, etc.)
      * </p>
      */
     public static final int VSYNC_TIMESTAMP = 11;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c5ca886..8810814 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1911,7 +1911,10 @@
         if (client == null) {
             return;
         }
-
+        if (mService == null) {
+            Log.w(TAG, "Autofill service is null!");
+            return;
+        }
         if (mServiceClient == null) {
             mServiceClient = new AutofillManagerClient(this);
             try {
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 1c703ec..a17c012 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -82,6 +82,7 @@
     public static InlineSuggestionInfo newInlineSuggestionInfo(
             @NonNull InlinePresentationSpec presentationSpec,
             @NonNull @Source String source,
+            @SuppressLint("NullableCollection")
             @Nullable String[] autofillHints, @NonNull @Type String type, boolean isPinned) {
         return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned);
     }
diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS
index e6a04da..d7db7c7 100644
--- a/core/java/android/view/inputmethod/OWNERS
+++ b/core/java/android/view/inputmethod/OWNERS
@@ -2,3 +2,5 @@
 set noparent
 
 include /services/core/java/com/android/server/inputmethod/OWNERS
+
+per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 502680d..7b4fcbf 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.os.RemoteException;
@@ -101,6 +102,7 @@
     /** Gets direct child tasks (ordered from top-to-bottom) */
     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
     @Nullable
+    @SuppressLint("NullableCollection")
     public static List<ActivityManager.RunningTaskInfo> getChildTasks(
             @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) {
         try {
@@ -113,6 +115,7 @@
     /** Gets all root tasks on a display (ordered from top-to-bottom) */
     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
     @Nullable
+    @SuppressLint("NullableCollection")
     public static List<ActivityManager.RunningTaskInfo> getRootTasks(
             int displayId, @NonNull int[] activityTypes) {
         try {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 16991b4..1270185 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1210,25 +1210,6 @@
                         if (TextUtils.isEmpty(packageName)) {
                             pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
                         }
-                    } else {
-                        // Update Domain Verification status
-                        ComponentName cn = intent.getComponent();
-                        String packageName = cn.getPackageName();
-                        String dataScheme = (data != null) ? data.getScheme() : null;
-
-                        boolean isHttpOrHttps = (dataScheme != null) &&
-                                (dataScheme.equals(IntentFilter.SCHEME_HTTP) ||
-                                        dataScheme.equals(IntentFilter.SCHEME_HTTPS));
-
-                        boolean isViewAction = (action != null) && action.equals(Intent.ACTION_VIEW);
-                        boolean hasCategoryBrowsable = (categories != null) &&
-                                categories.contains(Intent.CATEGORY_BROWSABLE);
-
-                        if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
-                            pm.updateIntentVerificationStatusAsUser(packageName,
-                                    PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
-                                    userId);
-                        }
                     }
                 } else {
                     try {
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl
similarity index 80%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl
index 46bc4ab..5d02a29 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package com.android.internal.compat;
 
-parcelable ApnThrottleStatus;
+parcelable CompatibilityOverrideConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
new file mode 100644
index 0000000..1c222a7
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.android.internal.compat;
+
+
+import android.app.compat.PackageOverride;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config overrides for a given application.
+ * @hide
+ */
+public final class CompatibilityOverrideConfig implements Parcelable {
+    public final Map<Long, PackageOverride> overrides;
+
+    public CompatibilityOverrideConfig(Map<Long, PackageOverride> overrides) {
+        this.overrides = overrides;
+    }
+
+    private CompatibilityOverrideConfig(Parcel in) {
+        int keyCount = in.readInt();
+        overrides = new HashMap<>();
+        for (int i = 0; i < keyCount; i++) {
+            long key = in.readLong();
+            PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader());
+            overrides.put(key, override);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(overrides.size());
+        for (Long key : overrides.keySet()) {
+            dest.writeLong(key);
+            dest.writeParcelable(overrides.get(key), 0);
+        }
+    }
+
+    public static final Creator<CompatibilityOverrideConfig> CREATOR =
+            new Creator<CompatibilityOverrideConfig>() {
+
+                @Override
+                public CompatibilityOverrideConfig createFromParcel(Parcel in) {
+                    return new CompatibilityOverrideConfig(in);
+                }
+
+                @Override
+                public CompatibilityOverrideConfig[] newArray(int size) {
+                    return new CompatibilityOverrideConfig[size];
+                }
+            };
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index a5eb5f6..60213e4 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -21,6 +21,7 @@
 import java.util.Map;
 
 parcelable CompatibilityChangeConfig;
+parcelable CompatibilityOverrideConfig;
 parcelable CompatibilityChangeInfo;
 /**
  * Platform private API for talking with the PlatformCompat service.
@@ -152,6 +153,17 @@
     /**
      * Adds overrides to compatibility changes.
      *
+     * <p>Kills the app to allow the changes to take effect.
+     *
+     * @param overrides   parcelable containing the compat change overrides to be applied
+     * @param packageName the package name of the app whose changes will be overridden
+     * @throws SecurityException if overriding changes is not permitted
+     */
+    void setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName);
+
+    /**
+     * Adds overrides to compatibility changes.
+     *
      * <p>Does not kill the app, to be only used in tests.
      *
      * @param overrides   parcelable containing the compat change overrides to be applied
diff --git a/core/java/com/android/internal/graphics/palette/OWNERS b/core/java/com/android/internal/graphics/palette/OWNERS
new file mode 100644
index 0000000..731dca9
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 484670

+dupin@google.com

+jamesoleary@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/os/CPU_OWNERS b/core/java/com/android/internal/os/CPU_OWNERS
new file mode 100644
index 0000000..5d3473c
--- /dev/null
+++ b/core/java/com/android/internal/os/CPU_OWNERS
@@ -0,0 +1,3 @@
+connoro@google.com
+dplotnikov@google.com
+rslawik@google.com  # Android Telemetry
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 1b07aa0..0aa54f5 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,5 +1,6 @@
 per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
 per-file *Zygote* = file:/ZYGOTE_OWNERS
+per-file *Cpu* = file:CPU_OWNERS
 
 # BatteryStats
 per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 0381a75..65beb93 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -103,7 +103,7 @@
      */
     public static final int PROFILE_FROM_SHELL = 1 << 15;
 
-    /*
+    /**
      * Enable using the ART app image startup cache
      */
     public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
@@ -116,13 +116,6 @@
      */
     public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
 
-    /**
-     * Disable runtime access to {@link android.annotation.TestApi} annotated members.
-     *
-     * <p>This only takes effect if Hidden API access restrictions are enabled as well.
-     */
-    public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
-
     public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
     /**
      * Enable pointer tagging in this process.
@@ -597,7 +590,7 @@
     static Runnable forkUsap(LocalServerSocket usapPoolSocket,
                              int[] sessionSocketRawFDs,
                              boolean isPriorityFork) {
-        FileDescriptor[] pipeFDs = null;
+        FileDescriptor[] pipeFDs;
 
         try {
             pipeFDs = Os.pipe2(O_CLOEXEC);
@@ -1103,4 +1096,11 @@
      * fully-feature Memory Tagging, rather than the static Tagged Pointers.
      */
     public static native boolean nativeSupportsTaggedPointers();
+
+    /**
+     * Returns the current native tagging level, as one of the
+     * MEMORY_TAG_LEVEL_* constants. Returns zero if no tagging is present, or
+     * we failed to determine the level.
+     */
+    public static native int nativeCurrentTaggingLevel();
 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 6573e42..5a576ebb 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -505,8 +505,8 @@
                         parsedArgs.mDisabledCompatChanges,
                         parsedArgs.mRemainingArgs, null /* classLoader */);
             } else {
-                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
-                        parsedArgs.mRemainingArgs, null /* classLoader */);
+                return ZygoteInit.childZygoteInit(
+                        parsedArgs.mRemainingArgs  /* classLoader */);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 6335baa..ef1c50f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -117,7 +117,7 @@
     /**
      * Controls whether we should preload resources during zygote init.
      */
-    public static final boolean PRELOAD_RESOURCES = true;
+    private static final boolean PRELOAD_RESOURCES = true;
 
     private static final int UNPRIVILEGED_UID = 9999;
     private static final int UNPRIVILEGED_GID = 9999;
@@ -159,7 +159,7 @@
         sPreloadComplete = true;
     }
 
-    public static void lazyPreload() {
+    static void lazyPreload() {
         Preconditions.checkState(!sPreloadComplete);
         Log.i(TAG, "Lazily preloading resources.");
 
@@ -364,7 +364,7 @@
             }
             if ("true".equals(prop)) {
                 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ResetJitCounters");
-                runtime.resetJitCounters();
+                VMRuntime.resetJitCounters();
                 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
             }
 
@@ -418,8 +418,6 @@
      * larger.
      */
     private static void preloadResources() {
-        final VMRuntime runtime = VMRuntime.getRuntime();
-
         try {
             mResources = Resources.getSystem();
             mResources.startPreloading();
@@ -463,9 +461,7 @@
         int N = ar.length();
         for (int i = 0; i < N; i++) {
             int id = ar.getResourceId(i, 0);
-            if (false) {
-                Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
-            }
+
             if (id != 0) {
                 if (mResources.getColorStateList(id, null) == null) {
                     throw new IllegalArgumentException(
@@ -483,9 +479,7 @@
         int N = ar.length();
         for (int i = 0; i < N; i++) {
             int id = ar.getResourceId(i, 0);
-            if (false) {
-                Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
-            }
+
             if (id != 0) {
                 if (mResources.getDrawable(id, null) == null) {
                     throw new IllegalArgumentException(
@@ -688,13 +682,12 @@
                 final String packageName = "*";
                 final String outputPath = null;
                 final int dexFlags = 0;
-                final String compilerFilter = systemServerFilter;
                 final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
                 final String seInfo = null;
                 final int targetSdkVersion = 0;  // SystemServer targets the system's SDK version
                 try {
                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
-                            instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
+                            instructionSet, dexoptNeeded, outputPath, dexFlags, systemServerFilter,
                             uuid, classLoaderContext, seInfo, false /* downgrade */,
                             targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
                             "server-dexopt");
@@ -770,7 +763,7 @@
         capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
 
         /* Hardcoded command line to start the system server */
-        String args[] = {
+        String[] args = {
                 "--setuid=1000",
                 "--setgid=1000",
                 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
@@ -781,7 +774,7 @@
                 "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                 "com.android.server.SystemServer",
         };
-        ZygoteArguments parsedArgs = null;
+        ZygoteArguments parsedArgs;
 
         int pid;
 
@@ -791,9 +784,19 @@
             Zygote.applyInvokeWithSystemProperty(parsedArgs);
 
             if (Zygote.nativeSupportsMemoryTagging()) {
-                /* The system server is more privileged than regular app processes, so it has async
-                 * tag checks enabled on hardware that supports memory tagging. */
-                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+                /* The system server has ASYNC MTE by default, in order to allow
+                 * system services to specify their own MTE level later, as you
+                 * can't re-enable MTE once it's disabled. */
+                String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
+                if (mode.equals("async")) {
+                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+                } else if (mode.equals("sync")) {
+                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
+                } else if (!mode.equals("off")) {
+                    /* When we have an invalid memory tag level, keep the current level. */
+                    parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
+                    Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
+                }
             } else if (Zygote.nativeSupportsTaggedPointers()) {
                 /* Enable pointer tagging in the system server. Hardware support for this is present
                  * in all ARMv8 CPUs. */
@@ -860,7 +863,7 @@
      * @param argv  Command line arguments used to specify the Zygote's configuration.
      */
     @UnsupportedAppUsage
-    public static void main(String argv[]) {
+    public static void main(String[] argv) {
         ZygoteServer zygoteServer = null;
 
         // Mark zygote start. This ensures that thread creation will throw
@@ -1019,7 +1022,7 @@
      *                              are enabled)
      * @param argv             arg strings
      */
-    public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
+    public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
             String[] argv, ClassLoader classLoader) {
         if (RuntimeInit.DEBUG) {
             Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
@@ -1039,11 +1042,10 @@
      * to zygoteInit(), which skips calling into initialization routines that start the Binder
      * threadpool.
      */
-    static final Runnable childZygoteInit(
-            int targetSdkVersion, String[] argv, ClassLoader classLoader) {
+    static Runnable childZygoteInit(String[] argv) {
         RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
-        return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
+        return RuntimeInit.findStaticMain(args.startClass, args.startArgs, /* classLoader= */null);
     }
 
-    private static final native void nativeZygoteInit();
+    private static native void nativeZygoteInit();
 }
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 0dd8b59..585ddf6 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -411,7 +411,7 @@
         }
     }
 
-    void resetUsapRefillState() {
+    private void resetUsapRefillState() {
         mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
         mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
     }
@@ -492,10 +492,12 @@
                 long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;
 
                 if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
-                    // Normalize the poll timeout value when the time between one poll event and the
-                    // next pushes us over the delay value.  This prevents poll receiving a 0
-                    // timeout value, which would result in it returning immediately.
-                    pollTimeoutMs = -1;
+                    // The refill delay has elapsed during the period between poll invocations.
+                    // We will now check for any currently ready file descriptors before refilling
+                    // the USAP pool.
+                    pollTimeoutMs = 0;
+                    mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
+                    mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
 
                 } else if (elapsedTimeMs <= 0) {
                     // This can occur if the clock used by currentTimeMillis is reset, which is
@@ -517,9 +519,11 @@
             }
 
             if (pollReturnValue == 0) {
-                // The poll timeout has been exceeded.  This only occurs when we have finished the
-                // USAP pool refill delay period.
-
+                // The poll returned zero results either when the timeout value has been exceeded
+                // or when a non-blocking poll is issued and no FDs are ready.  In either case it
+                // is time to refill the pool.  This will result in a duplicate assignment when
+                // the non-blocking poll returns zero results, but it avoids an additional
+                // conditional in the else branch.
                 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                 mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
 
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index ae566c3..d284d51 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -5,3 +5,17 @@
 per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
 per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
 per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS
+
+# Notification related
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Messaging* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Message* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Conversation* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *People* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ImageResolver* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file CallLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file CachingIconView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ImageFloatingTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ac2361d..dd40fbc 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -23,7 +23,6 @@
 import android.os.Build;
 import android.os.DropBoxManager;
 import android.os.Environment;
-import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.RecoverySystem;
 import android.os.RemoteException;
@@ -75,8 +74,8 @@
         SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536;
     private static final int GMSCORE_LASTK_LOG_SIZE = 196608;
 
-    private static final File TOMBSTONE_DIR = new File("/data/tombstones");
     private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE";
+    private static final String TAG_TOMBSTONE_PROTO = "SYSTEM_TOMBSTONE_PROTO";
 
     // The pre-froyo package and class of the system updater, which
     // ran in the system process.  We need to remove its packages here
@@ -86,9 +85,6 @@
     private static final String OLD_UPDATER_CLASS =
         "com.google.android.systemupdater.SystemUpdateReceiver";
 
-    // Keep a reference to the observer so the finalizer doesn't disable it.
-    private static FileObserver sTombstoneObserver = null;
-
     private static final String LOG_FILES_FILE = "log-files.xml";
     private static final AtomicFile sFile = new AtomicFile(new File(
             Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files");
@@ -154,7 +150,7 @@
         Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
     }
 
-    private String getPreviousBootHeaders() {
+    private static String getPreviousBootHeaders() {
         try {
             return FileUtils.readTextFile(lastHeaderFile, 0, null);
         } catch (IOException e) {
@@ -162,7 +158,7 @@
         }
     }
 
-    private String getCurrentBootHeaders() throws IOException {
+    private static String getCurrentBootHeaders() throws IOException {
         return new StringBuilder(512)
             .append("Build: ").append(Build.FINGERPRINT).append("\n")
             .append("Hardware: ").append(Build.BOARD).append("\n")
@@ -176,7 +172,7 @@
     }
 
 
-    private String getBootHeadersToLogAndUpdate() throws IOException {
+    private static String getBootHeadersToLogAndUpdate() throws IOException {
         final String oldHeaders = getPreviousBootHeaders();
         final String newHeaders = getCurrentBootHeaders();
 
@@ -248,38 +244,27 @@
         logFsMountTime();
         addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
         logSystemServerShutdownTimeMetrics();
-
-        // Scan existing tombstones (in case any new ones appeared)
-        File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
-        for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
-            if (tombstoneFiles[i].isFile()) {
-                addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
-                        LOG_SIZE, "SYSTEM_TOMBSTONE");
-            }
-        }
-
         writeTimestamps(timestamps);
+    }
 
-        // Start watching for new tombstone files; will record them as they occur.
-        // This gets registered with the singleton file observer thread.
-        sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) {
-            @Override
-            public void onEvent(int event, String path) {
-                HashMap<String, Long> timestamps = readTimestamps();
-                try {
-                    File file = new File(TOMBSTONE_DIR, path);
-                    if (file.isFile() && file.getName().startsWith("tombstone_")) {
-                        addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
-                                TAG_TOMBSTONE);
-                    }
-                } catch (IOException e) {
-                    Slog.e(TAG, "Can't log tombstone", e);
-                }
-                writeTimestamps(timestamps);
-            }
-        };
-
-        sTombstoneObserver.startWatching();
+    /**
+     * Add a tombstone to the DropBox.
+     *
+     * @param ctx Context
+     * @param tombstone path to the tombstone
+     */
+    public static void addTombstoneToDropBox(Context ctx, File tombstone, boolean proto) {
+        final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
+        final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
+        HashMap<String, Long> timestamps = readTimestamps();
+        try {
+            final String headers = getBootHeadersToLogAndUpdate();
+            addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE,
+                    proto ? TAG_TOMBSTONE_PROTO : TAG_TOMBSTONE);
+        } catch (IOException e) {
+            Slog.e(TAG, "Can't log tombstone", e);
+        }
+        writeTimestamps(timestamps);
     }
 
     private static void addLastkToDropBox(
@@ -764,7 +749,7 @@
         }
     }
 
-    private void writeTimestamps(HashMap<String, Long> timestamps) {
+    private static void writeTimestamps(HashMap<String, Long> timestamps) {
         synchronized (sFile) {
             final FileOutputStream stream;
             try {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 79a0dfd..0d05a6b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,4 +1,21 @@
 
+package {
+    default_applicable_licenses: ["frameworks_base_core_jni_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_core_jni_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_shared {
     name: "libandroid_runtime",
     host_supported: true,
@@ -50,11 +67,12 @@
         "libhwui",
         "liblog",
         "libminikin",
-        "libnativehelper",
         "libz",
         "libziparchive",
     ],
 
+    static_libs: ["libnativehelper_lazy"],
+
     export_include_dirs: [
         ".",
         "include",
@@ -206,6 +224,7 @@
             ],
 
             shared_libs: [
+                "android.hardware.memtrack-V1-ndk_platform",
                 "libandroidicu",
                 "libbpf_android",
                 "libnetdbpf",
@@ -266,12 +285,13 @@
                 "libstatspull",
             ],
             export_shared_lib_headers: [
-                // AndroidRuntime.h depends on nativehelper/jni.h
-                "libnativehelper",
-
                 // our headers include libnativewindow's public headers
                 "libnativewindow",
             ],
+            export_static_lib_headers: [
+                // AndroidRuntime.h depends on nativehelper/jni.h
+                "libnativehelper_lazy",
+            ],
             header_libs: [
                 "bionic_libc_platform_headers",
                 "dnsproxyd_protocol_headers",
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 2279d57..35d1d7b 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -5,6 +5,9 @@
 # Connectivity
 per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
 
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
+
 # Display
 per-file android_hardware_display_* = file:/services/core/java/com/android/server/display/OWNERS
 
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 28fc8ed..0e3db46 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,6 +33,7 @@
 #include <string>
 #include <vector>
 
+#include <aidl/android/hardware/memtrack/DeviceInfo.h>
 #include <android-base/logging.h>
 #include <bionic/malloc.h>
 #include <debuggerd/client.h>
@@ -43,7 +44,9 @@
 #include <nativehelper/JNIPlatformHelp.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "jni.h"
+#include <dmabufinfo/dmabuf_sysfs_stats.h>
 #include <dmabufinfo/dmabufinfo.h>
+#include <dmabufinfo/dmabuf_sysfs_stats.h>
 #include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <memtrack/memtrack.h>
@@ -519,14 +522,15 @@
     }
 
     if (outUssSwapPssRss != NULL) {
-        if (env->GetArrayLength(outUssSwapPssRss) >= 1) {
+        int outLen = env->GetArrayLength(outUssSwapPssRss);
+        if (outLen >= 1) {
             jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
             if (outUssSwapPssRssArray != NULL) {
                 outUssSwapPssRssArray[0] = uss;
-                if (env->GetArrayLength(outUssSwapPssRss) >= 2) {
+                if (outLen >= 2) {
                     outUssSwapPssRssArray[1] = swapPss;
                 }
-                if (env->GetArrayLength(outUssSwapPssRss) >= 3) {
+                if (outLen >= 3) {
                     outUssSwapPssRssArray[2] = rss;
                 }
             }
@@ -535,10 +539,20 @@
     }
 
     if (outMemtrack != NULL) {
-        if (env->GetArrayLength(outMemtrack) >= 1) {
+        int outLen = env->GetArrayLength(outMemtrack);
+        if (outLen >= 1) {
             jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
             if (outMemtrackArray != NULL) {
                 outMemtrackArray[0] = memtrack;
+                if (outLen >= 2) {
+                    outMemtrackArray[1] = graphics_mem.graphics;
+                }
+                if (outLen >= 3) {
+                    outMemtrackArray[2] = graphics_mem.gl;
+                }
+                if (outLen >= 4) {
+                    outMemtrackArray[3] = graphics_mem.other;
+                }
             }
             env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
         }
@@ -802,6 +816,26 @@
     return heapsSizeKb;
 }
 
+static jlong android_os_Debug_getDmabufTotalExportedKb(JNIEnv* env, jobject clazz) {
+    jlong dmabufTotalSizeKb = -1;
+    uint64_t size;
+
+    if (dmabufinfo::GetDmabufTotalExportedKb(&size)) {
+        dmabufTotalSizeKb = size;
+    }
+    return dmabufTotalSizeKb;
+}
+
+static jlong android_os_Debug_getDmabufHeapTotalExportedKb(JNIEnv* env, jobject clazz) {
+    jlong dmabufHeapTotalSizeKb = -1;
+    uint64_t size;
+
+    if (meminfo::ReadDmabufHeapTotalExportedKb(&size)) {
+        dmabufHeapTotalSizeKb = size;
+    }
+    return dmabufHeapTotalSizeKb;
+}
+
 static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
     jlong poolsSizeKb = -1;
     uint64_t size;
@@ -813,8 +847,44 @@
     return poolsSizeKb;
 }
 
-static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) {
-    jlong ionPss = 0;
+static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject clazz) {
+    jlong poolsSizeKb = -1;
+    uint64_t size;
+
+    if (meminfo::ReadDmabufHeapPoolsSizeKb(&size)) {
+        poolsSizeKb = size;
+    }
+
+    return poolsSizeKb;
+}
+
+static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) {
+    std::vector<aidl::android::hardware::memtrack::DeviceInfo> gpu_device_info;
+    if (!memtrack_gpu_device_info(&gpu_device_info)) {
+        return -1;
+    }
+
+    dmabufinfo::DmabufSysfsStats stats;
+    if (!GetDmabufSysfsStats(&stats)) {
+        return -1;
+    }
+
+    jlong sizeKb = 0;
+    const auto& importer_stats = stats.importer_info();
+    for (const auto& dev_info : gpu_device_info) {
+        const auto& importer_info = importer_stats.find(dev_info.name);
+        if (importer_info == importer_stats.end()) {
+            continue;
+        }
+
+        sizeKb += importer_info->second.size;
+    }
+
+    return sizeKb;
+}
+
+static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
+    jlong dmabufPss = 0;
     std::vector<dmabufinfo::DmaBuffer> dmabufs;
 
     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
@@ -838,10 +908,10 @@
     }
 
     for (const dmabufinfo::DmaBuffer& buf : dmabufs) {
-        ionPss += buf.size() / 1024;
+        dmabufPss += buf.size() / 1024;
     }
 
-    return ionPss;
+    return dmabufPss;
 }
 
 static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
@@ -919,10 +989,18 @@
             (void*)android_os_Debug_getFreeZramKb },
     { "getIonHeapsSizeKb", "()J",
             (void*)android_os_Debug_getIonHeapsSizeKb },
+    { "getDmabufTotalExportedKb", "()J",
+            (void*)android_os_Debug_getDmabufTotalExportedKb },
+    { "getGpuDmaBufUsageKb", "()J",
+            (void*)android_os_Debug_getGpuDmaBufUsageKb },
+    { "getDmabufHeapTotalExportedKb", "()J",
+            (void*)android_os_Debug_getDmabufHeapTotalExportedKb },
     { "getIonPoolsSizeKb", "()J",
             (void*)android_os_Debug_getIonPoolsSizeKb },
-    { "getIonMappedSizeKb", "()J",
-            (void*)android_os_Debug_getIonMappedSizeKb },
+    { "getDmabufMappedSizeKb", "()J",
+            (void*)android_os_Debug_getDmabufMappedSizeKb },
+    { "getDmabufHeapPoolsSizeKb", "()J",
+            (void*)android_os_Debug_getDmabufHeapPoolsSizeKb },
     { "getGpuTotalUsageKb", "()J",
             (void*)android_os_Debug_getGpuTotalUsageKb },
     { "isVmapStack", "()Z",
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 241570a..0fdab72 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -36,6 +36,7 @@
 #include <utils/List.h>
 #include <utils/KeyedVector.h>
 #include <binder/Parcel.h>
+#include <binder/ParcelRef.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <utils/threads.h>
@@ -529,8 +530,9 @@
 
 static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
 {
-    Parcel* parcel = new Parcel();
-    return reinterpret_cast<jlong>(parcel);
+    sp<ParcelRef> parcelRef = ParcelRef::create();
+    parcelRef->incStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
+    return reinterpret_cast<jlong>(static_cast<Parcel *>(parcelRef.get()));
 }
 
 static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -545,8 +547,8 @@
 
 static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
 {
-    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
-    delete parcel;
+    ParcelRef* derivative = static_cast<ParcelRef*>(reinterpret_cast<Parcel*>(nativePtr));
+    derivative->decStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
 }
 
 static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 0f7611a..f67007c 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -83,7 +83,7 @@
 }
 
 static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) {
-    atrace_set_debuggable(allowed);
+    atrace_update_tags();
 }
 
 static void android_os_Trace_nativeSetTracingEnabled(JNIEnv*, jclass, jboolean enabled) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 581dc08..f71b42c 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -35,6 +35,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
+#include <binder/ParcelRef.h>
 #include <binder/ProcessState.h>
 #include <binder/Stability.h>
 #include <binderthreadstate/CallerUtils.h>
@@ -1374,7 +1375,8 @@
 }
 
 static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
-        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
+        jint code, jobject dataObj, jobject replyObj, jboolean replyObjOwnsNativeParcel,
+        jint flags) // throws RemoteException
 {
     if (dataObj == NULL) {
         jniThrowNullPointerException(env, NULL);
@@ -1416,6 +1418,21 @@
     status_t err = target->transact(code, *data, reply, flags);
     //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
 
+    if (reply) {
+        if (replyObjOwnsNativeParcel) {
+            // as per Parcel java class constructor, here, "reply" MUST be a "ParcelRef"
+            // only for Parcel that contained Binder objects
+            if (reply->objectsCount() > 0) {
+                IPCThreadState::self()->createTransactionReference(static_cast<ParcelRef*>(reply));
+            }
+        } else {
+            // as per Parcel.java, if Parcel java object NOT owning native Parcel object, it will
+            // NOT destroy the native Parcel object upon GC(finalize()), so, there will be no race
+            // condtion in this case. Please refer to the java class methods: Parcel.finalize(),
+            // Parcel.destroy().
+        }
+    }
+
     if (kEnableBinderSample) {
         if (time_binder_calls) {
             conditionally_log_binder_call(start_millis, target, code);
@@ -1542,7 +1559,7 @@
     {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
     {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
     {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
-    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
+    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;ZI)Z", (void*)android_os_BinderProxy_transact},
     {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
     {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
     {"getNativeFinalizer",  "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d7001d8..903ecae 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -2526,6 +2526,36 @@
 #endif
 }
 
+static jint com_android_internal_os_Zygote_nativeCurrentTaggingLevel(JNIEnv* env, jclass) {
+#if defined(__aarch64__)
+  int level = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+  if (level < 0) {
+    ALOGE("Failed to get memory tag level: %s", strerror(errno));
+    return 0;
+  } else if (!(level & PR_TAGGED_ADDR_ENABLE)) {
+    return 0;
+  }
+  // TBI is only possible on non-MTE hardware.
+  if (!mte_supported()) {
+    return MEMORY_TAG_LEVEL_TBI;
+  }
+
+  switch (level & PR_MTE_TCF_MASK) {
+    case PR_MTE_TCF_NONE:
+      return 0;
+    case PR_MTE_TCF_SYNC:
+      return MEMORY_TAG_LEVEL_SYNC;
+    case PR_MTE_TCF_ASYNC:
+      return MEMORY_TAG_LEVEL_ASYNC;
+    default:
+      ALOGE("Unknown memory tagging level: %i", level);
+      return 0;
+  }
+#else // defined(__aarch64__)
+  return 0;
+#endif // defined(__aarch64__)
+}
+
 static const JNINativeMethod gMethods[] = {
         {"nativeForkAndSpecialize",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
@@ -2565,6 +2595,8 @@
          (void*)com_android_internal_os_Zygote_nativeSupportsMemoryTagging},
         {"nativeSupportsTaggedPointers", "()Z",
          (void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers},
+        {"nativeCurrentTaggingLevel", "()I",
+         (void*)com_android_internal_os_Zygote_nativeCurrentTaggingLevel},
 };
 
 int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 748b4b4..99fd215 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -16,6 +16,7 @@
 jjaggi@google.com
 roosa@google.com
 per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
+per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
 
 # Biometrics
 kchyn@google.com
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index 6794c8c..0041f19 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -63,6 +63,9 @@
         // higher-scoring network will not go into the background immediately,
         // but will linger and go into the background after the linger timeout.
         TYPE_BACKGROUND_REQUEST = 5;
+        // Like TRACK_DEFAULT, but tracks the system default network, instead of
+        // the default network of the calling application.
+        TYPE_TRACK_SYSTEM_DEFAULT = 6;
     }
     // The type of the request. This is only used by the system and is always
     // NONE elsewhere.
diff --git a/core/proto/android/server/apphibernationservice.proto b/core/proto/android/server/apphibernationservice.proto
new file mode 100644
index 0000000..d341c4b
--- /dev/null
+++ b/core/proto/android/server/apphibernationservice.proto
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package com.android.server.apphibernation;
+
+option java_multiple_files = true;
+
+// Proto for hibernation states for all packages for a user.
+message UserLevelHibernationStatesProto {
+  repeated UserLevelHibernationStateProto hibernation_state = 1;
+}
+
+// Proto for com.android.server.apphibernation.UserLevelState.
+message UserLevelHibernationStateProto {
+  optional string package_name = 1;
+  optional bool hibernated = 2;
+}
+
+// Proto for global hibernation states for all packages.
+message GlobalLevelHibernationStatesProto {
+  repeated GlobalLevelHibernationStateProto hibernation_state = 1;
+}
+
+// Proto for com.android.server.apphibernation.GlobalLevelState
+message GlobalLevelHibernationStateProto {
+  optional string package_name = 1;
+  optional bool hibernated = 2;
+}
\ No newline at end of file
diff --git a/core/res/Android.bp b/core/res/Android.bp
index f94a2b0..4c05cd6 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -14,6 +14,36 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_core_res_license"],
+}
+
+// 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_core_res_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-GPL",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "framework-res",
     sdk_version: "core_platform",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0e80c7b..d1e6111 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1790,6 +1790,12 @@
     <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to manage an automotive device's application network
+         preference as it relates to OEM_PAID and OEM_PRIVATE capable networks.
+         <p>Not for use by third-party or privileged applications. -->
+    <permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -1916,6 +1922,12 @@
     <permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows access to ultra wideband device.
+     <p>Not for use by third-party applications.
+     @hide -->
+    <permission android:name="android.permission.UWB_PRIVILEGED"
+                android:protectionLevel="signature|privileged" />
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -2499,6 +2511,10 @@
     <permission android:name="android.permission.CREATE_USERS"
         android:protectionLevel="signature" />
 
+    <!-- @TestApi @hide Allows an application to query user info for all users on the device. -->
+    <permission android:name="android.permission.QUERY_USERS"
+                android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to set the profile owners and the device owner.
          This permission is not available to third party applications.-->
     <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
@@ -3054,6 +3070,11 @@
     <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to set, update and remove the credential management app.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP"
+        android:protectionLevel="signature" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
@@ -3793,6 +3814,11 @@
     <permission android:name="android.permission.MOVE_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @TestApi Allows an application to keep uninstalled packages as apks.
+         @hide -->
+    <permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to change whether an application component (other than its own) is
          enabled or not.
          <p>Not for use by third-party applications. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 20cb270..ee45249 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1547,8 +1547,8 @@
          take precedence over lower ones.
          See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
     <string-array name="config_autoTimeSourcesPriority">
-        <item>telephony</item>
         <item>network</item>
+        <item>telephony</item>
     </string-array>
 
     <!-- Enables the TimeZoneRuleManager service. This is the global switch for the updateable time
diff --git a/core/sysprop/Android.bp b/core/sysprop/Android.bp
index 237ede2..f89099e 100644
--- a/core/sysprop/Android.bp
+++ b/core/sysprop/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"],
+}
+
 sysprop_library {
     name: "com.android.sysprop.localization",
     srcs: ["LocalizationProperties.sysprop"],
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index b8efd19..113f45d 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/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: "BroadcastRadioTests",
     privileged: true,
diff --git a/core/tests/ConnectivityManagerTest/Android.bp b/core/tests/ConnectivityManagerTest/Android.bp
index a33d219..beaf176 100644
--- a/core/tests/ConnectivityManagerTest/Android.bp
+++ b/core/tests/ConnectivityManagerTest/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: "ConnectivityManagerTest",
     libs: [
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index e74f30e..c7a0002 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FrameworksCorePackageInstallerSessionsTests",
 
diff --git a/core/tests/PlatformCompatFramework/Android.bp b/core/tests/PlatformCompatFramework/Android.bp
index 3380265..95e23ad 100644
--- a/core/tests/PlatformCompatFramework/Android.bp
+++ b/core/tests/PlatformCompatFramework/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: "PlatformCompatFrameworkTests",
     // Include all test java files.
diff --git a/core/tests/bandwidthtests/Android.bp b/core/tests/bandwidthtests/Android.bp
index 5d881b8..f1ecd45 100644
--- a/core/tests/bandwidthtests/Android.bp
+++ b/core/tests/bandwidthtests/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: "BandwidthTests",
     // Include all test java files.
diff --git a/core/tests/benchmarks/Android.bp b/core/tests/benchmarks/Android.bp
index 8dd7928..4cd5467 100644
--- a/core/tests/benchmarks/Android.bp
+++ b/core/tests/benchmarks/Android.bp
@@ -16,6 +16,15 @@
 // build framework base core benchmarks
 // ============================================================
 
+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: "frameworks-base-core-benchmarks",
     installable: true,
diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp
index 4b6f9db..a2e4dff 100644
--- a/core/tests/bluetoothtests/Android.bp
+++ b/core/tests/bluetoothtests/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: "BluetoothTests",
     // Include all test java files.
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index e42b4b4..f87797a 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/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: "BugreportManagerTestCases",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 1e16ee0..510578e 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/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: "FrameworksCoreTests",
 
diff --git a/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp b/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp
index 25e4fc3..b47c470 100644
--- a/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp
+++ b/core/tests/coretests/BinderDeathRecipientHelperApp/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_helper_app {
     name: "BinderDeathRecipientHelperApp1",
 
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.bp b/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
index 6279a48..b1df8db 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
+++ b/core/tests/coretests/BinderProxyCountingTestApp/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: "BinderProxyCountingTestApp",
 
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.bp b/core/tests/coretests/BinderProxyCountingTestService/Android.bp
index 22718cb..52c23a1 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.bp
+++ b/core/tests/coretests/BinderProxyCountingTestService/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: "BinderProxyCountingTestService",
 
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp
index a89d728..c82da9e 100644
--- a/core/tests/coretests/BstatsTestApp/Android.bp
+++ b/core/tests/coretests/BstatsTestApp/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: "BstatsTestApp",
 
diff --git a/core/tests/coretests/DisabledTestApp/Android.bp b/core/tests/coretests/DisabledTestApp/Android.bp
index 419816e..3ab3218 100644
--- a/core/tests/coretests/DisabledTestApp/Android.bp
+++ b/core/tests/coretests/DisabledTestApp/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_helper_app {
     name: "DisabledTestApp",
 
diff --git a/core/tests/coretests/EnabledTestApp/Android.bp b/core/tests/coretests/EnabledTestApp/Android.bp
index bc4f4bd..750b578 100644
--- a/core/tests/coretests/EnabledTestApp/Android.bp
+++ b/core/tests/coretests/EnabledTestApp/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_helper_app {
     name: "EnabledTestApp",
 
diff --git a/core/tests/coretests/aidl/Android.bp b/core/tests/coretests/aidl/Android.bp
index 6e442db..2d848cc 100644
--- a/core/tests/coretests/aidl/Android.bp
+++ b/core/tests/coretests/aidl/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"],
+}
+
 java_test {
     name: "coretests-aidl",
     sdk_version: "current",
diff --git a/core/tests/coretests/apks/Android.bp b/core/tests/coretests/apks/Android.bp
index 20c87b2..eda875ac 100644
--- a/core/tests/coretests/apks/Android.bp
+++ b/core/tests/coretests/apks/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_defaults {
     name: "FrameworksCoreTests_apks_defaults",
     sdk_version: "current",
diff --git a/core/tests/coretests/apks/install/Android.bp b/core/tests/coretests/apks/install/Android.bp
index e783fe2..652b491 100644
--- a/core/tests/coretests/apks/install/Android.bp
+++ b/core/tests/coretests/apks/install/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_helper_app {
     name: "FrameworksCoreTests_install",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.bp b/core/tests/coretests/apks/install_bad_dex/Android.bp
index d156793..7b96c9b4 100644
--- a/core/tests/coretests/apks/install_bad_dex/Android.bp
+++ b/core/tests/coretests/apks/install_bad_dex/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_helper_app {
     name: "FrameworksCoreTests_install_bad_dex_",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.bp b/core/tests/coretests/apks/install_complete_package_info/Android.bp
index 123558bd..3fee0c6 100644
--- a/core/tests/coretests/apks/install_complete_package_info/Android.bp
+++ b/core/tests/coretests/apks/install_complete_package_info/Android.bp
@@ -1,7 +1,15 @@
+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: "FrameworksCoreTests_install_complete_package_info",
     defaults: ["FrameworksCoreTests_apks_defaults"],
 
     srcs: ["**/*.java"],
 }
-
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.bp b/core/tests/coretests/apks/install_decl_perm/Android.bp
index 868e8b5..bf1f0de 100644
--- a/core/tests/coretests/apks/install_decl_perm/Android.bp
+++ b/core/tests/coretests/apks/install_decl_perm/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_helper_app {
     name: "FrameworksCoreTests_install_decl_perm",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.bp b/core/tests/coretests/apks/install_jni_lib/Android.bp
index df19fa0..d315e7b 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.bp
+++ b/core/tests/coretests/apks/install_jni_lib/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"],
+}
+
 cc_test_library {
     name: "libframeworks_coretests_jni",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
index 602b704..20cc96e 100644
--- a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/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_helper_app {
     name: "FrameworksCoreTests_install_jni_lib_open_from_apk",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.bp b/core/tests/coretests/apks/install_loc_auto/Android.bp
index 6393915..37daf76 100644
--- a/core/tests/coretests/apks/install_loc_auto/Android.bp
+++ b/core/tests/coretests/apks/install_loc_auto/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_helper_app {
     name: "FrameworksCoreTests_install_loc_auto",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.bp b/core/tests/coretests/apks/install_loc_internal/Android.bp
index 770aaa5..3e23313 100644
--- a/core/tests/coretests/apks/install_loc_internal/Android.bp
+++ b/core/tests/coretests/apks/install_loc_internal/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_helper_app {
     name: "FrameworksCoreTests_install_loc_internal",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.bp b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
index 1779401..708e655 100644
--- a/core/tests/coretests/apks/install_loc_sdcard/Android.bp
+++ b/core/tests/coretests/apks/install_loc_sdcard/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_helper_app {
     name: "FrameworksCoreTests_install_loc_sdcard",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/core/tests/coretests/apks/install_loc_unspecified/Android.bp
index 21c0f82..76869e9 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/core/tests/coretests/apks/install_loc_unspecified/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_helper_app {
     name: "FrameworksCoreTests_install_loc_unspecified",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.bp b/core/tests/coretests/apks/install_use_perm_good/Android.bp
index bb41ebb..89700dd 100644
--- a/core/tests/coretests/apks/install_use_perm_good/Android.bp
+++ b/core/tests/coretests/apks/install_use_perm_good/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_helper_app {
     name: "FrameworksCoreTests_install_use_perm_good",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.bp b/core/tests/coretests/apks/install_uses_feature/Android.bp
index 0ec747b..913a96a 100644
--- a/core/tests/coretests/apks/install_uses_feature/Android.bp
+++ b/core/tests/coretests/apks/install_uses_feature/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_helper_app {
     name: "FrameworksCoreTests_install_uses_feature",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.bp b/core/tests/coretests/apks/install_verifier_bad/Android.bp
index 1265739..ed13d74 100644
--- a/core/tests/coretests/apks/install_verifier_bad/Android.bp
+++ b/core/tests/coretests/apks/install_verifier_bad/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_helper_app {
     name: "FrameworksCoreTests_install_verifier_bad",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.bp b/core/tests/coretests/apks/install_verifier_good/Android.bp
index 4911ffb..fe9a24f 100644
--- a/core/tests/coretests/apks/install_verifier_good/Android.bp
+++ b/core/tests/coretests/apks/install_verifier_good/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_helper_app {
     name: "FrameworksCoreTests_install_verifier_good",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/keyset/Android.bp b/core/tests/coretests/apks/keyset/Android.bp
index e252b08..93c3b1f 100644
--- a/core/tests/coretests/apks/keyset/Android.bp
+++ b/core/tests/coretests/apks/keyset/Android.bp
@@ -1,4 +1,13 @@
 //apks signed by keyset_A
+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: "FrameworksCoreTests_keyset_sa_unone",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/locales/Android.bp b/core/tests/coretests/apks/locales/Android.bp
index 4a730ef..4fe6c7f 100644
--- a/core/tests/coretests/apks/locales/Android.bp
+++ b/core/tests/coretests/apks/locales/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_helper_app {
     name: "FrameworksCoreTests_locales",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/overlay_config/Android.bp b/core/tests/coretests/apks/overlay_config/Android.bp
index 9573557..9c971fd 100644
--- a/core/tests/coretests/apks/overlay_config/Android.bp
+++ b/core/tests/coretests/apks/overlay_config/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_helper_app {
     name: "FrameworksCoreTests_overlay_config",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/version/Android.bp b/core/tests/coretests/apks/version/Android.bp
index 371ccfc..8b750f7 100644
--- a/core/tests/coretests/apks/version/Android.bp
+++ b/core/tests/coretests/apks/version/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_helper_app {
     name: "FrameworksCoreTests_version_1",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/apks/version_nosys/Android.bp b/core/tests/coretests/apks/version_nosys/Android.bp
index 5756678..de40f49 100644
--- a/core/tests/coretests/apks/version_nosys/Android.bp
+++ b/core/tests/coretests/apks/version_nosys/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_helper_app {
     name: "FrameworksCoreTests_version_1_nosys",
     defaults: ["FrameworksCoreTests_apks_defaults"],
diff --git a/core/tests/coretests/assets/fonts/OWNERS b/core/tests/coretests/assets/fonts/OWNERS
new file mode 100644
index 0000000..b0e0b9d
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/text/OWNERS
diff --git a/core/tests/coretests/assets/fonts_for_family_selection/OWNERS b/core/tests/coretests/assets/fonts_for_family_selection/OWNERS
new file mode 100644
index 0000000..b0e0b9d
--- /dev/null
+++ b/core/tests/coretests/assets/fonts_for_family_selection/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/text/OWNERS
diff --git a/core/tests/coretests/certs/Android.bp b/core/tests/coretests/certs/Android.bp
index bd5c829..8411183 100644
--- a/core/tests/coretests/certs/Android.bp
+++ b/core/tests/coretests/certs/Android.bp
@@ -1,3 +1,14 @@
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_app_certificate {
     name: "FrameworksCoreTests_keyset_A_cert",
     certificate: "keyset_A",
diff --git a/core/tests/coretests/res/font/OWNERS b/core/tests/coretests/res/font/OWNERS
new file mode 100644
index 0000000..b0e0b9d
--- /dev/null
+++ b/core/tests/coretests/res/font/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/text/OWNERS
diff --git a/core/tests/coretests/src/android/provider/OWNERS b/core/tests/coretests/src/android/provider/OWNERS
new file mode 100644
index 0000000..581da71
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/provider/OWNERS
diff --git a/core/tests/coretests/src/android/provider/SimPhonebookContractTest.java b/core/tests/coretests/src/android/provider/SimPhonebookContractTest.java
new file mode 100644
index 0000000..bc7be1b
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/SimPhonebookContractTest.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.provider;
+
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SimPhonebookContractTest {
+
+    @Test
+    public void getContentUri_invalidEfType_throwsIllegalArgumentException() {
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getContentUri(1, 100)
+        );
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getContentUri(1, -1)
+        );
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getContentUri(1,
+                        SimPhonebookContract.ElementaryFiles.EF_UNKNOWN)
+        );
+    }
+
+    @Test
+    public void getItemUri_invalidEfType_throwsIllegalArgumentException() {
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getItemUri(1, 100, 1)
+        );
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getItemUri(1, -1, 1)
+        );
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getItemUri(1,
+                        SimPhonebookContract.ElementaryFiles.EF_UNKNOWN, 1)
+        );
+    }
+
+    @Test
+    public void getItemUri_invalidRecordIndex_throwsIllegalArgumentException() {
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getItemUri(1,
+                        SimPhonebookContract.ElementaryFiles.EF_ADN, 0)
+        );
+        assertThrows(IllegalArgumentException.class, () ->
+                SimPhonebookContract.SimRecords.getItemUri(1,
+                        SimPhonebookContract.ElementaryFiles.EF_ADN, -1)
+        );
+    }
+}
+
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index 5031ff9..80165f0 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -1,7 +1,7 @@
 # Input
-per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com
-per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com
-per-file VelocityTest.java = michaelwr@google.com, svv@google.com
+per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file VelocityTest.java = file:/services/core/java/com/android/server/input/OWNERS
 
 # WindowManager
 per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 7917a06..2c1bbf0 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@
         assertThat(entry3.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerSecond");
         assertThat(entry3.messageName).startsWith(
-                "com.android.internal.os.-$$Lambda$LooperStatsTest$");
+                "com.android.internal.os.LooperStatsTest-$$ExternalSyntheticLambda");
         assertThat(entry3.messageCount).isEqualTo(1);
         assertThat(entry3.recordedMessageCount).isEqualTo(1);
         assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/coretests/src/com/android/internal/os/OWNERS b/core/tests/coretests/src/com/android/internal/os/OWNERS
index 4068e2b..3f8f9e2 100644
--- a/core/tests/coretests/src/com/android/internal/os/OWNERS
+++ b/core/tests/coretests/src/com/android/internal/os/OWNERS
@@ -1 +1,4 @@
 include /BATTERY_STATS_OWNERS
+
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/widget/OWNERS b/core/tests/coretests/src/com/android/internal/widget/OWNERS
new file mode 100644
index 0000000..b40fe24
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/OWNERS
@@ -0,0 +1,3 @@
+# LockSettings related
+per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/core/tests/featureflagtests/Android.bp b/core/tests/featureflagtests/Android.bp
index 8730b70..d9f608e 100644
--- a/core/tests/featureflagtests/Android.bp
+++ b/core/tests/featureflagtests/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: "FrameworksCoreFeatureFlagTests",
     // We only want this apk build for tests.
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 4755e0e..f49e053 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/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: "HdmiCecTests",
     // Include all test java files
diff --git a/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp b/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp
index 1442481..b4efce2 100644
--- a/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/AutoLocTestApp/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: "AutoLocTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp
index 438ed25..0e07ddc 100644
--- a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/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: "AutoLocVersionedTestApp_v1",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp
index 2ac72a1..f408700 100644
--- a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/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: "AutoLocVersionedTestApp_v2",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp
index e06e82e..964401d 100644
--- a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/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: "ExternalLocAllPermsTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp
index c48dcd5..297ed57 100644
--- a/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/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: "ExternalLocPermFLTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp
index 5c1c15a..cf8c7e1 100644
--- a/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalLocTestApp/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: "ExternalLocTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp
index 13f5066..909bd7f 100644
--- a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/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: "ExternalLocVersionedTestApp_v1",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp
index e02ffb3..c5f9192 100644
--- a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/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: "ExternalLocVersionedTestApp_v2",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp
index de09800..1545f4d 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/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: "ExternalSharedPermsTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp
index 435144f..8690bdf 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/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: "ExternalSharedPermsBTTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp
index 445bac9..21b7c4c 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/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: "ExternalSharedPermsDiffKeyTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp
index d1da399..63bf8dc 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/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: "ExternalSharedPermsFLTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp b/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp
index fab9d43..f05cde4 100644
--- a/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/InternalLocTestApp/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: "InternalLocTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
index dcf1687..56f10fe 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/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: "MultiDexLegacyTestServicesTests",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp b/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp
index 50a2de4..88e3722 100644
--- a/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/NoLocTestApp/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: "NoLocTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp
index 4bc9edc..fd5ab26 100644
--- a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/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: "NoLocVersionedTestApp_v1",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp
index dd2952b..fa821d8 100644
--- a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/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: "NoLocVersionedTestApp_v2",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/Android.bp b/core/tests/hosttests/test-apps/SharedUid/32/Android.bp
index f3e3ede..6f3d4cf 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/Android.bp
@@ -19,6 +19,15 @@
 
 // Build activity
 
+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: "PMTest_Java32",
     srcs: ["**/*.java"],
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp
index 9e6c17f..867d65c 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.bp
@@ -17,6 +17,15 @@
 // This makefile supplies the rules for building a library of JNI code for
 // use by our example of how to bundle a shared library with an APK.
 
+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_test_library {
 
     // This is the target being built.
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/Android.bp b/core/tests/hosttests/test-apps/SharedUid/64/Android.bp
index 5d9c0b5..6bb25a8 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/Android.bp
@@ -19,6 +19,15 @@
 
 // Build activity
 
+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: "PMTest_Java64",
     srcs: ["**/*.java"],
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp
index 91da6e4..c032ba1 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.bp
@@ -17,6 +17,15 @@
 // This Android.bp supplies the rules for building a library of JNI code for
 // use by our example of how to bundle a shared library with an APK.
 
+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_test_library {
     // This is the target being built.
     name: "libpmtest64",
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp b/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp
index c42192d..94dd0c6 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp
@@ -19,6 +19,15 @@
 
 // Build activity
 
+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: "PMTest_Java_dual",
     srcs: ["**/*.java"],
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp
index 662755d..6b9d7f3 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.bp
@@ -17,6 +17,15 @@
 // This Android.bp supplies the rules for building a library of JNI code for
 // use by our example of how to bundle a shared library with an APK.
 
+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_test_library {
 
     // This is the target being built.
diff --git a/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp b/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp
index baedc6e..6d63267 100644
--- a/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp
+++ b/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp
@@ -19,6 +19,15 @@
 
 // Build activity
 
+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: "PMTest_Java",
     srcs: ["**/*.java"],
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp b/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp
index 5f443bd..b022bda 100644
--- a/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp
+++ b/core/tests/hosttests/test-apps/SimpleTestApp/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: "SimpleTestApp",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp
index 800e083..0ac825b 100644
--- a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp
+++ b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/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: "UpdateExtToIntLocTestApp_v1_ext",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp
index 299887c..6f66a51 100644
--- a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp
+++ b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/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: "UpdateExtToIntLocTestApp_v2_int",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp
index 1530422..d88bce0 100644
--- a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp
+++ b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/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: "UpdateExternalLocTestApp_v1_ext",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp
index 4c7975e..d1240df 100644
--- a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp
+++ b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/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: "UpdateExternalLocTestApp_v2_none",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp
index c6b60c3..751071c 100644
--- a/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_Auto/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: "VersatileTestApp_Auto",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp
index db521ef..b9ed015 100644
--- a/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_External/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: "VersatileTestApp_External",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp
index ca059302..7b72570 100644
--- a/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_Internal/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: "VersatileTestApp_Internal",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp
index 6e1aac7..5f67bce 100644
--- a/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_None/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: "VersatileTestApp_None",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index ae3ff86..96811be 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FrameworksMockingCoreTests",
 
diff --git a/core/tests/notificationtests/Android.bp b/core/tests/notificationtests/Android.bp
index e744d5a..1c0e39d 100644
--- a/core/tests/notificationtests/Android.bp
+++ b/core/tests/notificationtests/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: "NotificationStressTests",
     // Include all test java files.
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index f86ac9c..0d3b15a 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/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: "OverlayDeviceTests",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index ebbdda5..2d7d9b4 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -19,17 +19,13 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
 
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="remount-system" value="true" />
         <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" />
     </target_preparer>
-
-    <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. -->
-    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
-      <option name="pre-reboot" value="true" />
-      <option name="post-reboot" value="true" />
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="cleanup-apks" value="true" />
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
index 847b491..4ff59fa 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/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: "OverlayDeviceTests_AppOverlayOne",
     sdk_version: "current",
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
index 7d5f82a..1f5763e 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/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: "OverlayDeviceTests_AppOverlayTwo",
     sdk_version: "current",
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp
index 50dbc6f..178a020 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/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: "OverlayDeviceTests_FrameworkOverlay",
     sdk_version: "current",
diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp
index a2fcef5..e4c3fbe 100644
--- a/core/tests/overlaytests/host/Android.bp
+++ b/core/tests/overlaytests/host/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"],
+}
+
 java_test_host {
     name: "OverlayHostTests",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/overlaytests/remount/Android.bp b/core/tests/overlaytests/remount/Android.bp
index 939334c..0a6b88b 100644
--- a/core/tests/overlaytests/remount/Android.bp
+++ b/core/tests/overlaytests/remount/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"],
+}
+
 java_test_host {
     name: "OverlayRemountedTest",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
index 032a0cd..a341c9a 100644
--- a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
+++ b/core/tests/overlaytests/remount/test-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: "OverlayRemountedTest_Overlay",
     sdk_version: "current",
@@ -24,4 +33,4 @@
     name: "OverlayRemountedTest_Overlay_SameCert",
     certificate: ":rro-remounted-test-a",
     sdk_version: "current",
-}
\ No newline at end of file
+}
diff --git a/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp
index ffb0572..bc88d61 100644
--- a/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/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: "OverlayRemountedTest_SharedLibrary",
     sdk_version: "current",
diff --git a/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp
index 0d29aec..88a05ab 100644
--- a/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/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: "OverlayRemountedTest_SharedLibraryOverlay",
     sdk_version: "current",
diff --git a/core/tests/overlaytests/remount/test-apps/Target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
index e4b4eaa..869a75f 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Target/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: "OverlayRemountedTest_Target",
     sdk_version: "test_current",
diff --git a/core/tests/overlaytests/remount/test-apps/certs/Android.bp b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
index 06114ef..f5d89bc 100644
--- a/core/tests/overlaytests/remount/test-apps/certs/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
@@ -13,6 +13,17 @@
 // limitations under the License.
 
 // development/tools/make_key rro-remounted-test-a '/CN=rro_test_a'
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_app_certificate {
     name: "rro-remounted-test-a",
     certificate: "rro-remounted-test-a",
diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
index e6ebd5e..3536c40 100644
--- a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp
@@ -12,6 +12,17 @@
 // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 genrule {
   name: "com.android.overlaytest.overlaid.pem",
   out: ["com.android.overlaytest.overlaid.pem"],
@@ -39,4 +50,5 @@
     key: "com.android.overlaytest.overlaid.key",
     apps: ["OverlayRemountedTest_Target"],
     installable: false,
+    updatable: false,
 }
diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
index 07f27ee..f041404 100644
--- a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp
@@ -12,6 +12,17 @@
 // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 genrule {
   name: "com.android.overlaytest.overlay.pem",
   out: ["com.android.overlaytest.overlay.pem"],
@@ -39,4 +50,5 @@
     key: "com.android.overlaytest.overlay.key",
     apps: ["OverlayRemountedTest_Overlay"],
     installable: false,
+    updatable: false,
 }
diff --git a/core/tests/packagemanagertests/Android.bp b/core/tests/packagemanagertests/Android.bp
index 6f39af8..5ce71c9 100644
--- a/core/tests/packagemanagertests/Android.bp
+++ b/core/tests/packagemanagertests/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: "FrameworksCorePackageManagerTests",
     // We only want this apk build for tests.
diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp
index 7f56992..bc3dd81 100644
--- a/core/tests/privacytests/Android.bp
+++ b/core/tests/privacytests/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: "FrameworksPrivacyLibraryTests",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/screenshothelpertests/Android.bp b/core/tests/screenshothelpertests/Android.bp
index 3d54b68..37af99c 100644
--- a/core/tests/screenshothelpertests/Android.bp
+++ b/core/tests/screenshothelpertests/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: "ScreenshotHelperTests",
 
@@ -25,4 +34,3 @@
 
     certificate: "platform",
 }
-
diff --git a/core/tests/systemproperties/Android.bp b/core/tests/systemproperties/Android.bp
index 7ef1b9b..765ca3e 100644
--- a/core/tests/systemproperties/Android.bp
+++ b/core/tests/systemproperties/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: "FrameworksCoreSystemPropertiesTests",
     // Include all test java files.
diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp
index 1f742c2..d40d1d2 100644
--- a/core/tests/utillib/Android.bp
+++ b/core/tests/utillib/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"],
+}
+
 java_library {
     name: "frameworks-core-util-lib",
 
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index a9b9c41..72d6a2c 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -2,6 +2,15 @@
 // Build FrameworksUtilTests package
 //########################################################################
 
+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: "FrameworksUtilTests",
 
diff --git a/core/tests/utiltests/jni/Android.bp b/core/tests/utiltests/jni/Android.bp
index 6b75471..a9c695e 100644
--- a/core/tests/utiltests/jni/Android.bp
+++ b/core/tests/utiltests/jni/Android.bp
@@ -11,6 +11,15 @@
 // 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"],
+}
+
 

 cc_library_shared {

     name: "libmemoryintarraytest",

diff --git a/core/tests/uwbtests/Android.bp b/core/tests/uwbtests/Android.bp
index 8ee86f4..31f446f 100644
--- a/core/tests/uwbtests/Android.bp
+++ b/core/tests/uwbtests/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: "UwbManagerTests",
     static_libs: [
diff --git a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
deleted file mode 100644
index 7769c28..0000000
--- a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link AngleMeasurement}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AngleMeasurementTest {
-    private static final double EPSILON = 0.00000000001;
-
-    @Test
-    public void testBuilder() {
-        double radians = 0.1234;
-        double errorRadians = 0.5678;
-        double confidence = 0.5;
-
-        AngleMeasurement.Builder builder = new AngleMeasurement.Builder();
-        tryBuild(builder, false);
-
-        builder.setRadians(radians);
-        tryBuild(builder, false);
-
-        builder.setErrorRadians(errorRadians);
-        tryBuild(builder, false);
-
-        builder.setConfidenceLevel(confidence);
-        AngleMeasurement measurement = tryBuild(builder, true);
-
-        assertEquals(measurement.getRadians(), radians, 0);
-        assertEquals(measurement.getErrorRadians(), errorRadians, 0);
-        assertEquals(measurement.getConfidenceLevel(), confidence, 0);
-    }
-
-    private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) {
-        AngleMeasurement measurement = null;
-        try {
-            measurement = builder.build();
-            if (!expectSuccess) {
-                fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded");
-            }
-        } catch (IllegalStateException e) {
-            if (expectSuccess) {
-                fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed");
-            }
-        }
-        return measurement;
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        AngleMeasurement measurement = UwbTestUtils.getAngleMeasurement();
-        measurement.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        AngleMeasurement fromParcel = AngleMeasurement.CREATOR.createFromParcel(parcel);
-        assertEquals(measurement, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
deleted file mode 100644
index 9394dec..0000000
--- a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link AngleOfArrivalMeasurement}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AngleOfArrivalMeasurementTest {
-
-    @Test
-    public void testBuilder() {
-        AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement();
-        AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement();
-
-        AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
-        tryBuild(builder, false);
-
-        builder.setAltitude(altitude);
-        tryBuild(builder, false);
-
-        builder.setAzimuth(azimuth);
-        AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
-
-        assertEquals(azimuth, measurement.getAzimuth());
-        assertEquals(altitude, measurement.getAltitude());
-    }
-
-    private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
-        return new AngleMeasurement.Builder()
-                .setRadians(radian)
-                .setErrorRadians(error)
-                .setConfidenceLevel(confidence)
-                .build();
-    }
-
-    private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder,
-            boolean expectSuccess) {
-        AngleOfArrivalMeasurement measurement = null;
-        try {
-            measurement = builder.build();
-            if (!expectSuccess) {
-                fail("Expected AngleOfArrivalMeasurement.Builder.build() to fail");
-            }
-        } catch (IllegalStateException e) {
-            if (expectSuccess) {
-                fail("Expected AngleOfArrivalMeasurement.Builder.build() to succeed");
-            }
-        }
-        return measurement;
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        AngleOfArrivalMeasurement measurement = UwbTestUtils.getAngleOfArrivalMeasurement();
-        measurement.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        AngleOfArrivalMeasurement fromParcel =
-                AngleOfArrivalMeasurement.CREATOR.createFromParcel(parcel);
-        assertEquals(measurement, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
deleted file mode 100644
index 439c884..0000000
--- a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link DistanceMeasurement}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class DistanceMeasurementTest {
-    private static final double EPSILON = 0.00000000001;
-
-    @Test
-    public void testBuilder() {
-        double meters = 0.12;
-        double error = 0.54;
-        double confidence = 0.99;
-
-        DistanceMeasurement.Builder builder = new DistanceMeasurement.Builder();
-        tryBuild(builder, false);
-
-        builder.setMeters(meters);
-        tryBuild(builder, false);
-
-        builder.setErrorMeters(error);
-        tryBuild(builder, false);
-
-        builder.setConfidenceLevel(confidence);
-        DistanceMeasurement measurement = tryBuild(builder, true);
-
-        assertEquals(meters, measurement.getMeters(), 0);
-        assertEquals(error, measurement.getErrorMeters(), 0);
-        assertEquals(confidence, measurement.getConfidenceLevel(), 0);
-    }
-
-    private DistanceMeasurement tryBuild(DistanceMeasurement.Builder builder,
-            boolean expectSuccess) {
-        DistanceMeasurement measurement = null;
-        try {
-            measurement = builder.build();
-            if (!expectSuccess) {
-                fail("Expected DistanceMeasurement.Builder.build() to fail");
-            }
-        } catch (IllegalStateException e) {
-            if (expectSuccess) {
-                fail("Expected DistanceMeasurement.Builder.build() to succeed");
-            }
-        }
-        return measurement;
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        DistanceMeasurement measurement = UwbTestUtils.getDistanceMeasurement();
-        measurement.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        DistanceMeasurement fromParcel =
-                DistanceMeasurement.CREATOR.createFromParcel(parcel);
-        assertEquals(measurement, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
deleted file mode 100644
index edd4d08..0000000
--- a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-import android.os.SystemClock;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link RangingMeasurement}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingMeasurementTest {
-
-    @Test
-    public void testBuilder() {
-        int status = RangingMeasurement.RANGING_STATUS_SUCCESS;
-        UwbAddress address = UwbTestUtils.getUwbAddress(false);
-        long time = SystemClock.elapsedRealtimeNanos();
-        AngleOfArrivalMeasurement angleMeasurement = UwbTestUtils.getAngleOfArrivalMeasurement();
-        DistanceMeasurement distanceMeasurement = UwbTestUtils.getDistanceMeasurement();
-
-        RangingMeasurement.Builder builder = new RangingMeasurement.Builder();
-
-        builder.setStatus(status);
-        tryBuild(builder, false);
-
-        builder.setElapsedRealtimeNanos(time);
-        tryBuild(builder, false);
-
-        builder.setAngleOfArrivalMeasurement(angleMeasurement);
-        tryBuild(builder, false);
-
-        builder.setDistanceMeasurement(distanceMeasurement);
-        tryBuild(builder, false);
-
-        builder.setRemoteDeviceAddress(address);
-        RangingMeasurement measurement = tryBuild(builder, true);
-
-        assertEquals(status, measurement.getStatus());
-        assertEquals(address, measurement.getRemoteDeviceAddress());
-        assertEquals(time, measurement.getElapsedRealtimeNanos());
-        assertEquals(angleMeasurement, measurement.getAngleOfArrivalMeasurement());
-        assertEquals(distanceMeasurement, measurement.getDistanceMeasurement());
-    }
-
-    private RangingMeasurement tryBuild(RangingMeasurement.Builder builder,
-            boolean expectSuccess) {
-        RangingMeasurement measurement = null;
-        try {
-            measurement = builder.build();
-            if (!expectSuccess) {
-                fail("Expected RangingMeasurement.Builder.build() to fail");
-            }
-        } catch (IllegalStateException e) {
-            if (expectSuccess) {
-                fail("Expected DistanceMeasurement.Builder.build() to succeed");
-            }
-        }
-        return measurement;
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        RangingMeasurement measurement = UwbTestUtils.getRangingMeasurement();
-        measurement.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        RangingMeasurement fromParcel = RangingMeasurement.CREATOR.createFromParcel(parcel);
-        assertEquals(measurement, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
deleted file mode 100644
index 64c48ba..0000000
--- a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * Test of {@link RangingReport}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingReportTest {
-
-    @Test
-    public void testBuilder() {
-        List<RangingMeasurement> measurements = UwbTestUtils.getRangingMeasurements(5);
-
-        RangingReport.Builder builder = new RangingReport.Builder();
-        builder.addMeasurements(measurements);
-        RangingReport report = tryBuild(builder, true);
-        verifyMeasurementsEqual(measurements, report.getMeasurements());
-
-
-        builder = new RangingReport.Builder();
-        for (RangingMeasurement measurement : measurements) {
-            builder.addMeasurement(measurement);
-        }
-        report = tryBuild(builder, true);
-        verifyMeasurementsEqual(measurements, report.getMeasurements());
-    }
-
-    private void verifyMeasurementsEqual(List<RangingMeasurement> expected,
-            List<RangingMeasurement> actual) {
-        assertEquals(expected.size(), actual.size());
-        for (int i = 0; i < expected.size(); i++) {
-            assertEquals(expected.get(i), actual.get(i));
-        }
-    }
-
-    private RangingReport tryBuild(RangingReport.Builder builder,
-            boolean expectSuccess) {
-        RangingReport report = null;
-        try {
-            report = builder.build();
-            if (!expectSuccess) {
-                fail("Expected RangingReport.Builder.build() to fail");
-            }
-        } catch (IllegalStateException e) {
-            if (expectSuccess) {
-                fail("Expected RangingReport.Builder.build() to succeed");
-            }
-        }
-        return report;
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        RangingReport report = UwbTestUtils.getRangingReports(5);
-        report.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        RangingReport fromParcel = RangingReport.CREATOR.createFromParcel(parcel);
-        assertEquals(report, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java b/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java
deleted file mode 100644
index e5eea26..0000000
--- a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link RangingSession}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingSessionTest {
-    private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
-    private static final PersistableBundle PARAMS = new PersistableBundle();
-    private static final @RangingSession.Callback.Reason int REASON =
-            RangingSession.Callback.REASON_GENERIC_ERROR;
-
-    @Test
-    public void testOnRangingOpened_OnOpenSuccessCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-
-        // Verify that the onOpenSuccess callback was invoked
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(0)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingOpened_CannotOpenClosedSession() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        session.onRangingOpened();
-        verifyOpenState(session, true);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(0)).onClosed(anyInt(), any());
-
-        session.onRangingClosed(REASON, PARAMS);
-        verifyOpenState(session, false);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-
-        // Now invoke the ranging started callback and ensure the session remains closed
-        session.onRangingOpened();
-        verifyOpenState(session, false);
-        verify(callback, times(1)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingClosed(REASON, PARAMS);
-        verifyOpenState(session, false);
-
-        // Verify that the onOpenSuccess callback was invoked
-        verify(callback, times(0)).onOpened(eq(session));
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingClosed_OnClosedCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        session.onRangingStarted(PARAMS);
-        session.onRangingClosed(REASON, PARAMS);
-        verify(callback, times(1)).onClosed(anyInt(), any());
-
-        verifyOpenState(session, false);
-        session.onRangingClosed(REASON, PARAMS);
-        verify(callback, times(2)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedCalled() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        verifyOpenState(session, false);
-
-        session.onRangingStarted(PARAMS);
-        verifyOpenState(session, true);
-
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(1)).onReportReceived(eq(report));
-    }
-
-    @Test
-    public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        session.onRangingOpened();
-
-        session.start(PARAMS);
-        verify(callback, times(1)).onStarted(any());
-
-        // Calling start again should throw an illegal state
-        verifyThrowIllegalState(() -> session.start(PARAMS));
-        verify(callback, times(1)).onStarted(any());
-    }
-
-    @Test
-    public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
-        session.onRangingOpened();
-        session.start(PARAMS);
-
-        verifyNoThrowIllegalState(session::stop);
-        verify(callback, times(1)).onStopped();
-
-        // Calling stop again should throw an illegal state
-        verifyThrowIllegalState(session::stop);
-        verify(callback, times(1)).onStopped();
-    }
-
-    @Test
-    public void testReconfigure_OnlyWhenOpened() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
-        doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any());
-
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(0)).onReconfigured(any());
-        verifyOpenState(session, false);
-
-        session.onRangingOpened();
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(1)).onReconfigured(any());
-        verifyOpenState(session, true);
-
-        session.onRangingStarted(PARAMS);
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(2)).onReconfigured(any());
-        verifyOpenState(session, true);
-
-        session.onRangingStopped();
-        verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(3)).onReconfigured(any());
-        verifyOpenState(session, true);
-
-
-        session.onRangingClosed(REASON, PARAMS);
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verify(callback, times(3)).onReconfigured(any());
-        verifyOpenState(session, false);
-    }
-
-    @Test
-    public void testClose_NoCallbackUntilInvoked() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        session.onRangingOpened();
-
-        // Calling close multiple times should invoke closeRanging until the session receives
-        // the onClosed callback.
-        int totalCallsBeforeOnRangingClosed = 3;
-        for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) {
-            session.close();
-            verifyOpenState(session, true);
-            verify(adapter, times(i)).closeRanging(handle);
-            verify(callback, times(0)).onClosed(anyInt(), any());
-        }
-
-        // After onClosed is invoked, then the adapter should no longer be called for each call to
-        // the session's close.
-        final int totalCallsAfterOnRangingClosed = 2;
-        for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) {
-            session.onRangingClosed(REASON, PARAMS);
-            verifyOpenState(session, false);
-            verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
-            verify(callback, times(i)).onClosed(anyInt(), any());
-        }
-    }
-
-    @Test
-    public void testClose_OnClosedCalled() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-        session.onRangingOpened();
-
-        session.close();
-        verify(callback, times(1)).onClosed(anyInt(), any());
-    }
-
-    @Test
-    public void testClose_CannotInteractFurther() throws RemoteException {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-        doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-        session.close();
-
-        verifyThrowIllegalState(() -> session.start(PARAMS));
-        verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
-        verifyThrowIllegalState(() -> session.stop());
-        verifyNoThrowIllegalState(() -> session.close());
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        assertFalse(session.isOpen());
-        session.onRangingStarted(PARAMS);
-        assertTrue(session.isOpen());
-
-        // Verify that the onReportReceived callback was invoked
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(1)).onReportReceived(report);
-    }
-
-    @Test
-    public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
-        SessionHandle handle = new SessionHandle(123);
-        RangingSession.Callback callback = mock(RangingSession.Callback.class);
-        IUwbAdapter adapter = mock(IUwbAdapter.class);
-        RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
-        assertFalse(session.isOpen());
-
-        // Verify that the onReportReceived callback was invoked
-        RangingReport report = UwbTestUtils.getRangingReports(1);
-        session.onRangingResult(report);
-        verify(callback, times(0)).onReportReceived(report);
-    }
-
-    private void verifyOpenState(RangingSession session, boolean expected) {
-        assertEquals(expected, session.isOpen());
-    }
-
-    private void verifyThrowIllegalState(Runnable runnable) {
-        try {
-            runnable.run();
-            fail();
-        } catch (IllegalStateException e) {
-            // Pass
-        }
-    }
-
-    private void verifyNoThrowIllegalState(Runnable runnable) {
-        try {
-            runnable.run();
-        } catch (IllegalStateException e) {
-            fail();
-        }
-    }
-
-    abstract class AdapterAnswer implements Answer {
-        protected RangingSession mSession;
-
-        protected AdapterAnswer(RangingSession session) {
-            mSession = session;
-        }
-    }
-
-    class StartAnswer extends AdapterAnswer {
-        StartAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingStarted(PARAMS);
-            return null;
-        }
-    }
-
-    class ReconfigureAnswer extends AdapterAnswer {
-        ReconfigureAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingReconfigured(PARAMS);
-            return null;
-        }
-    }
-
-    class StopAnswer extends AdapterAnswer {
-        StopAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingStopped();
-            return null;
-        }
-    }
-
-    class CloseAnswer extends AdapterAnswer {
-        CloseAnswer(RangingSession session) {
-            super(session);
-        }
-
-        @Override
-        public Object answer(InvocationOnMock invocation) {
-            mSession.onRangingClosed(REASON, PARAMS);
-            return null;
-        }
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java b/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java
deleted file mode 100644
index 8b42ff7..0000000
--- a/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link SessionHandle}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SessionHandleTest {
-
-    @Test
-    public void testBasic() {
-        int handleId = 12;
-        SessionHandle handle = new SessionHandle(handleId);
-        assertEquals(handle.getId(), handleId);
-    }
-
-    @Test
-    public void testParcel() {
-        Parcel parcel = Parcel.obtain();
-        SessionHandle handle = new SessionHandle(10);
-        handle.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        SessionHandle fromParcel = SessionHandle.CREATOR.createFromParcel(parcel);
-        assertEquals(handle, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
deleted file mode 100644
index ccc88a9..0000000
--- a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link UwbAddress}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class UwbAddressTest {
-
-    @Test
-    public void testFromBytes_Short() {
-        runFromBytes(UwbAddress.SHORT_ADDRESS_BYTE_LENGTH);
-    }
-
-    @Test
-    public void testFromBytes_Extended() {
-        runFromBytes(UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH);
-    }
-
-    private void runFromBytes(int len) {
-        byte[] addressBytes = getByteArray(len);
-        UwbAddress address = UwbAddress.fromBytes(addressBytes);
-        assertEquals(address.size(), len);
-        assertEquals(addressBytes, address.toBytes());
-    }
-
-    private byte[] getByteArray(int len) {
-        byte[] res = new byte[len];
-        for (int i = 0; i < len; i++) {
-            res[i] = (byte) i;
-        }
-        return res;
-    }
-
-    @Test
-    public void testParcel_Short() {
-        runParcel(true);
-    }
-
-    @Test
-    public void testParcel_Extended() {
-        runParcel(false);
-    }
-
-    private void runParcel(boolean useShortAddress) {
-        Parcel parcel = Parcel.obtain();
-        UwbAddress address = UwbTestUtils.getUwbAddress(useShortAddress);
-        address.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        UwbAddress fromParcel = UwbAddress.CREATOR.createFromParcel(parcel);
-        assertEquals(address, fromParcel);
-    }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java b/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java
deleted file mode 100644
index 4983bed..0000000
--- a/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.uwb;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import android.content.Context;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link UwbManager}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class UwbManagerTest {
-
-    public final Context mContext = InstrumentationRegistry.getContext();
-
-    @Test
-    public void testServiceAvailable() {
-        UwbManager manager = mContext.getSystemService(UwbManager.class);
-        if (UwbTestUtils.isUwbSupported(mContext)) {
-            assertNotNull(manager);
-        } else {
-            assertNull(manager);
-        }
-    }
-}
diff --git a/core/xsd/Android.bp b/core/xsd/Android.bp
index 738f330..5387f85 100644
--- a/core/xsd/Android.bp
+++ b/core/xsd/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"],
+}
+
 xsd_config {
     name: "permission",
     srcs: ["permission.xsd"],
diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp
index ca655f1..5d8407f 100644
--- a/core/xsd/vts/Android.bp
+++ b/core/xsd/vts/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_test {
     name: "vts_permission_validate_test",
     srcs: [
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index fb8b17c..d0e2474 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -15,6 +15,15 @@
 
 // Sysconfig files
 
+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"],
+}
+
 prebuilt_etc {
     name: "framework-sysconfig.xml",
     sub_dir: "sysconfig",
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 65d3a01..549e074 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -6,7 +6,6 @@
 jsharkey@android.com
 jsharkey@google.com
 lorenzo@google.com
-moltmann@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
 toddke@android.com
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 12bd0f5..67848da 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -16,6 +16,15 @@
 
 // Privapp permission whitelist files
 
+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"],
+}
+
 prebuilt_etc {
     name: "privapp_whitelist_android.car.cluster.loggingrenderer",
     sub_dir: "permissions",
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a664ee3..5b32641 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -446,6 +446,7 @@
         <!-- Permission required for GTS test - GtsAssistIntentTestCases -->
         <permission name="android.permission.MANAGE_SOUND_TRIGGER" />
         <permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
+        <permission name="android.permission.MODIFY_QUIET_MODE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
@@ -459,6 +460,8 @@
         <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
         <!-- Permissions required for quick settings tile -->
         <permission name="android.permission.STATUS_BAR"/>
+        <!-- Permissions required to query Betterbug -->
+        <permission name="android.permission.QUERY_ALL_PACKAGES"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.tv">
diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp
index 3a3bea4..f0d750e 100644
--- a/data/fonts/Android.bp
+++ b/data/fonts/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_base_data_fonts_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_data_fonts_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 prebuilt_font {
     name: "DroidSansMono.ttf",
     src: "DroidSansMono.ttf",
diff --git a/data/keyboards/Android.mk b/data/keyboards/Android.mk
index 7949c77..6ae8800 100644
--- a/data/keyboards/Android.mk
+++ b/data/keyboards/Android.mk
@@ -22,6 +22,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := validate_framework_keymaps
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
 LOCAL_BUILT_MODULE := $(intermediates)/stamp
 
diff --git a/data/keyboards/OWNERS b/data/keyboards/OWNERS
index c4f6df8..0ce8350 100644
--- a/data/keyboards/OWNERS
+++ b/data/keyboards/OWNERS
@@ -1,5 +1,3 @@
 set noparent
 
-michaelwr@google.com
-svv@google.com
-lzye@google.com
+include /services/core/java/com/android/server/input/OWNERS
diff --git a/drm/jni/Android.bp b/drm/jni/Android.bp
index 68757d8..669f109 100644
--- a/drm/jni/Android.bp
+++ b/drm/jni/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_library_shared {
     name: "libdrmframework_jni",
 
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index 7d0557d..f384ae9 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -1,4 +1,13 @@
 
+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_plugin {
     name: "error_prone_android_framework",
 
diff --git a/graphics/java/android/graphics/pdf/OWNERS b/graphics/java/android/graphics/pdf/OWNERS
index f04e200..057dc0d 100644
--- a/graphics/java/android/graphics/pdf/OWNERS
+++ b/graphics/java/android/graphics/pdf/OWNERS
@@ -5,4 +5,3 @@
 sumir@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
-moltmann@google.com
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
index ea79b73..1b19266 100644
--- a/graphics/proto/Android.bp
+++ b/graphics/proto/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_static {
     name: "updatable-driver-protos",
     host_supported: true,
diff --git a/keystore/Android.bp b/keystore/Android.bp
new file mode 100644
index 0000000..5db668e
--- /dev/null
+++ b/keystore/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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 {
+    default_applicable_licenses: ["frameworks_base_keystore_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_keystore_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
new file mode 100644
index 0000000..c81c8c54
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -0,0 +1,105 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.usermanager.IKeystoreUserManager;
+import android.system.keystore2.ResponseCode;
+import android.util.Log;
+
+/**
+ * @hide This is the client side for IKeystoreUserManager AIDL.
+ * It shall only be used by the LockSettingsService.
+ */
+public class AndroidKeyStoreMaintenance {
+    private static final String TAG = "AndroidKeyStoreMaintenance";
+
+    public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+
+    private static IKeystoreUserManager getService() {
+        return IKeystoreUserManager.Stub.asInterface(
+                ServiceManager.checkService("android.security.usermanager"));
+    }
+
+    /**
+     * Informs keystore2 about adding a user
+     *
+     * @param userId - Android user id of the user being added
+     * @return 0 if successful or a {@code ResponseCode}
+     * @hide
+     */
+    public static int onUserAdded(@NonNull int userId) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().onUserAdded(userId);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "onUserAdded failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    /**
+     * Informs keystore2 about removing a usergit mer
+     *
+     * @param userId - Android user id of the user being removed
+     * @return 0 if successful or a {@code ResponseCode}
+     * @hide
+     */
+    public static int onUserRemoved(int userId) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().onUserRemoved(userId);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "onUserRemoved failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    /**
+     * Informs keystore2 about changing user's password
+     *
+     * @param userId   - Android user id of the user
+     * @param password - a secret derived from the synthetic password provided by the
+     *                 LockSettingService
+     * @return 0 if successful or a {@code ResponseCode}
+     * @hide
+     */
+    public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().onUserPasswordChanged(userId, password);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "onUserPasswordChanged failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to keystore/java/android/security/AppUriAuthenticationPolicy.aidl
index 46bc4ab..5c52c86 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.security;
 
-parcelable ApnThrottleStatus;
+parcelable AppUriAuthenticationPolicy;
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
new file mode 100644
index 0000000..0244ce9
--- /dev/null
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -0,0 +1,241 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * The app-URI authentication policy is set by the credential management app. This policy determines
+ * which alias for a private key and certificate pair should be used for authentication.
+ * <p>
+ * The authentication policy should be added as a parameter when calling
+ * {@link KeyChain#createManageCredentialsIntent}.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *     AppUriAuthenticationPolicy authenticationPolicy = new AppUriAuthenticationPolicy.Builder()
+ *              .addAppAndUriMapping("com.test.pkg", testUri, "testAlias")
+ *              .addAppAndUriMapping("com.test2.pkg", testUri1, "testAlias2")
+ *              .addAppAndUriMapping("com.test2.pkg", testUri2, "testAlias2")
+ *              .build();
+ *     Intent requestIntent = KeyChain.createManageCredentialsIntent(authenticationPolicy);
+ * }</pre>
+ * <p>
+ */
+public final class AppUriAuthenticationPolicy implements Parcelable {
+
+    private static final String KEY_AUTHENTICATION_POLICY_APP_TO_URIS =
+            "authentication_policy_app_to_uris";
+    private static final String KEY_AUTHENTICATION_POLICY_APP = "policy_app";
+
+    /**
+     * The mappings from an app and list of URIs to a list of aliases, which will be used for
+     * authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    private final Map<String, UrisToAliases> mAppToUris;
+
+    private AppUriAuthenticationPolicy(@NonNull Map<String, UrisToAliases> appToUris) {
+        Objects.requireNonNull(appToUris);
+        this.mAppToUris = appToUris;
+    }
+
+    /**
+     * Builder class for {@link AppUriAuthenticationPolicy} objects.
+     */
+    public static final class Builder {
+        private Map<String, UrisToAliases> mPackageNameToUris;
+
+        /**
+         * Initialize a new Builder to construct an {@link AppUriAuthenticationPolicy}.
+         */
+        public Builder() {
+            mPackageNameToUris = new HashMap<>();
+        }
+
+        /**
+         * Adds mappings from an app and URI to an alias, which will be used for authentication.
+         * <p>
+         * If this method is called with a package name and URI that was previously added, the
+         * previous alias will be overwritten.
+         *
+         * @param appPackageName The app's package name to authenticate the user to.
+         * @param uri            The URI to authenticate the user to.
+         * @param alias          The alias which will be used for authentication.
+         *
+         * @return the same Builder instance.
+         */
+        @NonNull
+        public Builder addAppAndUriMapping(@NonNull String appPackageName, @NonNull Uri uri,
+                @NonNull String alias) {
+            Objects.requireNonNull(appPackageName);
+            Objects.requireNonNull(uri);
+            Objects.requireNonNull(alias);
+            UrisToAliases urisToAliases =
+                    mPackageNameToUris.getOrDefault(appPackageName, new UrisToAliases());
+            urisToAliases.addUriToAlias(uri, alias);
+            mPackageNameToUris.put(appPackageName, urisToAliases);
+            return this;
+        }
+
+        /**
+         * Adds mappings from an app and list of URIs to a list of aliases, which will be used for
+         * authentication.
+         * <p>
+         * appPackageName -> uri -> alias
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder addAppAndUriMapping(@NonNull String appPackageName,
+                @NonNull UrisToAliases urisToAliases) {
+            Objects.requireNonNull(appPackageName);
+            Objects.requireNonNull(urisToAliases);
+            mPackageNameToUris.put(appPackageName, urisToAliases);
+            return this;
+        }
+
+        /**
+         * Combines all of the attributes that have been set on the {@link Builder}
+         *
+         * @return a new {@link AppUriAuthenticationPolicy} object.
+         */
+        @NonNull
+        public AppUriAuthenticationPolicy build() {
+            return new AppUriAuthenticationPolicy(mPackageNameToUris);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeMap(mAppToUris);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<AppUriAuthenticationPolicy> CREATOR =
+            new Parcelable.Creator<AppUriAuthenticationPolicy>() {
+                @Override
+                public AppUriAuthenticationPolicy createFromParcel(Parcel in) {
+                    Map<String, UrisToAliases> appToUris = new HashMap<>();
+                    in.readMap(appToUris, UrisToAliases.class.getClassLoader());
+                    return new AppUriAuthenticationPolicy(appToUris);
+                }
+
+                @Override
+                public AppUriAuthenticationPolicy[] newArray(int size) {
+                    return new AppUriAuthenticationPolicy[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "AppUriAuthenticationPolicy{"
+                + "mPackageNameToUris=" + mAppToUris
+                + '}';
+    }
+
+    /**
+     * Return the authentication policy mapping, which determines which alias for a private key
+     * and certificate pair should be used for authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    public Map<String, Map<Uri, String>> getAppAndUriMappings() {
+        Map<String, Map<Uri, String>> appAndUris = new HashMap<>();
+        for (Map.Entry<String, UrisToAliases> entry : mAppToUris.entrySet()) {
+            appAndUris.put(entry.getKey(), entry.getValue().getUrisToAliases());
+        }
+        return appAndUris;
+    }
+
+    /**
+     * Restore a previously saved {@link AppUriAuthenticationPolicy} from XML.
+     *
+     * @hide
+     */
+    @Nullable
+    public static AppUriAuthenticationPolicy readFromXml(@NonNull XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        AppUriAuthenticationPolicy.Builder builder = new AppUriAuthenticationPolicy.Builder();
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_APP_TO_URIS)) {
+                continue;
+            }
+            String app = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_APP);
+            UrisToAliases urisToAliases = UrisToAliases.readFromXml(parser);
+            builder.addAppAndUriMapping(app, urisToAliases);
+        }
+        return builder.build();
+    }
+
+    /**
+     * Save the {@link AppUriAuthenticationPolicy} to XML.
+     *
+     * @hide
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        for (Map.Entry<String, UrisToAliases> appsToUris : mAppToUris.entrySet()) {
+            out.startTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_APP, appsToUris.getKey());
+            appsToUris.getValue().writeToXml(out);
+            out.endTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+        }
+    }
+
+    /**
+     * Get the set of aliases found in the policy.
+     *
+     * @hide
+     */
+    public Set<String> getAliases() {
+        Set<String> aliases = new HashSet<>();
+        for (UrisToAliases appsToUris : mAppToUris.values()) {
+            aliases.addAll(appsToUris.getUrisToAliases().values());
+        }
+        return aliases;
+    }
+
+}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 21d23b1..50a9082 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -33,20 +33,12 @@
  */
 public class Authorization {
     private static final String TAG = "KeystoreAuthorization";
-    private static IKeystoreAuthorization sIKeystoreAuthorization;
 
     public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
 
-    public Authorization() {
-        sIKeystoreAuthorization = null;
-    }
-
-    private static synchronized IKeystoreAuthorization getService() {
-        if (sIKeystoreAuthorization == null) {
-            sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
+    private static IKeystoreAuthorization getService() {
+        return IKeystoreAuthorization.Stub.asInterface(
                     ServiceManager.checkService("android.security.authorization"));
-        }
-        return sIKeystoreAuthorization;
     }
 
     /**
@@ -55,12 +47,12 @@
      * @param authToken created by Android authenticators.
      * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
      */
-    public int addAuthToken(@NonNull HardwareAuthToken authToken) {
+    public static int addAuthToken(@NonNull HardwareAuthToken authToken) {
         if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().addAuthToken(authToken);
             return 0;
-        } catch (RemoteException e) {
+        } catch (RemoteException | NullPointerException e) {
             Log.w(TAG, "Can not connect to keystore", e);
             return SYSTEM_ERROR;
         } catch (ServiceSpecificException e) {
@@ -73,7 +65,7 @@
      * @param authToken
      * @return 0 if successful or a {@code ResponseCode}.
      */
-    public int addAuthToken(@NonNull byte[] authToken) {
+    public static int addAuthToken(@NonNull byte[] authToken) {
         return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken));
     }
 
@@ -86,7 +78,7 @@
      *
      * @return 0 if successful or a {@code ResponseCode}.
      */
-    public int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
+    public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
             @Nullable byte[] syntheticPassword) {
         if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
@@ -96,7 +88,7 @@
                 getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword);
             }
             return 0;
-        } catch (RemoteException e) {
+        } catch (RemoteException | NullPointerException e) {
             Log.w(TAG, "Can not connect to keystore", e);
             return SYSTEM_ERROR;
         } catch (ServiceSpecificException e) {
diff --git a/keystore/java/android/security/CredentialManagementApp.java b/keystore/java/android/security/CredentialManagementApp.java
new file mode 100644
index 0000000..cbb2301
--- /dev/null
+++ b/keystore/java/android/security/CredentialManagementApp.java
@@ -0,0 +1,123 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * The credential management app has the ability to manage the user's KeyChain credentials on
+ * unmanaged devices. {@link KeyChain#createManageCredentialsIntent} should be used by an app to
+ * request to become the credential management app. The user must approve this request before the
+ * app can manage the user's credentials.
+ * <p>
+ * Note: there can only be one credential management on the device. If another app requests to
+ * become the credential management app and the user approves, then the existing credential
+ * management app will no longer be able to manage credentials.
+ * <p>
+ * The requesting credential management app should include its authentication policy in the
+ * requesting intent. The authentication policy declares which certificates should be used for a
+ * given list of apps and URIs.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public class CredentialManagementApp {
+
+    private static final String TAG = "CredentialManagementApp";
+    private static final String KEY_PACKAGE_NAME = "package_name";
+
+    /**
+     * The credential management app's package name
+     */
+    @NonNull
+    private final String mPackageName;
+
+    /**
+     * The mappings from an app and list of URIs to a list of aliases, which will be used for
+     * authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    private AppUriAuthenticationPolicy mAuthenticationPolicy;
+
+    public CredentialManagementApp(@NonNull String packageName,
+            @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(authenticationPolicy);
+        mPackageName = packageName;
+        mAuthenticationPolicy = authenticationPolicy;
+    }
+
+    /**
+     * Returns the package name of the credential management app.
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Returns the authentication policy of the credential management app.
+     */
+    @NonNull
+    public AppUriAuthenticationPolicy getAuthenticationPolicy() {
+        return mAuthenticationPolicy;
+    }
+
+    /**
+     * Sets the authentication policy of the credential management app.
+     */
+    public void setAuthenticationPolicy(@Nullable AppUriAuthenticationPolicy authenticationPolicy) {
+        Objects.requireNonNull(authenticationPolicy);
+        mAuthenticationPolicy = authenticationPolicy;
+    }
+
+    /**
+     * Restore a previously saved {@link CredentialManagementApp} from XML.
+     */
+    @Nullable
+    public static CredentialManagementApp readFromXml(@NonNull XmlPullParser parser) {
+        try {
+            String packageName = parser.getAttributeValue(null, KEY_PACKAGE_NAME);
+            AppUriAuthenticationPolicy policy = AppUriAuthenticationPolicy.readFromXml(parser);
+            return new CredentialManagementApp(packageName, policy);
+        } catch (XmlPullParserException | IOException e) {
+            Log.w(TAG, "Reading from xml failed", e);
+        }
+        return null;
+    }
+
+    /**
+     * Save the {@link CredentialManagementApp} to XML.
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        out.attribute(null, KEY_PACKAGE_NAME, mPackageName);
+        if (mAuthenticationPolicy != null) {
+            mAuthenticationPolicy.writeToXml(out);
+        }
+    }
+}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 9e1fb54..ae9f8664 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,6 +49,8 @@
 
     public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
 
+    public static final String ACTION_MANAGE_CREDENTIALS = "android.security.MANAGE_CREDENTIALS";
+
     /**
      * Key prefix for CA certificates.
      *
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 97da3cc..f708298 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -18,6 +18,8 @@
 import android.content.pm.StringParceledListSlice;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.AppUriAuthenticationPolicy;
+import android.net.Uri;
 
 /**
  * Caller is required to ensure that {@link KeyStore#unlock
@@ -46,6 +48,8 @@
     boolean installKeyPair(
         in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
     boolean removeKeyPair(String alias);
+    boolean containsKeyPair(String alias);
+    int[] getGrants(String alias);
 
     // APIs used by Settings
     boolean deleteCaCertificate(String alias);
@@ -55,6 +59,12 @@
     boolean containsCaAlias(String alias);
     byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
     List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
+    void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
+    boolean hasCredentialManagementApp();
+    String getCredentialManagementAppPackageName();
+    AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
+    String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
+    void removeCredentialManagementApp();
 
     // APIs used by KeyChainActivity
     void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 6df62c0..63690d3 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,6 +15,8 @@
  */
 package android.security;
 
+import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -122,6 +124,11 @@
     private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
 
     /**
+     * Package name for Settings.
+     */
+    private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+    /**
      * Extra for use with {@link #ACTION_CHOOSER}
      * @hide Also used by KeyChainActivity implementation
      */
@@ -202,6 +209,20 @@
     public static final String EXTRA_PKCS12 = "PKCS12";
 
     /**
+     * Extra used by {@link #createManageCredentialsIntent(AppUriAuthenticationPolicy)} to specify
+     * the authentication policy of the credential management app.
+     *
+     * <p>The authentication policy declares which alias for a private key and certificate pair
+     * should be used for authentication, given a list of apps and URIs.
+     *
+     * <p>The extra value should be a {@link AppUriAuthenticationPolicy}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_AUTHENTICATION_POLICY =
+            "android.security.extra.AUTHENTICATION_POLICY";
+
+    /**
      * Broadcast Action: Indicates the trusted storage has changed. Sent when
      * one of this happens:
      *
@@ -386,6 +407,23 @@
     }
 
     /**
+     * Returns an {@code Intent} that should be used by an app to request to manage the user's
+     * credentials. This is limited to unmanaged devices. The authentication policy must be
+     * provided to be able to make this request successfully.
+     *
+     * @param policy The authentication policy determines which alias for a private key and
+     *               certificate pair should be used for authentication.
+     */
+    @NonNull
+    public static Intent createManageCredentialsIntent(@NonNull AppUriAuthenticationPolicy policy) {
+        Intent intent = new Intent(ACTION_MANAGE_CREDENTIALS);
+        intent.setComponent(ComponentName.createRelative(SETTINGS_PACKAGE,
+                ".security.RequestManageCredentials"));
+        intent.putExtra(EXTRA_AUTHENTICATION_POLICY, policy);
+        return intent;
+    }
+
+    /**
      * Launches an {@code Activity} for the user to select the alias
      * for a private key and certificate pair for authentication. The
      * selected alias or null will be returned via the
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index e19d88c..198df40 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -996,7 +996,7 @@
      */
     public int addAuthToken(byte[] authToken) {
         try {
-            new Authorization().addAuthToken(authToken);
+            Authorization.addAuthToken(authToken);
             return mBinder.addAuthToken(authToken);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index f7477bf..476e4d7 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -107,7 +107,6 @@
             try {
                 return request.execute(service);
             } catch (ServiceSpecificException e) {
-                Log.e(TAG, "KeyStore exception", e);
                 throw getKeyStoreException(e.errorCode);
             } catch (RemoteException e) {
                 if (firstTry) {
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 372add9..d188b65 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -190,7 +190,7 @@
         keyDescriptor.blob = wrappedKey;
         keyDescriptor.domain = wrappedKeyDescriptor.domain;
 
-        return handleExceptions(() -> mSecurityLevel.importWrappedKey(wrappedKeyDescriptor,
+        return handleExceptions(() -> mSecurityLevel.importWrappedKey(keyDescriptor,
                 wrappingKeyDescriptor, maskingKey,
                 args.toArray(new KeyParameter[args.size()]), authenticatorSpecs));
     }
diff --git a/keystore/java/android/security/UrisToAliases.java b/keystore/java/android/security/UrisToAliases.java
new file mode 100644
index 0000000..65d433a
--- /dev/null
+++ b/keystore/java/android/security/UrisToAliases.java
@@ -0,0 +1,138 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The mapping from URI to alias, which determines the alias to use when the user visits a URI.
+ * This mapping is part of the {@link AppUriAuthenticationPolicy}, which specifies which app this
+ * mapping should be used for.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public final class UrisToAliases implements Parcelable {
+
+    private static final String KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS =
+            "authentication_policy_uri_to_alias";
+    private static final String KEY_AUTHENTICATION_POLICY_URI = "policy_uri";
+    private static final String KEY_AUTHENTICATION_POLICY_ALIAS = "policy_alias";
+
+    /**
+     * The mappings from URIs to aliases, which will be used for authentication.
+     */
+    @NonNull
+    private final Map<Uri, String> mUrisToAliases;
+
+    public UrisToAliases() {
+        this.mUrisToAliases = new HashMap<>();
+    }
+
+    private UrisToAliases(@NonNull Map<Uri, String> urisToAliases) {
+        this.mUrisToAliases = urisToAliases;
+    }
+
+    @NonNull
+    public static final Creator<UrisToAliases> CREATOR = new Creator<UrisToAliases>() {
+        @Override
+        public UrisToAliases createFromParcel(Parcel in) {
+            Map<Uri, String> urisToAliases = new HashMap<>();
+            in.readMap(urisToAliases, String.class.getClassLoader());
+            return new UrisToAliases(urisToAliases);
+        }
+
+        @Override
+        public UrisToAliases[] newArray(int size) {
+            return new UrisToAliases[size];
+        }
+    };
+
+    /**
+     * Returns the mapping from URIs to aliases.
+     */
+    @NonNull
+    public Map<Uri, String> getUrisToAliases() {
+        return Collections.unmodifiableMap(mUrisToAliases);
+    }
+
+    /**
+     * Adds mapping from an URI to an alias.
+     */
+    public void addUriToAlias(@NonNull Uri uri, @NonNull String alias) {
+        mUrisToAliases.put(uri, alias);
+    }
+
+    /**
+     * Restore a previously saved {@link UrisToAliases} from XML.
+     */
+    @Nullable
+    public static UrisToAliases readFromXml(@NonNull XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        Map<Uri, String> urisToAliases = new HashMap<>();
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS)) {
+                continue;
+            }
+            Uri uri = Uri.parse(parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_URI));
+            String alias = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_ALIAS);
+            urisToAliases.put(uri, alias);
+        }
+        return new UrisToAliases(urisToAliases);
+    }
+
+    /**
+     * Save the {@link UrisToAliases} to XML.
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        for (Map.Entry<Uri, String> urisToAliases : mUrisToAliases.entrySet()) {
+            out.startTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_URI, urisToAliases.getKey().toString());
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_ALIAS, urisToAliases.getValue());
+            out.endTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeMap(mUrisToAliases);
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 334b111..988838b 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -17,6 +17,7 @@
 package android.security.keystore;
 
 import android.annotation.Nullable;
+import android.content.Context;
 import android.os.Build;
 import android.security.Credentials;
 import android.security.KeyPairGeneratorSpec;
@@ -25,6 +26,8 @@
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keymaster.KeymasterDefs;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 
 import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
 import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
@@ -477,11 +480,11 @@
 
             success = true;
             return keyPair;
-        } catch (ProviderException e) {
+        } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
           if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
               throw new SecureKeyImportUnavailableException(e);
           } else {
-              throw e;
+                throw new ProviderException(e);
           }
         } finally {
             if (!success) {
@@ -491,7 +494,7 @@
     }
 
     private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
-            throws ProviderException {
+            throws ProviderException, DeviceIdAttestationException {
         byte[] challenge = mSpec.getAttestationChallenge();
         if (challenge != null) {
             KeymasterArguments args = new KeymasterArguments();
@@ -510,6 +513,60 @@
                         Build.MODEL.getBytes(StandardCharsets.UTF_8));
             }
 
+            int[] idTypes = mSpec.getAttestationIds();
+            if (idTypes != null) {
+                final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
+                for (int idType : idTypes) {
+                    idTypesSet.add(idType);
+                }
+                TelephonyManager telephonyService = null;
+                if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
+                        || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
+                    telephonyService =
+                            (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
+                                    Context.TELEPHONY_SERVICE);
+                    if (telephonyService == null) {
+                        throw new DeviceIdAttestationException(
+                                "Unable to access telephony service");
+                    }
+                }
+                for (final Integer idType : idTypesSet) {
+                    switch (idType) {
+                        case AttestationUtils.ID_TYPE_SERIAL:
+                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
+                                    Build.getSerial().getBytes(StandardCharsets.UTF_8)
+                            );
+                            break;
+                        case AttestationUtils.ID_TYPE_IMEI: {
+                            final String imei = telephonyService.getImei(0);
+                            if (imei == null) {
+                                throw new DeviceIdAttestationException("Unable to retrieve IMEI");
+                            }
+                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
+                                    imei.getBytes(StandardCharsets.UTF_8)
+                            );
+                            break;
+                        }
+                        case AttestationUtils.ID_TYPE_MEID: {
+                            final String meid = telephonyService.getMeid(0);
+                            if (meid == null) {
+                                throw new DeviceIdAttestationException("Unable to retrieve MEID");
+                            }
+                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
+                                    meid.getBytes(StandardCharsets.UTF_8)
+                            );
+                            break;
+                        }
+                        case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
+                            args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
+                            break;
+                        }
+                        default:
+                            throw new IllegalArgumentException("Unknown device ID type " + idType);
+                    }
+                }
+            }
+
             return getAttestationChain(privateKeyAlias, keyPair, args);
         }
 
@@ -547,7 +604,8 @@
         }
     }
 
-    private KeymasterArguments constructKeyGenerationArguments() {
+    private KeymasterArguments constructKeyGenerationArguments()
+            throws IllegalArgumentException, DeviceIdAttestationException {
         KeymasterArguments args = new KeymasterArguments();
         args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
         args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
@@ -565,9 +623,9 @@
                 mSpec.getKeyValidityForConsumptionEnd());
         addAlgorithmSpecificParameters(args);
 
-        if (mSpec.isUniqueIdIncluded())
+        if (mSpec.isUniqueIdIncluded()) {
             args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
-
+        }
         return args;
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index b1b6306..0871517 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -23,7 +23,6 @@
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
-import android.sysprop.Keystore2Properties;
 
 import java.io.IOException;
 import java.security.KeyFactory;
@@ -117,8 +116,6 @@
         putSecretKeyFactoryImpl("HmacSHA512");
     }
 
-    private static boolean sKeystore2Enabled;
-
     /**
      * This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
      * Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
@@ -133,10 +130,9 @@
      * @hide
      */
     public static boolean isKeystore2Enabled() {
-        return sKeystore2Enabled;
+        return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
     }
 
-
     /**
      * Installs a new instance of this provider (and the
      * {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -164,11 +160,6 @@
             // priority.
             Security.addProvider(workaroundProvider);
         }
-
-        // {@code install()} is run by zygote when this property is still accessible. We store its
-        // value so that the Keystore SPI can act accordingly without having to access an internal
-        // property.
-        sKeystore2Enabled = Keystore2Properties.keystore2_enabled().orElse(false);
     }
 
     private void putSecretKeyFactoryImpl(String algorithm) {
@@ -443,14 +434,16 @@
     @NonNull
     public static java.security.KeyStore getKeyStoreForUid(int uid)
             throws KeyStoreException, NoSuchProviderException {
-        String providerName = PROVIDER_NAME;
+        final java.security.KeyStore.LoadStoreParameter loadParameter;
         if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
-            providerName = "AndroidKeyStoreLegacy";
+            loadParameter = new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
+                    KeyProperties.legacyUidToNamespace(uid));
+        } else {
+            loadParameter = new AndroidKeyStoreLoadStoreParameter(uid);
         }
-        java.security.KeyStore result =
-                java.security.KeyStore.getInstance(providerName);
+        java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
         try {
-            result.load(new AndroidKeyStoreLoadStoreParameter(uid));
+            result.load(loadParameter);
         } catch (NoSuchAlgorithmException | CertificateException | IOException e) {
             throw new KeyStoreException(
                     "Failed to load AndroidKeyStore KeyStore for UID " + uid, e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 3694d63..d2678c7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -215,7 +215,8 @@
                 // Keystore 1.0 does not tell us the exact security level of the key
                 // so we report an unknown but secure security level.
                 insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
-                        : KeyProperties.SECURITY_LEVEL_SOFTWARE);
+                        : KeyProperties.SECURITY_LEVEL_SOFTWARE,
+                KeyProperties.UNRESTRICTED_USAGE_COUNT);
     }
 
     private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java
index c8c1de4..f22b604 100644
--- a/keystore/java/android/security/keystore/ArrayUtils.java
+++ b/keystore/java/android/security/keystore/ArrayUtils.java
@@ -34,6 +34,14 @@
         return ((array != null) && (array.length > 0)) ? array.clone() : array;
     }
 
+    /**
+     * Clones an array if it is not null and has a length greater than 0. Otherwise, returns the
+     * array.
+     */
+    public static int[] cloneIfNotEmpty(int[] array) {
+        return ((array != null) && (array.length > 0)) ? array.clone() : array;
+    }
+
     public static byte[] cloneIfNotEmpty(byte[] array) {
         return ((array != null) && (array.length > 0)) ? array.clone() : array;
     }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index e9aac7d..c79c12c 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -236,10 +236,51 @@
  * keyStore.load(null);
  * key = (SecretKey) keyStore.getKey("key2", null);
  * }</pre>
+ *
+ * <p><h3 id="example:ecdh">Example: EC key for ECDH key agreement</h3>
+ * This example illustrates how to generate an elliptic curve key pair, used to establish a shared
+ * secret with another party using ECDH key agreement.
+ * <pre> {@code
+ * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
+ *         KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ * keyPairGenerator.initialize(
+ *         new KeyGenParameterSpec.Builder(
+ *             "eckeypair",
+ *             KeyProperties.PURPOSE_AGREE_KEY)
+ *             .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ *             .build());
+ * KeyPair myKeyPair = keyPairGenerator.generateKeyPair();
+ *
+ * // Exchange public keys with server. A new ephemeral key MUST be used for every message.
+ * PublicKey serverEphemeralPublicKey; // Ephemeral key received from server.
+ *
+ * // Create a shared secret based on our private key and the other party's public key.
+ * KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "AndroidKeyStore");
+ * keyAgreement.init(myKeyPair.getPrivate());
+ * keyAgreement.doPhase(serverEphemeralPublicKey, true);
+ * byte[] sharedSecret = keyAgreement.generateSecret();
+ *
+ * // sharedSecret cannot safely be used as a key yet. We must run it through a key derivation
+ * // function with some other data: "salt" and "info". Salt is an optional random value,
+ * // omitted in this example. It's good practice to include both public keys and any other
+ * // key negotiation data in info. Here we use the public keys and a label that indicates
+ * // messages encrypted with this key are coming from the server.
+ * byte[] salt = {};
+ * ByteArrayOutputStream info = new ByteArrayOutputStream();
+ * info.write("ECDH secp256r1 AES-256-GCM-SIV\0".getBytes(StandardCharsets.UTF_8));
+ * info.write(myKeyPair.getPublic().getEncoded());
+ * info.write(serverEphemeralPublicKey.getEncoded());
+ *
+ * // This example uses the Tink library and the HKDF key derivation function.
+ * AesGcmSiv key = new AesGcmSiv(Hkdf.computeHkdf(
+ *         "HMACSHA256", sharedSecret, salt, info.toByteArray(), 32));
+ * byte[] associatedData = {};
+ * return key.decrypt(ciphertext, associatedData);
+ * }
  */
 public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
-
-    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final X500Principal DEFAULT_CERT_SUBJECT =
+            new X500Principal("CN=Android Keystore Key");
     private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
     private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
     private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
@@ -267,6 +308,7 @@
     private final boolean mUserPresenceRequired;
     private final byte[] mAttestationChallenge;
     private final boolean mDevicePropertiesAttestationIncluded;
+    private final int[] mAttestationIds;
     private final boolean mUniqueIdIncluded;
     private final boolean mUserAuthenticationValidWhileOnBody;
     private final boolean mInvalidatedByBiometricEnrollment;
@@ -274,6 +316,8 @@
     private final boolean mUserConfirmationRequired;
     private final boolean mUnlockedDeviceRequired;
     private final boolean mCriticalToDeviceEncryption;
+    private final int mMaxUsageCount;
+    private final String mAttestKeyAlias;
     /*
      * ***NOTE***: All new fields MUST also be added to the following:
      * ParcelableKeyGenParameterSpec class.
@@ -307,13 +351,16 @@
             boolean userPresenceRequired,
             byte[] attestationChallenge,
             boolean devicePropertiesAttestationIncluded,
+            int[] attestationIds,
             boolean uniqueIdIncluded,
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             boolean isStrongBoxBacked,
             boolean userConfirmationRequired,
             boolean unlockedDeviceRequired,
-            boolean criticalToDeviceEncryption) {
+            boolean criticalToDeviceEncryption,
+            int maxUsageCount,
+            String attestKeyAlias) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -359,6 +406,7 @@
         mUserAuthenticationType = userAuthenticationType;
         mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
         mDevicePropertiesAttestationIncluded = devicePropertiesAttestationIncluded;
+        mAttestationIds = attestationIds;
         mUniqueIdIncluded = uniqueIdIncluded;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
@@ -366,6 +414,8 @@
         mUserConfirmationRequired = userConfirmationRequired;
         mUnlockedDeviceRequired = unlockedDeviceRequired;
         mCriticalToDeviceEncryption = criticalToDeviceEncryption;
+        mMaxUsageCount = maxUsageCount;
+        mAttestKeyAlias = attestKeyAlias;
     }
 
     /**
@@ -717,6 +767,25 @@
     }
 
     /**
+     * @hide
+     * Allows the caller to specify device IDs to be attested to in the certificate for the
+     * generated key pair. These values are the enums specified in
+     * {@link android.security.keystore.AttestationUtils}
+     *
+     * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
+     * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
+     * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
+     * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
+     *
+     * @return integer array representing the requested device IDs to attest.
+     */
+    @SystemApi
+    @Nullable
+    public int[] getAttestationIds() {
+        return Utils.cloneIfNotNull(mAttestationIds);
+    }
+
+    /**
      * @hide This is a system-only API
      *
      * Returns {@code true} if the attestation certificate will contain a unique ID field.
@@ -782,7 +851,7 @@
     }
 
     /**
-     * Return whether this key is critical to the device encryption flow.
+     * Returns whether this key is critical to the device encryption flow.
      *
      * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
      * @hide
@@ -792,6 +861,29 @@
     }
 
     /**
+     * Returns the maximum number of times the limited use key is allowed to be used or
+     * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
+     * times the key can be used.
+     *
+     * @see Builder#setMaxUsageCount(int)
+     */
+    public int getMaxUsageCount() {
+        return mMaxUsageCount;
+    }
+
+    /**
+     * Returns the alias of the attestation key that will be used to sign the attestation
+     * certificate of the generated key.  Note that an attestation certificate will only be
+     * generated if an attestation challenge is set.
+     *
+     * @see Builder#setAttestKeyAlias(String)
+     */
+    @Nullable
+    public String getAttestKeyAlias() {
+        return mAttestKeyAlias;
+    }
+
+    /**
      * Builder of {@link KeyGenParameterSpec} instances.
      */
     public final static class Builder {
@@ -820,6 +912,7 @@
         private boolean mUserPresenceRequired = false;
         private byte[] mAttestationChallenge = null;
         private boolean mDevicePropertiesAttestationIncluded = false;
+        private int[] mAttestationIds = null;
         private boolean mUniqueIdIncluded = false;
         private boolean mUserAuthenticationValidWhileOnBody;
         private boolean mInvalidatedByBiometricEnrollment = true;
@@ -827,6 +920,8 @@
         private boolean mUserConfirmationRequired;
         private boolean mUnlockedDeviceRequired = false;
         private boolean mCriticalToDeviceEncryption = false;
+        private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
+        private String mAttestKeyAlias = null;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -887,6 +982,7 @@
             mAttestationChallenge = sourceSpec.getAttestationChallenge();
             mDevicePropertiesAttestationIncluded =
                     sourceSpec.isDevicePropertiesAttestationIncluded();
+            mAttestationIds = sourceSpec.getAttestationIds();
             mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
             mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
             mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment();
@@ -894,6 +990,8 @@
             mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
             mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
             mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();
+            mMaxUsageCount = sourceSpec.getMaxUsageCount();
+            mAttestKeyAlias = sourceSpec.getAttestKeyAlias();
         }
 
         /**
@@ -1457,6 +1555,26 @@
         }
 
         /**
+         * @hide
+         * Sets which IDs to attest in the attestation certificate for the key. The acceptable
+         * values in this integer array are the enums specified in
+         * {@link android.security.keystore.AttestationUtils}
+         *
+         * @param attestationIds the array of ID types to attest to in the certificate.
+         *
+         * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
+         * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
+         * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
+         * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
+         */
+        @SystemApi
+        @NonNull
+        public Builder setAttestationIds(@NonNull int[] attestationIds) {
+            mAttestationIds = attestationIds;
+            return this;
+        }
+
+        /**
          * @hide Only system apps can use this method.
          *
          * Sets whether to include a temporary unique ID field in the attestation certificate.
@@ -1553,6 +1671,69 @@
         }
 
         /**
+         * Sets the maximum number of times the key is allowed to be used. After every use of the
+         * key, the use counter will decrease. This authorization applies only to secret key and
+         * private key operations. Public key operations are not restricted. For example, after
+         * successfully encrypting and decrypting data using methods such as
+         * {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
+         * successfully signing data using methods such as {@link Signature#sign()}, the use
+         * counter of the private key will decrease.
+         *
+         * When the use counter is depleted, the key will be marked for deletion by Android
+         * Keystore and any subsequent attempt to use the key will throw
+         * {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
+         * Android Keystore once the exhausted key is permanently deleted, as if the key never
+         * existed before.
+         *
+         * <p>By default, there is no restriction on the usage of key.
+         *
+         * <p>Some secure hardware may not support this feature at all, in which case it will
+         * be enforced in software, some secure hardware may support it but only with
+         * maxUsageCount = 1, and some secure hardware may support it with larger value
+         * of maxUsageCount.
+         *
+         * <p>The PackageManger feature flags:
+         * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
+         * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
+         * to check whether the secure hardware cannot enforce this feature, can only enforce it
+         * with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
+         *
+         * @param maxUsageCount maximum number of times the key is allowed to be used or
+         *        {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
+         *        usage.
+         */
+        @NonNull
+        public Builder setMaxUsageCount(int maxUsageCount) {
+            if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
+                mMaxUsageCount = maxUsageCount;
+                return this;
+            }
+            throw new IllegalArgumentException("maxUsageCount is not valid");
+        }
+
+        /**
+         * Sets the alias of the attestation key that will be used to sign the attestation
+         * certificate for the generated key pair, if an attestation challenge is set with {@link
+         * #setAttestationChallenge}.  If an attestKeyAlias is set but no challenge, {@link
+         * java.security.KeyPairGenerator#initialize} will throw {@link
+         * java.security.InvalidAlgorithmParameterException}.
+         *
+         * <p>If the attestKeyAlias is set to null (the default), Android Keystore will select an
+         * appropriate system-provided attestation signing key.  If not null, the alias must
+         * reference an Android Keystore Key that was created with {@link
+         * android.security.keystore.KeyProperties#PURPOSE_ATTEST_KEY}, or key generation will throw
+         * {@link java.security.InvalidAlgorithmParameterException}.
+         *
+         * @param attestKeyAlias the alias of the attestation key to be used to sign the
+         *        attestation certificate.
+         */
+        @NonNull
+        public Builder setAttestKeyAlias(@Nullable String attestKeyAlias) {
+            mAttestKeyAlias = attestKeyAlias;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1581,13 +1762,16 @@
                     mUserPresenceRequired,
                     mAttestationChallenge,
                     mDevicePropertiesAttestationIncluded,
+                    mAttestationIds,
                     mUniqueIdIncluded,
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
                     mIsStrongBoxBacked,
                     mUserConfirmationRequired,
                     mUnlockedDeviceRequired,
-                    mCriticalToDeviceEncryption);
+                    mCriticalToDeviceEncryption,
+                    mMaxUsageCount,
+                    mAttestKeyAlias);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index 7158d0c..f50efd2 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -85,6 +85,7 @@
     private final boolean mInvalidatedByBiometricEnrollment;
     private final boolean mUserConfirmationRequired;
     private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
+    private final int mRemainingUsageCount;
 
     /**
      * @hide
@@ -109,7 +110,8 @@
             boolean trustedUserPresenceRequired,
             boolean invalidatedByBiometricEnrollment,
             boolean userConfirmationRequired,
-            @KeyProperties.SecurityLevelEnum int securityLevel) {
+            @KeyProperties.SecurityLevelEnum int securityLevel,
+            int remainingUsageCount) {
         mKeystoreAlias = keystoreKeyAlias;
         mInsideSecureHardware = insideSecureHardware;
         mOrigin = origin;
@@ -134,6 +136,7 @@
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mUserConfirmationRequired = userConfirmationRequired;
         mSecurityLevel = securityLevel;
+        mRemainingUsageCount = remainingUsageCount;
     }
 
     /**
@@ -374,4 +377,15 @@
     public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
         return mSecurityLevel;
     }
+
+    /**
+     * Returns the remaining number of times the key is allowed to be used or
+     * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there's no restriction on the number of
+     * times the key can be used. Note that this gives a best effort count and need not be
+     * accurate (as there might be usages happening in parallel and the count maintained here need
+     * not be in sync with the usage).
+     */
+    public int getRemainingUsageCount() {
+        return mRemainingUsageCount;
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 014d688..7b0fa91 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -20,6 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.annotation.SystemApi;
+import android.os.Process;
 import android.security.KeyStore;
 import android.security.keymaster.KeymasterDefs;
 
@@ -68,6 +70,7 @@
             PURPOSE_VERIFY,
             PURPOSE_WRAP_KEY,
             PURPOSE_AGREE_KEY,
+            PURPOSE_ATTEST_KEY,
     })
     public @interface PurposeEnum {}
 
@@ -98,10 +101,26 @@
 
     /**
      * Purpose of key: creating a shared ECDH secret through key agreement.
+     *
+     * <p>A key having this purpose can be combined with the elliptic curve public key of another
+     * party to establish a shared secret over an insecure channel. It should be used  as a
+     * parameter to {@link javax.crypto.KeyAgreement#init(java.security.Key)} (a complete example is
+     * available <a
+     * href="{@docRoot}reference/android/security/keystore/KeyGenParameterSpec#example:ecdh"
+     * >here</a>).
+     * See <a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman">this
+     * article</a> for a more detailed explanation.
      */
     public static final int PURPOSE_AGREE_KEY = 1 << 6;
 
     /**
+     * Purpose of key: Signing attestaions. This purpose is incompatible with all others, meaning
+     * that when generating a key with PURPOSE_ATTEST_KEY, no other purposes may be specified. In
+     * addition, PURPOSE_ATTEST_KEY may not be specified for imported keys.
+     */
+    public static final int PURPOSE_ATTEST_KEY = 1 << 7;
+
+    /**
      * @hide
      */
     public static abstract class Purpose {
@@ -121,6 +140,8 @@
                     return KeymasterDefs.KM_PURPOSE_WRAP;
                 case PURPOSE_AGREE_KEY:
                     return KeymasterDefs.KM_PURPOSE_AGREE_KEY;
+                case PURPOSE_ATTEST_KEY:
+                    return KeymasterDefs.KM_PURPOSE_ATTEST_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
@@ -140,6 +161,8 @@
                     return PURPOSE_WRAP_KEY;
                 case KeymasterDefs.KM_PURPOSE_AGREE_KEY:
                     return PURPOSE_AGREE_KEY;
+                case KeymasterDefs.KM_PURPOSE_ATTEST_KEY:
+                    return PURPOSE_ATTEST_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
@@ -874,9 +897,18 @@
      * which it must be configured in SEPolicy.
      * @hide
      */
+    @SystemApi
     public static final int NAMESPACE_APPLICATION = -1;
 
     /**
+     * The namespace identifier for the WIFI Keystore namespace.
+     * This must be kept in sync with system/sepolicy/private/keystore2_key_contexts
+     * @hide
+     */
+    @SystemApi
+    public static final int NAMESPACE_WIFI = 102;
+
+    /**
      * For legacy support, translate namespaces into known UIDs.
      * @hide
      */
@@ -884,6 +916,8 @@
         switch (namespace) {
             case NAMESPACE_APPLICATION:
                 return KeyStore.UID_SELF;
+            case NAMESPACE_WIFI:
+                return Process.WIFI_UID;
             // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
             //  b/171305388 and b/171305607
             default:
@@ -900,6 +934,8 @@
         switch (uid) {
             case KeyStore.UID_SELF:
                 return NAMESPACE_APPLICATION;
+            case Process.WIFI_UID:
+                return NAMESPACE_WIFI;
             // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
             //  b/171305388 and b/171305607
             default:
@@ -907,4 +943,9 @@
                         + uid);
         }
     }
+
+    /**
+     * This value indicates that there is no restriction on the number of times the key can be used.
+     */
+    public static final int UNRESTRICTED_USAGE_COUNT = -1;
 }
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 2e793de..673491e 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -235,6 +235,7 @@
     private final boolean mUserConfirmationRequired;
     private final boolean mUnlockedDeviceRequired;
     private final boolean mIsStrongBoxBacked;
+    private final int mMaxUsageCount;
 
     private KeyProtection(
             Date keyValidityStart,
@@ -256,7 +257,8 @@
             boolean criticalToDeviceEncryption,
             boolean userConfirmationRequired,
             boolean unlockedDeviceRequired,
-            boolean isStrongBoxBacked) {
+            boolean isStrongBoxBacked,
+            int maxUsageCount) {
         mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
         mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
         mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -279,6 +281,7 @@
         mUserConfirmationRequired = userConfirmationRequired;
         mUnlockedDeviceRequired = unlockedDeviceRequired;
         mIsStrongBoxBacked = isStrongBoxBacked;
+        mMaxUsageCount = maxUsageCount;
     }
 
     /**
@@ -548,6 +551,17 @@
     }
 
     /**
+     * Returns the maximum number of times the limited use key is allowed to be used or
+     * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
+     * times the key can be used.
+     *
+     * @see Builder#setMaxUsageCount(int)
+     */
+    public int getMaxUsageCount() {
+        return mMaxUsageCount;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -574,6 +588,8 @@
         private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
         private boolean mCriticalToDeviceEncryption = false;
         private boolean mIsStrongBoxBacked = false;
+        private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
+        private String mAttestKeyAlias = null;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -1040,6 +1056,47 @@
         }
 
         /**
+         * Sets the maximum number of times the key is allowed to be used. After every use of the
+         * key, the use counter will decrease. This authorization applies only to secret key and
+         * private key operations. Public key operations are not restricted. For example, after
+         * successfully encrypting and decrypting data using methods such as
+         * {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
+         * successfully signing data using methods such as {@link Signature#sign()}, the use
+         * counter of the private key will decrease.
+         *
+         * When the use counter is depleted, the key will be marked for deletion by Android
+         * Keystore and any subsequent attempt to use the key will throw
+         * {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
+         * Android Keystore once the exhausted key is permanently deleted, as if the key never
+         * existed before.
+         *
+         * <p>By default, there is no restriction on the usage of key.
+         *
+         * <p>Some secure hardware may not support this feature at all, in which case it will
+         * be enforced in software, some secure hardware may support it but only with
+         * maxUsageCount = 1, and some secure hardware may support it with larger value
+         * of maxUsageCount.
+         *
+         * <p>The PackageManger feature flags:
+         * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
+         * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
+         * to check whether the secure hardware cannot enforce this feature, can only enforce it
+         * with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
+         *
+         * @param maxUsageCount maximum number of times the key is allowed to be used or
+         *        {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
+         *        usage.
+         */
+        @NonNull
+        public Builder setMaxUsageCount(int maxUsageCount) {
+            if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
+                mMaxUsageCount = maxUsageCount;
+                return this;
+            }
+            throw new IllegalArgumentException("maxUsageCount is not valid");
+        }
+
+        /**
          * Builds an instance of {@link KeyProtection}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -1066,7 +1123,8 @@
                     mCriticalToDeviceEncryption,
                     mUserConfirmationRequired,
                     mUnlockedDeviceRequired,
-                    mIsStrongBoxBacked);
+                    mIsStrongBoxBacked,
+                    mMaxUsageCount);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index 69c15cc..a6e3366 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -59,7 +59,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mSpec.getKeystoreAlias());
         out.writeInt(mSpec.getPurposes());
-        out.writeInt(mSpec.getUid());
+        out.writeInt(mSpec.getNamespace());
         out.writeInt(mSpec.getKeySize());
 
         // Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec.
@@ -101,6 +101,7 @@
         out.writeBoolean(mSpec.isUserPresenceRequired());
         out.writeByteArray(mSpec.getAttestationChallenge());
         out.writeBoolean(mSpec.isDevicePropertiesAttestationIncluded());
+        out.writeIntArray(mSpec.getAttestationIds());
         out.writeBoolean(mSpec.isUniqueIdIncluded());
         out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
         out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
@@ -108,6 +109,8 @@
         out.writeBoolean(mSpec.isUserConfirmationRequired());
         out.writeBoolean(mSpec.isUnlockedDeviceRequired());
         out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
+        out.writeInt(mSpec.getMaxUsageCount());
+        out.writeString(mSpec.getAttestKeyAlias());
     }
 
     private static Date readDateOrNull(Parcel in) {
@@ -122,7 +125,7 @@
     private ParcelableKeyGenParameterSpec(Parcel in) {
         final String keystoreAlias = in.readString();
         final int purposes = in.readInt();
-        final int uid = in.readInt();
+        final int namespace = in.readInt();
         final int keySize = in.readInt();
 
         final int keySpecType = in.readInt();
@@ -159,6 +162,7 @@
         final boolean userPresenceRequired = in.readBoolean();
         final byte[] attestationChallenge = in.createByteArray();
         final boolean devicePropertiesAttestationIncluded = in.readBoolean();
+        final int[] attestationIds = in.createIntArray();
         final boolean uniqueIdIncluded = in.readBoolean();
         final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
         final boolean invalidatedByBiometricEnrollment = in.readBoolean();
@@ -166,12 +170,14 @@
         final boolean userConfirmationRequired = in.readBoolean();
         final boolean unlockedDeviceRequired = in.readBoolean();
         final boolean criticalToDeviceEncryption = in.readBoolean();
+        final int maxUsageCount = in.readInt();
+        final String attestKeyAlias = in.readString();
         // The KeyGenParameterSpec is intentionally not constructed using a Builder here:
         // The intention is for this class to break if new parameters are added to the
         // KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
         mSpec = new KeyGenParameterSpec(
                 keystoreAlias,
-                uid,
+                namespace,
                 keySize,
                 algorithmSpec,
                 certificateSubject,
@@ -193,13 +199,16 @@
                 userPresenceRequired,
                 attestationChallenge,
                 devicePropertiesAttestationIncluded,
+                attestationIds,
                 uniqueIdIncluded,
                 userAuthenticationValidWhileOnBody,
                 invalidatedByBiometricEnrollment,
                 isStrongBoxBacked,
                 userConfirmationRequired,
                 unlockedDeviceRequired,
-                criticalToDeviceEncryption);
+                criticalToDeviceEncryption,
+                maxUsageCount,
+                attestKeyAlias);
     }
 
     public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
index 5722c7b..e58b1cc 100644
--- a/keystore/java/android/security/keystore/Utils.java
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -33,4 +33,8 @@
     static byte[] cloneIfNotNull(byte[] value) {
         return (value != null) ? value.clone() : null;
     }
+
+    static int[] cloneIfNotNull(int[] value) {
+        return (value != null) ? value.clone() : null;
+    }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index 8475ad9..0f77749 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -164,6 +164,9 @@
 
         List<KeyParameter> parameters = new ArrayList<>();
         parameters.add(KeyStore2ParameterUtils.makeEnum(
+                KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN
+        ));
+        parameters.add(KeyStore2ParameterUtils.makeEnum(
                 KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC
         ));
         parameters.add(KeyStore2ParameterUtils.makeEnum(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
index 32650ae..5619585 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
@@ -21,7 +21,6 @@
 import android.system.keystore2.Authorization;
 import android.system.keystore2.Domain;
 import android.system.keystore2.KeyDescriptor;
-import android.util.Log;
 
 import java.security.Key;
 
@@ -127,15 +126,6 @@
             return false;
         }
 
-        // If the key ids are equal and the class matches all the other fields cannot differ
-        // unless we have a bug.
-        if (!mAlgorithm.equals(other.mAlgorithm)
-                || !mAuthorizations.equals(other.mAuthorizations)
-                || !mDescriptor.equals(other.mDescriptor)) {
-            Log.e("AndroidKeyStoreKey", "Bug: key ids are identical, but key metadata"
-                    + "differs.");
-            return false;
-        }
         return true;
     }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 233f352..1575bb4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -366,6 +366,13 @@
             ));
         }
 
+        if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+            params.add(KeyStore2ParameterUtils.makeInt(
+                    KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+                    spec.getMaxUsageCount()
+            ));
+        }
+
         byte[] additionalEntropy =
                 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
                         mRng, (mKeySizeBits + 7) / 8);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index df0e146..e401add 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,26 +18,36 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyPurpose;
 import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Tag;
 import android.os.Build;
 import android.security.KeyPairGeneratorSpec;
+import android.security.KeyStore;
 import android.security.KeyStore2;
 import android.security.KeyStoreException;
 import android.security.KeyStoreSecurityLevel;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.ArrayUtils;
+import android.security.keystore.AttestationUtils;
+import android.security.keystore.DeviceIdAttestationException;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeymasterUtils;
 import android.security.keystore.SecureKeyImportUnavailableException;
 import android.security.keystore.StrongBoxUnavailableException;
+import android.system.keystore2.Authorization;
 import android.system.keystore2.Domain;
 import android.system.keystore2.IKeystoreSecurityLevel;
 import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyEntryResponse;
 import android.system.keystore2.KeyMetadata;
 import android.system.keystore2.ResponseCode;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 import android.util.Log;
 
 import libcore.util.EmptyArray;
@@ -55,6 +65,7 @@
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -63,6 +74,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * Provides a way to create instances of a KeyPair which will be placed in the
@@ -142,11 +154,12 @@
     private KeyGenParameterSpec mSpec;
 
     private String mEntryAlias;
-    private int mEntryUid;
+    private int mEntryNamespace;
     private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
     private int mKeymasterAlgorithm = -1;
     private int mKeySizeBits;
     private SecureRandom mRng;
+    private KeyDescriptor mAttestKeyDescriptor;
 
     private int[] mKeymasterPurposes;
     private int[] mKeymasterBlockModes;
@@ -191,83 +204,9 @@
                 // Legacy/deprecated spec
                 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
                 try {
-                    KeyGenParameterSpec.Builder specBuilder;
-                    String specKeyAlgorithm = legacySpec.getKeyType();
-                    if (specKeyAlgorithm != null) {
-                        // Spec overrides the generator's default key algorithm
-                        try {
-                            keymasterAlgorithm =
-                                    KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
-                                            specKeyAlgorithm);
-                        } catch (IllegalArgumentException e) {
-                            throw new InvalidAlgorithmParameterException(
-                                    "Invalid key type in parameters", e);
-                        }
-                    }
-                    switch (keymasterAlgorithm) {
-                        case KeymasterDefs.KM_ALGORITHM_EC:
-                            specBuilder = new KeyGenParameterSpec.Builder(
-                                    legacySpec.getKeystoreAlias(),
-                                    KeyProperties.PURPOSE_SIGN
-                                    | KeyProperties.PURPOSE_VERIFY);
-                            // Authorized to be used with any digest (including no digest).
-                            // MD5 was never offered for Android Keystore for ECDSA.
-                            specBuilder.setDigests(
-                                    KeyProperties.DIGEST_NONE,
-                                    KeyProperties.DIGEST_SHA1,
-                                    KeyProperties.DIGEST_SHA224,
-                                    KeyProperties.DIGEST_SHA256,
-                                    KeyProperties.DIGEST_SHA384,
-                                    KeyProperties.DIGEST_SHA512);
-                            break;
-                        case KeymasterDefs.KM_ALGORITHM_RSA:
-                            specBuilder = new KeyGenParameterSpec.Builder(
-                                    legacySpec.getKeystoreAlias(),
-                                    KeyProperties.PURPOSE_ENCRYPT
-                                    | KeyProperties.PURPOSE_DECRYPT
-                                    | KeyProperties.PURPOSE_SIGN
-                                    | KeyProperties.PURPOSE_VERIFY);
-                            // Authorized to be used with any digest (including no digest).
-                            specBuilder.setDigests(
-                                    KeyProperties.DIGEST_NONE,
-                                    KeyProperties.DIGEST_MD5,
-                                    KeyProperties.DIGEST_SHA1,
-                                    KeyProperties.DIGEST_SHA224,
-                                    KeyProperties.DIGEST_SHA256,
-                                    KeyProperties.DIGEST_SHA384,
-                                    KeyProperties.DIGEST_SHA512);
-                            // Authorized to be used with any encryption and signature padding
-                            // schemes (including no padding).
-                            specBuilder.setEncryptionPaddings(
-                                    KeyProperties.ENCRYPTION_PADDING_NONE,
-                                    KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
-                                    KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
-                            specBuilder.setSignaturePaddings(
-                                    KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
-                                    KeyProperties.SIGNATURE_PADDING_RSA_PSS);
-                            // Disable randomized encryption requirement to support encryption
-                            // padding NONE above.
-                            specBuilder.setRandomizedEncryptionRequired(false);
-                            break;
-                        default:
-                            throw new ProviderException(
-                                    "Unsupported algorithm: " + mKeymasterAlgorithm);
-                    }
-
-                    if (legacySpec.getKeySize() != -1) {
-                        specBuilder.setKeySize(legacySpec.getKeySize());
-                    }
-                    if (legacySpec.getAlgorithmParameterSpec() != null) {
-                        specBuilder.setAlgorithmParameterSpec(
-                                legacySpec.getAlgorithmParameterSpec());
-                    }
-                    specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
-                    specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
-                    specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
-                    specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
-                    specBuilder.setUserAuthenticationRequired(false);
-
-                    spec = specBuilder.build();
+                    keymasterAlgorithm = getKeymasterAlgorithmFromLegacy(keymasterAlgorithm,
+                            legacySpec);
+                    spec = buildKeyGenParameterSpecFromLegacy(legacySpec, keymasterAlgorithm);
                 } catch (NullPointerException | IllegalArgumentException e) {
                     throw new InvalidAlgorithmParameterException(e);
                 }
@@ -279,7 +218,7 @@
             }
 
             mEntryAlias = spec.getKeystoreAlias();
-            mEntryUid = spec.getUid();
+            mEntryNamespace = spec.getNamespace();
             mSpec = spec;
             mKeymasterAlgorithm = keymasterAlgorithm;
             mKeySizeBits = spec.getKeySize();
@@ -336,6 +275,10 @@
             mJcaKeyAlgorithm = jcaKeyAlgorithm;
             mRng = random;
             mKeyStore = KeyStore2.getInstance();
+
+            mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec);
+            checkAttestKeyPurpose(spec);
+
             success = true;
         } finally {
             if (!success) {
@@ -344,9 +287,159 @@
         }
     }
 
+    private void checkAttestKeyPurpose(KeyGenParameterSpec spec)
+            throws InvalidAlgorithmParameterException {
+        if ((spec.getPurposes() & KeyProperties.PURPOSE_ATTEST_KEY) != 0
+                && spec.getPurposes() != KeyProperties.PURPOSE_ATTEST_KEY) {
+            throw new InvalidAlgorithmParameterException(
+                    "PURPOSE_ATTEST_KEY may not be specified with any other purposes");
+        }
+    }
+
+    private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec)
+            throws InvalidAlgorithmParameterException {
+        if (spec.getAttestKeyAlias() != null) {
+            KeyDescriptor attestKeyDescriptor = new KeyDescriptor();
+            attestKeyDescriptor.domain = Domain.APP;
+            attestKeyDescriptor.alias = spec.getAttestKeyAlias();
+            try {
+                KeyEntryResponse attestKey = mKeyStore.getKeyEntry(attestKeyDescriptor);
+                checkAttestKeyChallenge(spec);
+                checkAttestKeyPurpose(attestKey.metadata.authorizations);
+                checkAttestKeySecurityLevel(spec, attestKey);
+            } catch (KeyStoreException e) {
+                throw new InvalidAlgorithmParameterException("Invalid attestKeyAlias", e);
+            }
+            return attestKeyDescriptor;
+        }
+        return null;
+    }
+
+    private void checkAttestKeyChallenge(KeyGenParameterSpec spec)
+            throws InvalidAlgorithmParameterException {
+        if (spec.getAttestationChallenge() == null) {
+            throw new InvalidAlgorithmParameterException(
+                    "AttestKey specified but no attestation challenge provided");
+        }
+    }
+
+    private void checkAttestKeyPurpose(Authorization[] keyAuths)
+            throws InvalidAlgorithmParameterException {
+        Predicate<Authorization> isAttestKeyPurpose = x -> x.keyParameter.tag == Tag.PURPOSE
+                && x.keyParameter.value.getKeyPurpose() == KeyPurpose.ATTEST_KEY;
+
+        if (Arrays.stream(keyAuths).noneMatch(isAttestKeyPurpose)) {
+            throw new InvalidAlgorithmParameterException(
+                    ("Invalid attestKey, does not have PURPOSE_ATTEST_KEY"));
+        }
+    }
+
+    private void checkAttestKeySecurityLevel(KeyGenParameterSpec spec, KeyEntryResponse key)
+            throws InvalidAlgorithmParameterException {
+        boolean attestKeyInStrongBox = key.metadata.keySecurityLevel == SecurityLevel.STRONGBOX;
+        if (spec.isStrongBoxBacked() != attestKeyInStrongBox) {
+            if (attestKeyInStrongBox) {
+                throw new InvalidAlgorithmParameterException(
+                        "Invalid security level: Cannot sign non-StrongBox key with "
+                                + "StrongBox attestKey");
+
+            } else {
+                throw new InvalidAlgorithmParameterException(
+                        "Invalid security level: Cannot sign StrongBox key with "
+                                + "non-StrongBox attestKey");
+            }
+        }
+    }
+
+    private int getKeymasterAlgorithmFromLegacy(int keymasterAlgorithm,
+            KeyPairGeneratorSpec legacySpec) throws InvalidAlgorithmParameterException {
+        String specKeyAlgorithm = legacySpec.getKeyType();
+        if (specKeyAlgorithm != null) {
+            // Spec overrides the generator's default key algorithm
+            try {
+                keymasterAlgorithm =
+                        KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
+                                specKeyAlgorithm);
+            } catch (IllegalArgumentException e) {
+                throw new InvalidAlgorithmParameterException(
+                        "Invalid key type in parameters", e);
+            }
+        }
+        return keymasterAlgorithm;
+    }
+
+    private KeyGenParameterSpec buildKeyGenParameterSpecFromLegacy(KeyPairGeneratorSpec legacySpec,
+            int keymasterAlgorithm) {
+        KeyGenParameterSpec.Builder specBuilder;
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_EC:
+                specBuilder = new KeyGenParameterSpec.Builder(
+                        legacySpec.getKeystoreAlias(),
+                        KeyProperties.PURPOSE_SIGN
+                        | KeyProperties.PURPOSE_VERIFY);
+                // Authorized to be used with any digest (including no digest).
+                // MD5 was never offered for Android Keystore for ECDSA.
+                specBuilder.setDigests(
+                        KeyProperties.DIGEST_NONE,
+                        KeyProperties.DIGEST_SHA1,
+                        KeyProperties.DIGEST_SHA224,
+                        KeyProperties.DIGEST_SHA256,
+                        KeyProperties.DIGEST_SHA384,
+                        KeyProperties.DIGEST_SHA512);
+                break;
+            case KeymasterDefs.KM_ALGORITHM_RSA:
+                specBuilder = new KeyGenParameterSpec.Builder(
+                        legacySpec.getKeystoreAlias(),
+                        KeyProperties.PURPOSE_ENCRYPT
+                        | KeyProperties.PURPOSE_DECRYPT
+                        | KeyProperties.PURPOSE_SIGN
+                        | KeyProperties.PURPOSE_VERIFY);
+                // Authorized to be used with any digest (including no digest).
+                specBuilder.setDigests(
+                        KeyProperties.DIGEST_NONE,
+                        KeyProperties.DIGEST_MD5,
+                        KeyProperties.DIGEST_SHA1,
+                        KeyProperties.DIGEST_SHA224,
+                        KeyProperties.DIGEST_SHA256,
+                        KeyProperties.DIGEST_SHA384,
+                        KeyProperties.DIGEST_SHA512);
+                // Authorized to be used with any encryption and signature padding
+                // schemes (including no padding).
+                specBuilder.setEncryptionPaddings(
+                        KeyProperties.ENCRYPTION_PADDING_NONE,
+                        KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
+                        KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
+                specBuilder.setSignaturePaddings(
+                        KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
+                        KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+                // Disable randomized encryption requirement to support encryption
+                // padding NONE above.
+                specBuilder.setRandomizedEncryptionRequired(false);
+                break;
+            default:
+                throw new ProviderException(
+                        "Unsupported algorithm: " + mKeymasterAlgorithm);
+        }
+
+        if (legacySpec.getKeySize() != -1) {
+            specBuilder.setKeySize(legacySpec.getKeySize());
+        }
+        if (legacySpec.getAlgorithmParameterSpec() != null) {
+            specBuilder.setAlgorithmParameterSpec(
+                    legacySpec.getAlgorithmParameterSpec());
+        }
+        specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
+        specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
+        specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
+        specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
+        specBuilder.setUserAuthenticationRequired(false);
+
+        return specBuilder.build();
+    }
+
     private void resetAll() {
         mEntryAlias = null;
-        mEntryUid = KeyProperties.NAMESPACE_APPLICATION;
+        mEntryNamespace = KeyProperties.NAMESPACE_APPLICATION;
         mJcaKeyAlgorithm = null;
         mKeymasterAlgorithm = -1;
         mKeymasterPurposes = null;
@@ -448,17 +541,17 @@
 
         KeyDescriptor descriptor = new KeyDescriptor();
         descriptor.alias = mEntryAlias;
-        descriptor.domain = mEntryUid == KeyProperties.NAMESPACE_APPLICATION
+        descriptor.domain = mEntryNamespace == KeyProperties.NAMESPACE_APPLICATION
                 ? Domain.APP
                 : Domain.SELINUX;
-        descriptor.nspace = mEntryUid;
+        descriptor.nspace = mEntryNamespace;
         descriptor.blob = null;
 
         boolean success = false;
         try {
             KeyStoreSecurityLevel iSecurityLevel = mKeyStore.getSecurityLevel(securityLevel);
 
-            KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, null,
+            KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, mAttestKeyDescriptor,
                     constructKeyGenerationArguments(), flags, additionalEntropy);
 
             AndroidKeyStorePublicKey publicKey =
@@ -478,7 +571,8 @@
                     }
                     throw p;
             }
-        } catch (UnrecoverableKeyException e) {
+        } catch (UnrecoverableKeyException | IllegalArgumentException
+                    | DeviceIdAttestationException e) {
             throw new ProviderException(
                     "Failed to construct key object from newly generated key pair.", e);
         } finally {
@@ -496,7 +590,7 @@
     }
 
     private void addAttestationParameters(@NonNull List<KeyParameter> params)
-            throws ProviderException {
+            throws ProviderException, IllegalArgumentException, DeviceIdAttestationException {
         byte[] challenge = mSpec.getAttestationChallenge();
 
         if (challenge != null) {
@@ -526,15 +620,69 @@
                         Build.MODEL.getBytes(StandardCharsets.UTF_8)
                 ));
             }
-        } else {
-            if (mSpec.isDevicePropertiesAttestationIncluded()) {
-                throw new ProviderException("An attestation challenge must be provided when "
-                        + "requesting device properties attestation.");
+
+            int[] idTypes = mSpec.getAttestationIds();
+            if (idTypes == null) {
+                return;
+            }
+            final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
+            for (int idType : idTypes) {
+                idTypesSet.add(idType);
+            }
+            TelephonyManager telephonyService = null;
+            if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
+                    || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
+                telephonyService =
+                    (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
+                        Context.TELEPHONY_SERVICE);
+                if (telephonyService == null) {
+                    throw new DeviceIdAttestationException("Unable to access telephony service");
+                }
+            }
+            for (final Integer idType : idTypesSet) {
+                switch (idType) {
+                    case AttestationUtils.ID_TYPE_SERIAL:
+                        params.add(KeyStore2ParameterUtils.makeBytes(
+                                KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
+                                Build.getSerial().getBytes(StandardCharsets.UTF_8)
+                        ));
+                        break;
+                    case AttestationUtils.ID_TYPE_IMEI: {
+                        final String imei = telephonyService.getImei(0);
+                        if (imei == null) {
+                            throw new DeviceIdAttestationException("Unable to retrieve IMEI");
+                        }
+                        params.add(KeyStore2ParameterUtils.makeBytes(
+                                KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
+                                imei.getBytes(StandardCharsets.UTF_8)
+                        ));
+                        break;
+                    }
+                    case AttestationUtils.ID_TYPE_MEID: {
+                        final String meid = telephonyService.getMeid(0);
+                        if (meid == null) {
+                            throw new DeviceIdAttestationException("Unable to retrieve MEID");
+                        }
+                        params.add(KeyStore2ParameterUtils.makeBytes(
+                                KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
+                                meid.getBytes(StandardCharsets.UTF_8)
+                        ));
+                        break;
+                    }
+                    case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
+                        params.add(KeyStore2ParameterUtils.makeBool(
+                                KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION));
+                        break;
+                    }
+                    default:
+                        throw new IllegalArgumentException("Unknown device ID type " + idType);
+                }
             }
         }
     }
 
-    private Collection<KeyParameter> constructKeyGenerationArguments() {
+    private Collection<KeyParameter> constructKeyGenerationArguments()
+            throws DeviceIdAttestationException, IllegalArgumentException {
         List<KeyParameter> params = new ArrayList<>();
         params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits));
         params.add(KeyStore2ParameterUtils.makeEnum(
@@ -585,6 +733,37 @@
                     mSpec.getKeyValidityForConsumptionEnd()
             ));
         }
+        if (mSpec.getCertificateNotAfter() != null) {
+            params.add(KeyStore2ParameterUtils.makeDate(
+                    KeymasterDefs.KM_TAG_CERTIFICATE_NOT_AFTER,
+                    mSpec.getCertificateNotAfter()
+            ));
+        }
+        if (mSpec.getCertificateNotBefore() != null) {
+            params.add(KeyStore2ParameterUtils.makeDate(
+                    KeymasterDefs.KM_TAG_CERTIFICATE_NOT_BEFORE,
+                    mSpec.getCertificateNotBefore()
+            ));
+        }
+        if (mSpec.getCertificateSerialNumber() != null) {
+            params.add(KeyStore2ParameterUtils.makeBignum(
+                    KeymasterDefs.KM_TAG_CERTIFICATE_SERIAL,
+                    mSpec.getCertificateSerialNumber()
+            ));
+        }
+        if (mSpec.getCertificateSubject() != null) {
+            params.add(KeyStore2ParameterUtils.makeBytes(
+                    KeymasterDefs.KM_TAG_CERTIFICATE_SUBJECT,
+                    mSpec.getCertificateSubject().getEncoded()
+            ));
+        }
+
+        if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+            params.add(KeyStore2ParameterUtils.makeInt(
+                    KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+                    mSpec.getMaxUsageCount()
+            ));
+        }
 
         addAlgorithmSpecificParameters(params);
 
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 75ac61a..e101115 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -352,14 +352,17 @@
         try {
             response = keyStore.getKeyEntry(descriptor);
         } catch (android.security.KeyStoreException e) {
-            if (e.getErrorCode() == ResponseCode.KEY_PERMANENTLY_INVALIDATED) {
-                throw new KeyPermanentlyInvalidatedException(
-                        "User changed or deleted their auth credentials",
-                        e);
-            } else {
-                throw (UnrecoverableKeyException)
-                        new UnrecoverableKeyException("Failed to obtain information about key")
-                                .initCause(e);
+            switch (e.getErrorCode()) {
+                case ResponseCode.KEY_NOT_FOUND:
+                    return null;
+                case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
+                    throw new KeyPermanentlyInvalidatedException(
+                            "User changed or deleted their auth credentials",
+                            e);
+                default:
+                    throw (UnrecoverableKeyException)
+                            new UnrecoverableKeyException("Failed to obtain information about key")
+                                    .initCause(e);
             }
         }
 
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 74503e1..fe05989 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -95,6 +95,7 @@
         boolean userAuthenticationValidWhileOnBody = false;
         boolean trustedUserPresenceRequired = false;
         boolean trustedUserConfirmationRequired = false;
+        int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
         try {
             for (Authorization a : key.getAuthorizations()) {
                 switch (a.keyParameter.tag) {
@@ -195,6 +196,16 @@
                         trustedUserConfirmationRequired =
                                 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
                         break;
+                    case KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT:
+                        long remainingUsageCountUnsigned =
+                                KeyStore2ParameterUtils.getUnsignedInt(a);
+                        if (remainingUsageCountUnsigned > Integer.MAX_VALUE) {
+                            throw new ProviderException(
+                                    "Usage count of limited use key too long: "
+                                     + remainingUsageCountUnsigned);
+                        }
+                        remainingUsageCount = (int) remainingUsageCountUnsigned;
+                        break;
                 }
             }
         } catch (IllegalArgumentException e) {
@@ -247,7 +258,8 @@
                 trustedUserPresenceRequired,
                 invalidatedByBiometricEnrollment,
                 trustedUserConfirmationRequired,
-                securityLevel);
+                securityLevel,
+                remainingUsageCount);
     }
 
     private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 07169ce..39607ae 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -535,6 +535,12 @@
                         spec.getKeyValidityForConsumptionEnd()
                 ));
             }
+            if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+                importArgs.add(KeyStore2ParameterUtils.makeInt(
+                        KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+                        spec.getMaxUsageCount()
+                ));
+            }
         } catch (IllegalArgumentException | IllegalStateException e) {
             throw new KeyStoreException(e);
         }
@@ -772,6 +778,12 @@
                         params.getKeyValidityForConsumptionEnd()
                 ));
             }
+            if (params.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+                importArgs.add(KeyStore2ParameterUtils.makeInt(
+                        KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+                        params.getMaxUsageCount()
+                ));
+            }
         } catch (IllegalArgumentException | IllegalStateException e) {
             throw new KeyStoreException(e);
         }
@@ -854,7 +866,8 @@
         try {
             response = mKeyStore.getKeyEntry(wrappingkey);
         } catch (android.security.KeyStoreException e) {
-            throw new KeyStoreException("Failed to load wrapping key.", e);
+            throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
+                    + e.getErrorCode(), e);
         }
 
         KeyDescriptor wrappedKey = makeKeyDescriptor(alias);
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 4c8ab8d..dcdd7de 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -28,6 +28,7 @@
 import android.security.keystore.UserAuthArgs;
 import android.system.keystore2.Authorization;
 
+import java.math.BigInteger;
 import java.security.ProviderException;
 import java.util.ArrayList;
 import java.util.Date;
@@ -154,6 +155,23 @@
     }
 
     /**
+     * This function constructs a {@link KeyParameter} expressing a Bignum.
+     * @param tag Must be KeyMint tag with the associated type BIGNUM.
+     * @param b A BitInteger to be stored in the new key parameter.
+     * @return An instance of {@link KeyParameter}.
+     * @hide
+     */
+    static @NonNull KeyParameter makeBignum(int tag, @NonNull BigInteger b) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BIGNUM) {
+            throw new IllegalArgumentException("Not a bignum tag: " + tag);
+        }
+        KeyParameter p = new KeyParameter();
+        p.tag = tag;
+        p.value = KeyParameterValue.blob(b.toByteArray());
+        return p;
+    }
+
+    /**
      * This function constructs a {@link KeyParameter} expressing date.
      * @param tag Must be KeyMint tag with the associated type DATE.
      * @param date A date
@@ -167,10 +185,6 @@
         KeyParameter p = new KeyParameter();
         p.tag = tag;
         p.value = KeyParameterValue.dateTime(date.getTime());
-        if (p.value.getDateTime() < 0) {
-            throw new IllegalArgumentException("Date tag value out of range: "
-                    + p.value.getDateTime());
-        }
         return p;
     }
     /**
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
index e9b22c1..2315a85 100644
--- a/keystore/tests/Android.bp
+++ b/keystore/tests/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_keystore_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_keystore_license"],
+}
+
 android_test {
     name: "KeystoreTests",
     // LOCAL_MODULE := keystore
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
index 7fbbb61..b6622bf 100644
--- a/libs/WindowManager/Jetpack/Android.bp
+++ b/libs/WindowManager/Jetpack/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_library_import {
     name: "window-sidecar",
     aars: ["window-sidecar-release.aar"],
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index b8934dc..2987dab 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/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_library {
     name: "WindowManager-Shell",
     srcs: [
diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/Android.bp
index 78fa45e..ca37ad7 100644
--- a/libs/WindowManager/Shell/tests/Android.bp
+++ b/libs/WindowManager/Shell/tests/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: "WindowManagerShellTests",
 
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 6a7df94..581af0d 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -14,6 +14,23 @@
 
 // libandroidfw is partially built for the host (used by obbtool, aapt, and others)
 
+package {
+    default_applicable_licenses: ["frameworks_base_libs_androidfw_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_libs_androidfw_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "libandroidfw_defaults",
     cflags: [
diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING
index 777aa0b..766714c 100644
--- a/libs/androidfw/TEST_MAPPING
+++ b/libs/androidfw/TEST_MAPPING
@@ -1,10 +1,6 @@
 {
   "presubmit": [
     {
-      "name": "libandroidfw_tests",
-      "host": true
-    },
-    {
       "name": "CtsResourcesLoaderTests"
     }
   ]
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
index 77ef8df..b511244 100644
--- a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/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_libs_androidfw_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_libs_androidfw_license"],
+}
+
 cc_fuzz {
     name: "resourcefile_fuzzer",
     srcs: [
diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
index e713b98..0388e92 100644
--- a/libs/hostgraphics/Android.bp
+++ b/libs/hostgraphics/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_host_static {
     name: "libhostgraphics",
 
@@ -28,4 +37,4 @@
             enabled: true,
         }
     },
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index aa842ff..6220abe 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -1,3 +1,33 @@
+package {
+    default_applicable_licenses: ["frameworks_base_libs_hwui_license"],
+}
+
+// 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_libs_hwui_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "hwui_defaults",
     defaults: [
@@ -313,12 +343,13 @@
         "libharfbuzz_ng",
         "liblog",
         "libminikin",
-        "libnativehelper",
         "libz",
         "libziparchive",
         "libjpeg",
     ],
 
+    static_libs: ["libnativehelper_lazy"],
+
     target: {
         android: {
             srcs: [ // sources that depend on android only libraries
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index d291ec0..697cbb9 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 cc_defaults {
     name: "libincidentpriv_defaults",
 
@@ -125,6 +134,3 @@
         "libgmock",
     ],
 }
-
-
-
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index dca3501..55f932d 100644
--- a/libs/input/Android.bp
+++ b/libs/input/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"],
+}
+
 cc_library_shared {
     name: "libinputservice",
     srcs: [
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 213b3ad..4eabfb2 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/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"],
+}
+
 cc_test {
     name: "libinputservice_test",
     srcs: [
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index d2b7d5c..132d71e 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -12,6 +12,15 @@
 // 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"],
+}
+
 cc_defaults {
     name: "libprotoutil_defaults",
 
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index 1e62107..bf2e764 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -14,6 +14,15 @@
 
 // Provides C++ wrappers for system services.
 
+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: "libservices",
     srcs: [
diff --git a/libs/storage/Android.bp b/libs/storage/Android.bp
index c19933e..e8c6c07 100644
--- a/libs/storage/Android.bp
+++ b/libs/storage/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_base_libs_storage_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_libs_storage_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_static {
     name: "libstorage",
 
diff --git a/libs/tracingproxy/Android.bp b/libs/tracingproxy/Android.bp
new file mode 100644
index 0000000..7126bfa
--- /dev/null
+++ b/libs/tracingproxy/Android.bp
@@ -0,0 +1,53 @@
+// 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.
+
+// Provides C++ wrappers for system services.
+
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+    name: "libtracingproxy",
+
+    aidl: {
+        export_aidl_headers: true,
+        include_dirs: [
+            "frameworks/base/core/java",
+        ],
+    },
+
+    srcs: [
+        ":ITracingServiceProxy.aidl",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/libs/usb/Android.bp b/libs/usb/Android.bp
index e752b55..edc8474 100644
--- a/libs/usb/Android.bp
+++ b/libs/usb/Android.bp
@@ -14,6 +14,16 @@
 // 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
+    //   SPDX-license-identifier-GPL-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_sdk_library {
     name: "com.android.future.usb.accessory",
     srcs: ["src/**/*.java"],
diff --git a/libs/usb/tests/AccessoryChat/Android.bp b/libs/usb/tests/AccessoryChat/Android.bp
index 19ed3d3..72090fb 100644
--- a/libs/usb/tests/AccessoryChat/Android.bp
+++ b/libs/usb/tests/AccessoryChat/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AccessoryChat",
 
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/Android.bp b/libs/usb/tests/AccessoryChat/accessorychat/Android.bp
index 5613745..108649a 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/Android.bp
+++ b/libs/usb/tests/AccessoryChat/accessorychat/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_binary {
     name: "accessorychat",
     host_supported: true,
diff --git a/libs/usb/tests/accessorytest/Android.bp b/libs/usb/tests/accessorytest/Android.bp
index c6340e3..69761ae 100644
--- a/libs/usb/tests/accessorytest/Android.bp
+++ b/libs/usb/tests/accessorytest/Android.bp
@@ -1,3 +1,13 @@
+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
+    //   SPDX-license-identifier-GPL-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 cc_binary_host {
     name: "accessorytest",
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 33c6951..ccb74eb 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1445,6 +1445,7 @@
     @TestApi
     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
     @Nullable
+    @SuppressWarnings("NullableCollection")
     public List<String> getProviderPackages(@NonNull String provider) {
         try {
             return mService.getProviderPackages(provider);
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index cd45e8e..5cd5a59 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_sdk_library {
     name: "com.android.location.provider",
     srcs: ["java/**/*.java"],
diff --git a/location/tests/locationtests/Android.bp b/location/tests/locationtests/Android.bp
index 1a4e2c7..c18ef28 100644
--- a/location/tests/locationtests/Android.bp
+++ b/location/tests/locationtests/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: "FrameworksLocationTests",
     // Include all test java files.
diff --git a/lowpan/tests/Android.bp b/lowpan/tests/Android.bp
index ad2bc27..5908929 100644
--- a/lowpan/tests/Android.bp
+++ b/lowpan/tests/Android.bp
@@ -14,6 +14,15 @@
 
 // Make test APK
 // ============================================================
+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: "FrameworksLowpanApiTests",
     srcs: ["**/*.java"],
diff --git a/media/Android.bp b/media/Android.bp
index 0ed1047..6b4c3886a 100644
--- a/media/Android.bp
+++ b/media/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"],
+}
+
 aidl_interface {
     name: "audio_common-aidl",
     unstable: true,
diff --git a/media/OWNERS b/media/OWNERS
index e741490..abfc8bf 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -26,3 +26,7 @@
 
 # SEO
 sungsoo@google.com
+
+# SEA/KIR/BVE
+jtinker@google.com
+robertshih@google.com
diff --git a/media/java/Android.bp b/media/java/Android.bp
index 0810699..aea63a0 100644
--- a/media/java/Android.bp
+++ b/media/java/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"],
+}
+
 filegroup {
     name: "IMidiDeviceServer.aidl",
     srcs: ["android/media/midi/IMidiDeviceServer.aidl"],
diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp
index c65d25a..66c7bd4 100644
--- a/media/java/android/media/tv/tunerresourcemanager/Android.bp
+++ b/media/java/android/media/tv/tunerresourcemanager/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"],
+}
+
 filegroup {
     name: "framework-media-tv-tunerresourcemanager-sources",
     srcs: [
@@ -14,4 +23,4 @@
     visibility: [
         "//frameworks/base",
     ],
-}
\ No newline at end of file
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index d346670..f65dfdd 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_base_media_jni_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_media_jni_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_shared {
     name: "libmedia_jni",
 
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 40e4c54..c2fc91d 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/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_media_jni_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_media_jni_license"],
+}
+
 cc_library_shared {
     name: "libaudioeffect_jni",
 
diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp
index 6141308..b3406cd 100644
--- a/media/jni/soundpool/Android.bp
+++ b/media/jni/soundpool/Android.bp
@@ -1,3 +1,22 @@
+package {
+    default_applicable_licenses: [
+        "frameworks_base_media_jni_soundpool_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_media_jni_soundpool_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 tidy_errors = [
     // https://clang.llvm.org/extra/clang-tidy/checks/list.html
     // For many categories, the checks are too many to specify individually.
@@ -26,26 +45,30 @@
     "modernize-return-braced-init-list",
     "modernize-shrink-to-fit",
     "modernize-unary-static-assert",
-    "modernize-use-auto",  // debatable - auto can obscure type
+    // "modernize-use-auto",  // found in StreamManager.h, debatable - auto can obscure type
     "modernize-use-bool-literals",
     "modernize-use-default-member-init",
     "modernize-use-emplace",
     "modernize-use-equals-default",
     "modernize-use-equals-delete",
-    "modernize-use-nodiscard",
+    // "modernize-use-nodiscard", // found in SteamManager.h
     "modernize-use-noexcept",
     "modernize-use-nullptr",
     "modernize-use-override",
     //"modernize-use-trailing-return-type", // not necessarily more readable
     "modernize-use-transparent-functors",
     "modernize-use-uncaught-exceptions",
-    "modernize-use-using",
+    //"modernize-use-using", // found in SoundManager.h
     "performance-*",
 
     // Remove some pedantic stylistic requirements.
     "-google-readability-casting", // C++ casts not always necessary and may be verbose
     "-google-readability-todo",    // do not require TODO(info)
     "-google-build-using-namespace", // Reenable and fix later.
+
+    "-google-explicit-constructor", // found in StreamManager.h
+    "-misc-non-private-member-variables-in-classes", // found in SoundManager.h
+    "-performance-unnecessary-value-param", // found in StreamManager.h
 ]
 
 cc_defaults {
@@ -77,8 +100,7 @@
     tidy_checks: tidy_errors,
     tidy_checks_as_errors: tidy_errors,
     tidy_flags: [
-      "-format-style='file'",
-      "--header-filter='frameworks/base/media/jni/soundpool'",
+      "-format-style=file",
     ],
 }
 
diff --git a/media/jni/soundpool/tests/Android.bp b/media/jni/soundpool/tests/Android.bp
index 52f59ed..7d31c10 100644
--- a/media/jni/soundpool/tests/Android.bp
+++ b/media/jni/soundpool/tests/Android.bp
@@ -1,3 +1,14 @@
+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_media_jni_soundpool_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_base_media_jni_soundpool_license",
+    ],
+}
+
 cc_binary {
     name: "soundpool_stress",
     host_supported: false,
diff --git a/media/lib/remotedisplay/Android.bp b/media/lib/remotedisplay/Android.bp
index 5f4b930..bfb0cb8 100644
--- a/media/lib/remotedisplay/Android.bp
+++ b/media/lib/remotedisplay/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_sdk_library {
     name: "com.android.media.remotedisplay",
     srcs: ["java/**/*.java"],
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 3b25787..6504176 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_sdk_library {
     name: "com.android.mediadrm.signer",
     srcs: ["java/**/*.java"],
diff --git a/media/lib/tvremote/Android.bp b/media/lib/tvremote/Android.bp
index 5f101a3..5f9185a 100644
--- a/media/lib/tvremote/Android.bp
+++ b/media/lib/tvremote/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_sdk_library {
     name: "com.android.media.tv.remoteprovider",
     srcs: ["java/**/*.java"],
diff --git a/media/lib/tvremote/tests/Android.bp b/media/lib/tvremote/tests/Android.bp
index f00eed0..f02cfc3 100644
--- a/media/lib/tvremote/tests/Android.bp
+++ b/media/lib/tvremote/tests/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: "TvRemoteTests",
     srcs: ["src/**/*.java"],
diff --git a/media/mca/filterfw/Android.bp b/media/mca/filterfw/Android.bp
index 0e0ecf3..ef3583f 100644
--- a/media/mca/filterfw/Android.bp
+++ b/media/mca/filterfw/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 cc_library_shared {
     name: "libfilterfw",
 
diff --git a/media/mca/filterfw/native/Android.bp b/media/mca/filterfw/native/Android.bp
index 7a8a6a1..7e4a34e 100644
--- a/media/mca/filterfw/native/Android.bp
+++ b/media/mca/filterfw/native/Android.bp
@@ -16,6 +16,15 @@
 //####################
 // Build module libfilterfw_static
 
+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_static {
     name: "libfilterfw_native",
 
diff --git a/media/mca/filterpacks/Android.bp b/media/mca/filterpacks/Android.bp
index 34fb27d..b50df6e 100644
--- a/media/mca/filterpacks/Android.bp
+++ b/media/mca/filterpacks/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 cc_library_static {
     name: "libfilterpack_base",
     srcs: [
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.bp b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
index 96e81ab..541660c 100644
--- a/media/mca/samples/CameraEffectsRecordingSample/Android.bp
+++ b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
@@ -15,6 +15,15 @@
 
 // Build activity
 
+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: "CameraEffectsRecordingSample",
     srcs: ["**/*.java"],
@@ -23,4 +32,3 @@
         enabled: false,
     },
 }
-
diff --git a/media/mca/tests/Android.bp b/media/mca/tests/Android.bp
index 6b11dd9..f02b4c0 100644
--- a/media/mca/tests/Android.bp
+++ b/media/mca/tests/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: "CameraEffectsTests",
     libs: [
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index 2da45b6..7acb8c7 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/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"],
+}
+
 cc_library_shared {
     name: "libamidi",
 
diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp
index 48fc329..5ac4e7f 100644
--- a/media/packages/BluetoothMidiService/Android.bp
+++ b/media/packages/BluetoothMidiService/Android.bp
@@ -14,6 +14,15 @@
 // 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_library {
     name: "BluetoothMidiLib",
     srcs: [
diff --git a/media/packages/BluetoothMidiService/tests/unit/Android.bp b/media/packages/BluetoothMidiService/tests/unit/Android.bp
index 4d4ae9e..ad07993 100644
--- a/media/packages/BluetoothMidiService/tests/unit/Android.bp
+++ b/media/packages/BluetoothMidiService/tests/unit/Android.bp
@@ -14,6 +14,15 @@
 // 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: "BluetoothMidiTests",
     srcs: ["src/**/*.java"],
diff --git a/media/tests/AudioPolicyTest/Android.bp b/media/tests/AudioPolicyTest/Android.bp
index ed338375..95d1c6c 100644
--- a/media/tests/AudioPolicyTest/Android.bp
+++ b/media/tests/AudioPolicyTest/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: "audiopolicytest",
     srcs: ["**/*.java"],
diff --git a/media/tests/CameraBrowser/Android.bp b/media/tests/CameraBrowser/Android.bp
index 8e3ca19..1408640 100644
--- a/media/tests/CameraBrowser/Android.bp
+++ b/media/tests/CameraBrowser/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: "CameraBrowser",
     srcs: ["**/*.java"],
diff --git a/media/tests/EffectsTest/Android.bp b/media/tests/EffectsTest/Android.bp
index 214e8c0..644e453 100644
--- a/media/tests/EffectsTest/Android.bp
+++ b/media/tests/EffectsTest/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: "EffectsTest",
     srcs: ["**/*.java"],
diff --git a/media/tests/MediaDump/Android.bp b/media/tests/MediaDump/Android.bp
index 0eba8b2..f54b97a 100644
--- a/media/tests/MediaDump/Android.bp
+++ b/media/tests/MediaDump/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_app {
     name: "MediaDump",
     // Only compile source java files in this apk.
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index ecbe2b3..725781f 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/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: "mediaframeworktest",
     srcs: ["**/*.java"],
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 5a0a50c..b5465905 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/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: "mediaroutertest",
 
@@ -16,4 +25,4 @@
 
     platform_apis: true,
     certificate: "platform",
-}
\ No newline at end of file
+}
diff --git a/media/tests/MtpTests/Android.bp b/media/tests/MtpTests/Android.bp
index 7d2c7c6..3016873 100644
--- a/media/tests/MtpTests/Android.bp
+++ b/media/tests/MtpTests/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: "MtpTests",
     srcs: ["**/*.java"],
diff --git a/media/tests/ScoAudioTest/Android.bp b/media/tests/ScoAudioTest/Android.bp
index ad2b9171..f8a893b 100644
--- a/media/tests/ScoAudioTest/Android.bp
+++ b/media/tests/ScoAudioTest/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: "scoaudiotest",
     platform_apis: true,
diff --git a/media/tests/SoundPoolTest/Android.bp b/media/tests/SoundPoolTest/Android.bp
index 473f531..0a50106d 100644
--- a/media/tests/SoundPoolTest/Android.bp
+++ b/media/tests/SoundPoolTest/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: "SoundPoolTest",
     srcs: ["**/*.java"],
diff --git a/media/tests/TunerTest/Android.bp b/media/tests/TunerTest/Android.bp
index cef8791..2816fcc 100644
--- a/media/tests/TunerTest/Android.bp
+++ b/media/tests/TunerTest/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: "mediatunertest",
 
diff --git a/media/tests/audiotests/Android.bp b/media/tests/audiotests/Android.bp
index 5db0ab0..c52c033 100644
--- a/media/tests/audiotests/Android.bp
+++ b/media/tests/audiotests/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_test {
     name: "shared_mem_test",
     gtest: false,
diff --git a/media/tests/players/Android.bp b/media/tests/players/Android.bp
index 23c5f04..3b6df70 100644
--- a/media/tests/players/Android.bp
+++ b/media/tests/players/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"],
+}
+
 cc_test_library {
     name: "invoke_mock_media_player",
     srcs: ["invoke_mock_media_player.cpp"],
diff --git a/mime/Android.bp b/mime/Android.bp
index 23a8fbf..a3ea65c 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 java_defaults {
     name: "mimemap-defaults",
     srcs: [
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 02e1ebe..d1dddbd 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // The headers module is in frameworks/native/Android.bp.
+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"],
+}
+
 ndk_library {
     name: "libandroid",
     symbol_file: "libandroid.map.txt",
diff --git a/native/android/OWNERS b/native/android/OWNERS
index ac5a895..d414ed4 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,3 +1,4 @@
 per-file libandroid_net.map.txt, net.c = set noparent
 per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
 per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
+per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 15b473c..3f7f445 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/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"],
+}
+
 cc_library_shared {
     name: "libjnigraphics",
 
diff --git a/native/webview/loader/Android.bp b/native/webview/loader/Android.bp
index dfa5bdd..bb9b890 100644
--- a/native/webview/loader/Android.bp
+++ b/native/webview/loader/Android.bp
@@ -17,6 +17,15 @@
 
 // Loader library which handles address space reservation and relro sharing.
 // Does NOT link any native chromium code.
+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: "libwebviewchromium_loader",
 
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 1a3b36d..2e94e84 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -18,6 +18,38 @@
 
 // Native support library (libwebviewchromium_plat_support.so) - does NOT link
 // any native chromium code.
+package {
+    default_applicable_licenses: [
+        "frameworks_base_native_webview_plat_support_license",
+    ],
+}
+
+// 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_native_webview_plat_support_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "LICENSE",
+    ],
+}
+
 cc_library_shared {
     name: "libwebviewchromium_plat_support",
 
diff --git a/nfc-extras/Android.bp b/nfc-extras/Android.bp
index cbacd48..43b2830 100644
--- a/nfc-extras/Android.bp
+++ b/nfc-extras/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_sdk_library {
     name: "com.android.nfc_extras",
     srcs: ["java/**/*.java"],
diff --git a/nfc-extras/tests/Android.bp b/nfc-extras/tests/Android.bp
index fc52006..4c1f2fb 100644
--- a/nfc-extras/tests/Android.bp
+++ b/nfc-extras/tests/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: "NfcExtrasTests",
 
diff --git a/obex/Android.bp b/obex/Android.bp
index 6558eb3..95eac81 100644
--- a/obex/Android.bp
+++ b/obex/Android.bp
@@ -14,6 +14,36 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_obex_license"],
+}
+
+// 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_obex_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_sdk_library {
     name: "javax.obex",
     srcs: ["javax/**/*.java"],
diff --git a/packages/AppPredictionLib/Android.bp b/packages/AppPredictionLib/Android.bp
index e0f4ded..5a68fdc 100644
--- a/packages/AppPredictionLib/Android.bp
+++ b/packages/AppPredictionLib/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_library {
     name: "app_prediction",
 
diff --git a/packages/BackupEncryption/Android.bp b/packages/BackupEncryption/Android.bp
index 68e937c..00f2ddb 100644
--- a/packages/BackupEncryption/Android.bp
+++ b/packages/BackupEncryption/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "BackupEncryption",
     srcs: ["src/**/*.java"],
diff --git a/packages/BackupEncryption/test/robolectric-integration/Android.bp b/packages/BackupEncryption/test/robolectric-integration/Android.bp
index 67365df..c842e42 100644
--- a/packages/BackupEncryption/test/robolectric-integration/Android.bp
+++ b/packages/BackupEncryption/test/robolectric-integration/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_robolectric_test {
     name: "BackupEncryptionRoboIntegTests",
     srcs: [
diff --git a/packages/BackupEncryption/test/robolectric/Android.bp b/packages/BackupEncryption/test/robolectric/Android.bp
index 2a36dcf..7665d8f 100644
--- a/packages/BackupEncryption/test/robolectric/Android.bp
+++ b/packages/BackupEncryption/test/robolectric/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_robolectric_test {
     name: "BackupEncryptionRoboTests",
     srcs: [
diff --git a/packages/BackupEncryption/test/unittest/Android.bp b/packages/BackupEncryption/test/unittest/Android.bp
index d7c510b..f005170 100644
--- a/packages/BackupEncryption/test/unittest/Android.bp
+++ b/packages/BackupEncryption/test/unittest/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: "BackupEncryptionUnitTests",
     srcs: ["src/**/*.java"],
@@ -19,4 +28,4 @@
     test_suites: ["device-tests"],
     instrumentation_for: "BackupEncryption",
     certificate: "platform",
-}
\ No newline at end of file
+}
diff --git a/packages/BackupRestoreConfirmation/Android.bp b/packages/BackupRestoreConfirmation/Android.bp
index b0222da..8152f8d 100644
--- a/packages/BackupRestoreConfirmation/Android.bp
+++ b/packages/BackupRestoreConfirmation/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "BackupRestoreConfirmation",
     srcs: ["src/**/*.java"],
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 8598f74e..2e1c208 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -13,6 +13,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_library {
     name: "CarSystemUI-core",
 
diff --git a/packages/CarrierDefaultApp/Android.bp b/packages/CarrierDefaultApp/Android.bp
index c1b0b2d..fc753da 100644
--- a/packages/CarrierDefaultApp/Android.bp
+++ b/packages/CarrierDefaultApp/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_app {
     name: "CarrierDefaultApp",
     srcs: ["src/**/*.java"],
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.bp b/packages/CarrierDefaultApp/tests/unit/Android.bp
index 5655abb..54c9016 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.bp
+++ b/packages/CarrierDefaultApp/tests/unit/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: "CarrierDefaultAppUnitTests",
     certificate: "platform",
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 1453ec3..09505b7 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_CompanionDeviceManager_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_CompanionDeviceManager_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "CompanionDeviceManager",
     srcs: ["src/**/*.java"],
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index 8db8d76..ffca971 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -14,16 +14,48 @@
 // 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"],
+}
+
 // TODO: use a java_library in the bootclasspath instead
 filegroup {
-    name: "framework-connectivity-sources",
+    name: "framework-connectivity-internal-sources",
     srcs: [
         "src/**/*.java",
         "src/**/*.aidl",
     ],
     path: "src",
     visibility: [
+        "//visibility:private",
+    ],
+}
+
+filegroup {
+    name: "framework-connectivity-aidl-export-sources",
+    srcs: [
+        "aidl-export/**/*.aidl",
+    ],
+    path: "aidl-export",
+    visibility: [
+        "//visibility:private",
+    ],
+}
+
+// TODO: use a java_library in the bootclasspath instead
+filegroup {
+    name: "framework-connectivity-sources",
+    srcs: [
+        ":framework-connectivity-internal-sources",
+        ":framework-connectivity-aidl-export-sources",
+    ],
+    visibility: [
         "//frameworks/base",
         "//packages/modules/Connectivity:__subpackages__",
     ],
-}
\ No newline at end of file
+}
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl b/packages/Connectivity/framework/aidl-export/android/net/CaptivePortalData.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/CaptivePortalData.aidl
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl b/packages/Connectivity/framework/aidl-export/android/net/ConnectivityDiagnosticsManager.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/ConnectivityDiagnosticsManager.aidl
diff --git a/packages/Connectivity/framework/src/android/net/DhcpInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/DhcpInfo.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/DhcpInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/DhcpInfo.aidl
diff --git a/packages/Connectivity/framework/src/android/net/IpConfiguration.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpConfiguration.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/IpConfiguration.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/IpConfiguration.aidl
diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/IpPrefix.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
diff --git a/packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl b/packages/Connectivity/framework/aidl-export/android/net/KeepalivePacketData.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/KeepalivePacketData.aidl
diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.aidl b/packages/Connectivity/framework/aidl-export/android/net/LinkAddress.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/LinkAddress.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/LinkAddress.aidl
diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.aidl b/packages/Connectivity/framework/aidl-export/android/net/LinkProperties.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/LinkProperties.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/LinkProperties.aidl
diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.aidl b/packages/Connectivity/framework/aidl-export/android/net/MacAddress.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/MacAddress.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/MacAddress.aidl
diff --git a/packages/Connectivity/framework/src/android/net/Network.aidl b/packages/Connectivity/framework/aidl-export/android/net/Network.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/Network.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/Network.aidl
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkAgentConfig.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkAgentConfig.aidl
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkCapabilities.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkCapabilities.aidl
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkInfo.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/NetworkInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkInfo.aidl
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkRequest.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/NetworkRequest.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkRequest.aidl
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/ProxyInfo.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/ProxyInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/ProxyInfo.aidl
diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/RouteInfo.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/RouteInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/RouteInfo.aidl
diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl b/packages/Connectivity/framework/aidl-export/android/net/StaticIpConfiguration.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/StaticIpConfiguration.aidl
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl b/packages/Connectivity/framework/aidl-export/android/net/TestNetworkInterface.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/TestNetworkInterface.aidl
diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl b/packages/Connectivity/framework/aidl-export/android/net/apf/ApfCapabilities.aidl
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/apf/ApfCapabilities.aidl
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
index 18467fa..eafda4d 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
@@ -16,12 +16,15 @@
 
 package android.net;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -40,10 +43,29 @@
     private final long mExpiryTimeMillis;
     private final boolean mCaptive;
     private final String mVenueFriendlyName;
+    private final int mVenueInfoUrlSource;
+    private final int mUserPortalUrlSource;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CAPTIVE_PORTAL_DATA_SOURCE_"}, value = {
+            CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+            CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT})
+    public @interface CaptivePortalDataSource {}
+
+    /**
+     * Source of information: Other (default)
+     */
+    public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0;
+
+    /**
+     * Source of information: Wi-Fi Passpoint
+     */
+    public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1;
 
     private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
             boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
-            String venueFriendlyName) {
+            String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
         mRefreshTimeMillis = refreshTimeMillis;
         mUserPortalUrl = userPortalUrl;
         mVenueInfoUrl = venueInfoUrl;
@@ -52,11 +74,14 @@
         mExpiryTimeMillis = expiryTimeMillis;
         mCaptive = captive;
         mVenueFriendlyName = venueFriendlyName;
+        mVenueInfoUrlSource = venueInfoUrlSource;
+        mUserPortalUrlSource = userPortalUrlSource;
     }
 
     private CaptivePortalData(Parcel p) {
         this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
-                p.readLong(), p.readLong(), p.readBoolean(), p.readString());
+                p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
+                p.readInt());
     }
 
     @Override
@@ -74,6 +99,8 @@
         dest.writeLong(mExpiryTimeMillis);
         dest.writeBoolean(mCaptive);
         dest.writeString(mVenueFriendlyName);
+        dest.writeInt(mVenueInfoUrlSource);
+        dest.writeInt(mUserPortalUrlSource);
     }
 
     /**
@@ -88,6 +115,9 @@
         private long mExpiryTime = -1;
         private boolean mCaptive;
         private String mVenueFriendlyName;
+        private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
+        private @CaptivePortalDataSource int mUserPortalUrlSource =
+                CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
 
         /**
          * Create an empty builder.
@@ -100,8 +130,8 @@
         public Builder(@Nullable CaptivePortalData data) {
             if (data == null) return;
             setRefreshTime(data.mRefreshTimeMillis)
-                    .setUserPortalUrl(data.mUserPortalUrl)
-                    .setVenueInfoUrl(data.mVenueInfoUrl)
+                    .setUserPortalUrl(data.mUserPortalUrl, data.mUserPortalUrlSource)
+                    .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource)
                     .setSessionExtendable(data.mIsSessionExtendable)
                     .setBytesRemaining(data.mByteLimit)
                     .setExpiryTime(data.mExpiryTimeMillis)
@@ -123,7 +153,18 @@
          */
         @NonNull
         public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
+            return setUserPortalUrl(userPortalUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
+        }
+
+        /**
+         * Set the URL to be used for users to login to the portal, if captive, and the source of
+         * the data, see {@link CaptivePortalDataSource}
+         */
+        @NonNull
+        public Builder setUserPortalUrl(@Nullable Uri userPortalUrl,
+                @CaptivePortalDataSource int source) {
             mUserPortalUrl = userPortalUrl;
+            mUserPortalUrlSource = source;
             return this;
         }
 
@@ -132,7 +173,18 @@
          */
         @NonNull
         public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
+            return setVenueInfoUrl(venueInfoUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
+        }
+
+        /**
+         * Set the URL that can be used by users to view information about the network venue, and
+         * the source of the data, see {@link CaptivePortalDataSource}
+         */
+        @NonNull
+        public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl,
+                @CaptivePortalDataSource int source) {
             mVenueInfoUrl = venueInfoUrl;
+            mVenueInfoUrlSource = source;
             return this;
         }
 
@@ -188,7 +240,8 @@
         public CaptivePortalData build() {
             return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
                     mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive,
-                    mVenueFriendlyName);
+                    mVenueFriendlyName, mVenueInfoUrlSource,
+                    mUserPortalUrlSource);
         }
     }
 
@@ -249,6 +302,22 @@
     }
 
     /**
+     * Get the information source of the Venue URL
+     * @return The source that the Venue URL was obtained from
+     */
+    public @CaptivePortalDataSource int getVenueInfoUrlSource() {
+        return mVenueInfoUrlSource;
+    }
+
+    /**
+     * Get the information source of the user portal URL
+     * @return The source that the user portal URL was obtained from
+     */
+    public @CaptivePortalDataSource int getUserPortalUrlSource() {
+        return mUserPortalUrlSource;
+    }
+
+    /**
      * Get the venue friendly name
      */
     @Nullable
@@ -272,11 +341,12 @@
     @Override
     public int hashCode() {
         return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
-                mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName);
+                mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName,
+                mVenueInfoUrlSource, mUserPortalUrlSource);
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof CaptivePortalData)) return false;
         final CaptivePortalData other = (CaptivePortalData) obj;
         return mRefreshTimeMillis == other.mRefreshTimeMillis
@@ -286,7 +356,9 @@
                 && mByteLimit == other.mByteLimit
                 && mExpiryTimeMillis == other.mExpiryTimeMillis
                 && mCaptive == other.mCaptive
-                && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName);
+                && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName)
+                && mVenueInfoUrlSource == other.mVenueInfoUrlSource
+                && mUserPortalUrlSource == other.mUserPortalUrlSource;
     }
 
     @Override
@@ -300,6 +372,8 @@
                 + ", expiryTime: " + mExpiryTimeMillis
                 + ", captive: " + mCaptive
                 + ", venueFriendlyName: " + mVenueFriendlyName
+                + ", venueInfoUrlSource: " + mVenueInfoUrlSource
+                + ", userPortalUrlSource: " + mUserPortalUrlSource
                 + "}";
     }
 }
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
index 9afa5d1..92a792b 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -49,17 +49,6 @@
                 }
         );
 
-        // TODO: move outside of the connectivity JAR
-        SystemServiceRegistry.registerContextAwareService(
-                Context.VPN_MANAGEMENT_SERVICE,
-                VpnManager.class,
-                (context) -> {
-                    final ConnectivityManager cm = context.getSystemService(
-                            ConnectivityManager.class);
-                    return cm.createVpnManager();
-                }
-        );
-
         SystemServiceRegistry.registerContextAwareService(
                 Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
                 ConnectivityDiagnosticsManager.class,
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 987dcc4..6273f4b 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -21,6 +21,7 @@
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
 import static android.net.QosCallback.QosCallbackRegistrationException;
 
 import android.annotation.CallbackExecutor;
@@ -48,8 +49,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -455,7 +454,7 @@
      * @hide
      */
     @SystemApi
-    public static final int TETHERING_WIFI      = TetheringManager.TETHERING_WIFI;
+    public static final int TETHERING_WIFI      = 0;
 
     /**
      * USB tethering type.
@@ -463,7 +462,7 @@
      * @hide
      */
     @SystemApi
-    public static final int TETHERING_USB       = TetheringManager.TETHERING_USB;
+    public static final int TETHERING_USB       = 1;
 
     /**
      * Bluetooth tethering type.
@@ -471,7 +470,7 @@
      * @hide
      */
     @SystemApi
-    public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH;
+    public static final int TETHERING_BLUETOOTH = 2;
 
     /**
      * Wifi P2p tethering type.
@@ -823,6 +822,7 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     private final IConnectivityManager mService;
+
     /**
      * A kludge to facilitate static access where a Context pointer isn't available, like in the
      * case of the static set/getProcessDefaultNetwork methods and from the Network class.
@@ -833,7 +833,6 @@
 
     private final Context mContext;
 
-    private INetworkManagementService mNMService;
     private INetworkPolicyManager mNPManager;
     private final TetheringManager mTetheringManager;
 
@@ -1068,109 +1067,6 @@
     }
 
     /**
-     * Checks if a VPN app supports always-on mode.
-     *
-     * In order to support the always-on feature, an app has to
-     * <ul>
-     *     <li>target {@link VERSION_CODES#N API 24} or above, and
-     *     <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
-     *         meta-data field.
-     * </ul>
-     *
-     * @param userId The identifier of the user for whom the VPN app is installed.
-     * @param vpnPackage The canonical package name of the VPN app.
-     * @return {@code true} if and only if the VPN app exists and supports always-on mode.
-     * @hide
-     */
-    public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
-        try {
-            return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Configures an always-on VPN connection through a specific application.
-     * This connection is automatically granted and persisted after a reboot.
-     *
-     * <p>The designated package should declare a {@link VpnService} in its
-     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
-     *    otherwise the call will fail.
-     *
-     * @param userId The identifier of the user to set an always-on VPN for.
-     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
-     *                   to remove an existing always-on VPN configuration.
-     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
-     *        {@code false} otherwise.
-     * @param lockdownAllowlist The list of packages that are allowed to access network directly
-     *         when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
-     *         this method must be called when a package that should be allowed is installed or
-     *         uninstalled.
-     * @return {@code true} if the package is set as always-on VPN controller;
-     *         {@code false} otherwise.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
-            boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
-        try {
-            return mService.setAlwaysOnVpnPackage(
-                    userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-   /**
-     * Returns the package name of the currently set always-on VPN application.
-     * If there is no always-on VPN set, or the VPN is provided by the system instead
-     * of by an app, {@code null} will be returned.
-     *
-     * @return Package name of VPN controller responsible for always-on VPN,
-     *         or {@code null} if none is set.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public String getAlwaysOnVpnPackageForUser(int userId) {
-        try {
-            return mService.getAlwaysOnVpnPackage(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * @return whether always-on VPN is in lockdown mode.
-     *
-     * @hide
-     **/
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public boolean isVpnLockdownEnabled(int userId) {
-        try {
-            return mService.isVpnLockdownEnabled(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-    }
-
-    /**
-     * @return the list of packages that are allowed to access network when always-on VPN is in
-     * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
-     *
-     * @hide
-     **/
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public List<String> getVpnLockdownWhitelist(int userId) {
-        try {
-            return mService.getVpnLockdownWhitelist(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Adds or removes a requirement for given UID ranges to use the VPN.
      *
      * If set to {@code true}, informs the system that the UIDs in the specified ranges must not
@@ -1220,6 +1116,45 @@
     }
 
     /**
+     * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by
+     * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12
+     * but is still supported for backwards compatibility.
+     * <p>
+     * This type of VPN is assumed always to use the system default network, and must always declare
+     * exactly one underlying network, which is the network that was the default when the VPN
+     * connected.
+     * <p>
+     * Calling this method with {@code true} enables legacy behaviour, specifically:
+     * <ul>
+     *     <li>Any VPN that applies to userId 0 behaves specially with respect to deprecated
+     *     {@link #CONNECTIVITY_ACTION} broadcasts. Any such broadcasts will have the state in the
+     *     {@link #EXTRA_NETWORK_INFO} replaced by state of the VPN network. Also, any time the VPN
+     *     connects, a {@link #CONNECTIVITY_ACTION} broadcast will be sent for the network
+     *     underlying the VPN.</li>
+     *     <li>Deprecated APIs that return {@link NetworkInfo} objects will have their state
+     *     similarly replaced by the VPN network state.</li>
+     *     <li>Information on current network interfaces passed to NetworkStatsService will not
+     *     include any VPN interfaces.</li>
+     * </ul>
+     *
+     * @param enabled whether legacy lockdown VPN is enabled or disabled
+     *
+     * TODO: @SystemApi(client = MODULE_LIBRARIES)
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_SETTINGS})
+    public void setLegacyLockdownVpnEnabled(boolean enabled) {
+        try {
+            mService.setLegacyLockdownVpnEnabled(enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
@@ -1368,7 +1303,7 @@
     public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
         try {
             return mService.getDefaultNetworkCapabilitiesForUser(
-                    userId, mContext.getOpPackageName());
+                    userId, mContext.getOpPackageName(), getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1450,7 +1385,8 @@
     @Nullable
     public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
         try {
-            return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
+            return mService.getNetworkCapabilities(
+                    network, mContext.getOpPackageName(), getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2142,7 +2078,7 @@
      */
     // TODO: Remove method and replace with direct call once R code is pushed to AOSP
     private @Nullable String getAttributionTag() {
-        return null;
+        return mContext.getAttributionTag();
     }
 
     /**
@@ -2220,17 +2156,6 @@
         void onNetworkActive();
     }
 
-    private INetworkManagementService getNetworkManagementService() {
-        synchronized (this) {
-            if (mNMService != null) {
-                return mNMService;
-            }
-            IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-            mNMService = INetworkManagementService.Stub.asInterface(b);
-            return mNMService;
-        }
-    }
-
     private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
             mNetworkActivityListeners = new ArrayMap<>();
 
@@ -2255,7 +2180,7 @@
         };
 
         try {
-            getNetworkManagementService().registerNetworkActivityListener(rl);
+            mService.registerNetworkActivityListener(rl);
             mNetworkActivityListeners.put(l, rl);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -2272,7 +2197,7 @@
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
         Preconditions.checkArgument(rl != null, "Listener was not registered.");
         try {
-            getNetworkManagementService().unregisterNetworkActivityListener(rl);
+            mService.registerNetworkActivityListener(rl);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2288,7 +2213,7 @@
      */
     public boolean isDefaultNetworkActive() {
         try {
-            return getNetworkManagementService().isNetworkActive();
+            return mService.isDefaultNetworkActive();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2808,7 +2733,7 @@
      */
     @SystemApi
     @Deprecated
-    public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR;
+    public static final int TETHER_ERROR_NO_ERROR = 0;
     /**
      * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}.
      * {@hide}
@@ -2884,8 +2809,7 @@
      */
     @SystemApi
     @Deprecated
-    public static final int TETHER_ERROR_PROVISION_FAILED =
-            TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
+    public static final int TETHER_ERROR_PROVISION_FAILED = 11;
     /**
      * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
      * {@hide}
@@ -2899,8 +2823,7 @@
      */
     @SystemApi
     @Deprecated
-    public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN =
-            TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
+    public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
 
     /**
      * Get a more detailed error code after a Tethering or Untethering
@@ -3178,23 +3101,6 @@
     }
 
     /**
-     * If the LockdownVpn mechanism is enabled, updates the vpn
-     * with a reload of its profile.
-     *
-     * @return a boolean with {@code} indicating success
-     *
-     * <p>This method can only be called by the system UID
-     * {@hide}
-     */
-    public boolean updateLockdownVpn() {
-        try {
-            return mService.updateLockdownVpn();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Set sign in error notification to visible or invisible
      *
      * @hide
@@ -3231,32 +3137,6 @@
         }
     }
 
-    /** {@hide} - returns the factory serial number */
-    @UnsupportedAppUsage
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_FACTORY})
-    public int registerNetworkFactory(Messenger messenger, String name) {
-        try {
-            return mService.registerNetworkFactory(messenger, name);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_FACTORY})
-    public void unregisterNetworkFactory(Messenger messenger) {
-        try {
-            mService.unregisterNetworkFactory(messenger);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     /**
      * Registers the specified {@link NetworkProvider}.
      * Each listener must only be registered once. The listener can be unregistered with
@@ -3746,7 +3626,8 @@
         printStackTrace();
         checkCallbackNotNull(callback);
         Preconditions.checkArgument(
-                reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities");
+                reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null,
+                "null NetworkCapabilities");
         final NetworkRequest request;
         final String callingPackageName = mContext.getOpPackageName();
         try {
@@ -3761,7 +3642,8 @@
                 Binder binder = new Binder();
                 if (reqType == LISTEN) {
                     request = mService.listenForNetwork(
-                            need, messenger, binder, callingPackageName);
+                            need, messenger, binder, callingPackageName,
+                            getAttributionTag());
                 } else {
                     request = mService.requestNetwork(
                             need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
@@ -4206,7 +4088,8 @@
         checkPendingIntentNotNull(operation);
         try {
             mService.pendingListenForNetwork(
-                    request.networkCapabilities, operation, mContext.getOpPackageName());
+                    request.networkCapabilities, operation, mContext.getOpPackageName(),
+                    getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -4215,8 +4098,9 @@
     }
 
     /**
-     * Registers to receive notifications about changes in the system default network. The callbacks
-     * will continue to be called until either the application exits or
+     * Registers to receive notifications about changes in the application's default network. This
+     * may be a physical network or a virtual network, such as a VPN that applies to the
+     * application. The callbacks will continue to be called until either the application exits or
      * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
      *
      * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
@@ -4229,7 +4113,7 @@
      * {@link #unregisterNetworkCallback(NetworkCallback)}.
      *
      * @param networkCallback The {@link NetworkCallback} that the system will call as the
-     *                        system default network changes.
+     *                        application's default network changes.
      *                        The callback is invoked on the default internal Handler.
      * @throws RuntimeException if the app already has too many callbacks registered.
      */
@@ -4239,10 +4123,46 @@
     }
 
     /**
+     * Registers to receive notifications about changes in the application's default network. This
+     * may be a physical network or a virtual network, such as a VPN that applies to the
+     * application. The callbacks will continue to be called until either the application exits or
+     * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+     *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
+     * @param networkCallback The {@link NetworkCallback} that the system will call as the
+     *                        application's default network changes.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @throws RuntimeException if the app already has too many callbacks registered.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
+            @NonNull Handler handler) {
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+                TRACK_DEFAULT, TYPE_NONE, cbHandler);
+    }
+
+    /**
      * Registers to receive notifications about changes in the system default network. The callbacks
      * will continue to be called until either the application exits or
      * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
      *
+     * This method should not be used to determine networking state seen by applications, because in
+     * many cases, most or even all application traffic may not use the default network directly,
+     * and traffic from different applications may go on different networks by default. As an
+     * example, if a VPN is connected, traffic from all applications might be sent through the VPN
+     * and not onto the system default network. Applications or system components desiring to do
+     * determine network state as seen by applications should use other methods such as
+     * {@link #registerDefaultNetworkCallback(NetworkCallback, Handler)}.
+     *
      * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
      * number of outstanding requests to 100 per app (identified by their UID), shared with
      * all variants of this method, of {@link #requestNetwork} as well as
@@ -4256,20 +4176,19 @@
      *                        system default network changes.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      * @throws RuntimeException if the app already has too many callbacks registered.
+     *
+     * @hide
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
+    @SystemApi(client = MODULE_LIBRARIES)
+    @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_SETTINGS})
+    public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
             @NonNull Handler handler) {
-        // This works because if the NetworkCapabilities are null,
-        // ConnectivityService takes them from the default request.
-        //
-        // Since the capabilities are exactly the same as the default request's
-        // capabilities, this request is guaranteed, at all times, to be
-        // satisfied by the same network, if any, that satisfies the default
-        // request, i.e., the system default network.
         CallbackHandler cbHandler = new CallbackHandler(handler);
         sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
-                TRACK_DEFAULT, TYPE_NONE, cbHandler);
+                TRACK_SYSTEM_DEFAULT, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -4609,7 +4528,7 @@
             // Set HTTP proxy system properties to match network.
             // TODO: Deprecate this static method and replace it with a non-static version.
             try {
-                Proxy.setHttpProxySystemProperty(getInstance().getDefaultProxy());
+                Proxy.setHttpProxyConfiguration(getInstance().getDefaultProxy());
             } catch (SecurityException e) {
                 // The process doesn't have ACCESS_NETWORK_STATE, so we can't fetch the proxy.
                 Log.e(TAG, "Can't set proxy properties", e);
@@ -4836,11 +4755,6 @@
     }
 
     /** @hide */
-    public VpnManager createVpnManager() {
-        return new VpnManager(mContext, mService);
-    }
-
-    /** @hide */
     public ConnectivityDiagnosticsManager createDiagnosticsManager() {
         return new ConnectivityDiagnosticsManager(mContext, mService);
     }
@@ -4871,11 +4785,6 @@
         }
     }
 
-    private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) {
-        Log.d(TAG, "setOemNetworkPreference called with preference: "
-                + preference.toString());
-    }
-
     @NonNull
     private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
 
@@ -5077,4 +4986,60 @@
         sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
                 TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
     }
+
+    /**
+     * Listener for {@link #setOemNetworkPreference(OemNetworkPreferences, Executor,
+     * OnSetOemNetworkPreferenceListener)}.
+     * @hide
+     */
+    @SystemApi
+    public interface OnSetOemNetworkPreferenceListener {
+        /**
+         * Called when setOemNetworkPreference() successfully completes.
+         */
+        void onComplete();
+    }
+
+    /**
+     * Used by automotive devices to set the network preferences used to direct traffic at an
+     * application level as per the given OemNetworkPreferences. An example use-case would be an
+     * automotive OEM wanting to provide connectivity for applications critical to the usage of a
+     * vehicle via a particular network.
+     *
+     * Calling this will overwrite the existing preference.
+     *
+     * @param preference {@link OemNetworkPreferences} The application network preference to be set.
+     * @param executor the executor on which listener will be invoked.
+     * @param listener {@link OnSetOemNetworkPreferenceListener} optional listener used to
+     *                  communicate completion of setOemNetworkPreference(). This will only be
+     *                  called once upon successful completion of setOemNetworkPreference().
+     * @throws IllegalArgumentException if {@code preference} contains invalid preference values.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws UnsupportedOperationException if called on a non-automotive device.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE)
+    public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
+            @Nullable @CallbackExecutor final Executor executor,
+            @Nullable final OnSetOemNetworkPreferenceListener listener) {
+        Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+        if (null != listener) {
+            Objects.requireNonNull(executor, "Executor must be non-null");
+        }
+        final IOnSetOemNetworkPreferenceListener listenerInternal = listener == null ? null :
+                new IOnSetOemNetworkPreferenceListener.Stub() {
+                    @Override
+                    public void onComplete() {
+                        executor.execute(listener::onComplete);
+                    }
+        };
+
+        try {
+            mService.setOemNetworkPreference(preference, listenerInternal);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 1b4d2e4..160338d 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -20,6 +20,8 @@
 import android.net.ConnectionInfo;
 import android.net.ConnectivityDiagnosticsManager;
 import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.INetworkActivityListener;
 import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
 import android.net.LinkProperties;
@@ -29,21 +31,18 @@
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
+import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
 import android.net.UidRange;
 import android.net.QosSocketInfo;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
 
 import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
 
 /**
  * Interface that answers queries about, and allows changing, the
@@ -65,7 +64,7 @@
     Network getNetworkForType(int networkType);
     Network[] getAllNetworks();
     NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
-            int userId, String callingPackageName);
+            int userId, String callingPackageName, String callingAttributionTag);
 
     boolean isNetworkSupported(int networkType);
 
@@ -74,7 +73,8 @@
     LinkProperties getLinkPropertiesForType(int networkType);
     LinkProperties getLinkProperties(in Network network);
 
-    NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
+    NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
+            String callingAttributionTag);
 
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     NetworkState[] getAllNetworkState();
@@ -120,35 +120,8 @@
 
     ProxyInfo getProxyForNetwork(in Network nework);
 
-    boolean prepareVpn(String oldPackage, String newPackage, int userId);
-
-    void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
-
-    ParcelFileDescriptor establishVpn(in VpnConfig config);
-
-    boolean provisionVpnProfile(in VpnProfile profile, String packageName);
-
-    void deleteVpnProfile(String packageName);
-
-    void startVpnProfile(String packageName);
-
-    void stopVpnProfile(String packageName);
-
-    VpnConfig getVpnConfig(int userId);
-
-    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    void startLegacyVpn(in VpnProfile profile);
-
-    LegacyVpnInfo getLegacyVpnInfo(int userId);
-
-    boolean updateLockdownVpn();
-    boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
-    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
-            in List<String> lockdownWhitelist);
-    String getAlwaysOnVpnPackage(int userId);
-    boolean isVpnLockdownEnabled(int userId);
-    List<String> getVpnLockdownWhitelist(int userId);
     void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);
+    void setLegacyLockdownVpnEnabled(boolean enabled);
 
     void setProvisioningNotificationVisible(boolean visible, int networkType, in String action);
 
@@ -156,9 +129,6 @@
 
     boolean requestBandwidthUpdate(in Network network);
 
-    int registerNetworkFactory(in Messenger messenger, in String name);
-    void unregisterNetworkFactory(in Messenger messenger);
-
     int registerNetworkProvider(in Messenger messenger, in String name);
     void unregisterNetworkProvider(in Messenger messenger);
 
@@ -178,10 +148,12 @@
     void releasePendingNetworkRequest(in PendingIntent operation);
 
     NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
-            in Messenger messenger, in IBinder binder, String callingPackageName);
+            in Messenger messenger, in IBinder binder, String callingPackageName,
+            String callingAttributionTag);
 
     void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
-            in PendingIntent operation, String callingPackageName);
+            in PendingIntent operation, String callingPackageName,
+            String callingAttributionTag);
 
     void releaseNetworkRequest(in NetworkRequest networkRequest);
 
@@ -198,10 +170,6 @@
 
     int getRestoreDefaultNetworkDelay(int networkType);
 
-    boolean addVpnAddress(String address, int prefixLength);
-    boolean removeVpnAddress(String address, int prefixLength);
-    boolean setUnderlyingNetworksForVpn(in Network[] networks);
-
     void factoryReset();
 
     void startNattKeepalive(in Network network, int intervalSeconds,
@@ -221,8 +189,6 @@
     byte[] getNetworkWatchlistConfigHash();
 
     int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
-    boolean isCallerCurrentAlwaysOnVpnApp();
-    boolean isCallerCurrentAlwaysOnVpnLockdownApp();
 
     void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
             in NetworkRequest request, String callingPackageName);
@@ -243,4 +209,7 @@
 
     void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
     void unregisterQosCallback(in IQosCallback callback);
+
+    void setOemNetworkPreference(in OemNetworkPreferences preference,
+            in IOnSetOemNetworkPreferenceListener listener);
 }
diff --git a/core/java/android/os/INetworkActivityListener.aidl b/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
similarity index 96%
rename from core/java/android/os/INetworkActivityListener.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
index 24e6e55..79687dd 100644
--- a/core/java/android/os/INetworkActivityListener.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
@@ -13,7 +13,7 @@
 ** limitations under the License.
 */
 
-package android.os;
+package android.net;
 
 /**
  * @hide
diff --git a/packages/Connectivity/framework/src/android/net/IpConfiguration.java b/packages/Connectivity/framework/src/android/net/IpConfiguration.java
index 0b20564..d5f8b2e 100644
--- a/packages/Connectivity/framework/src/android/net/IpConfiguration.java
+++ b/packages/Connectivity/framework/src/android/net/IpConfiguration.java
@@ -167,7 +167,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == this) {
             return true;
         }
diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java
index e7c8014..d2ee7d1 100644
--- a/packages/Connectivity/framework/src/android/net/IpPrefix.java
+++ b/packages/Connectivity/framework/src/android/net/IpPrefix.java
@@ -18,11 +18,14 @@
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Pair;
 
+import com.android.net.module.util.NetUtils;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -58,7 +61,7 @@
             throw new IllegalArgumentException(
                     "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
         }
-        NetworkUtils.maskRawAddress(address, prefixLength);
+        NetUtils.maskRawAddress(address, prefixLength);
     }
 
     /**
@@ -124,7 +127,7 @@
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof IpPrefix)) {
             return false;
         }
@@ -189,7 +192,7 @@
         if (addrBytes == null || addrBytes.length != this.address.length) {
             return false;
         }
-        NetworkUtils.maskRawAddress(addrBytes, prefixLength);
+        NetUtils.maskRawAddress(addrBytes, prefixLength);
         return Arrays.equals(this.address, addrBytes);
     }
 
@@ -203,7 +206,7 @@
     public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
         if (otherPrefix.getPrefixLength() < prefixLength) return false;
         final byte[] otherAddress = otherPrefix.getRawAddress();
-        NetworkUtils.maskRawAddress(otherAddress, prefixLength);
+        NetUtils.maskRawAddress(otherAddress, prefixLength);
         return Arrays.equals(otherAddress, address);
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.java b/packages/Connectivity/framework/src/android/net/LinkAddress.java
index 44d25a1..d1bdaa0 100644
--- a/packages/Connectivity/framework/src/android/net/LinkAddress.java
+++ b/packages/Connectivity/framework/src/android/net/LinkAddress.java
@@ -349,7 +349,7 @@
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof LinkAddress)) {
             return false;
         }
diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.java b/packages/Connectivity/framework/src/android/net/LinkProperties.java
index 486e2d7..e41ed72 100644
--- a/packages/Connectivity/framework/src/android/net/LinkProperties.java
+++ b/packages/Connectivity/framework/src/android/net/LinkProperties.java
@@ -1613,7 +1613,7 @@
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
 
         if (!(obj instanceof LinkProperties)) return false;
diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java
index c7116b4..c83c23a 100644
--- a/packages/Connectivity/framework/src/android/net/MacAddress.java
+++ b/packages/Connectivity/framework/src/android/net/MacAddress.java
@@ -161,7 +161,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index b07bd68..46141e0 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -510,7 +511,7 @@
     };
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof Network)) return false;
         Network other = (Network)obj;
         return this.netId == other.netId;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index d22d82d..27aa15d 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -775,7 +776,8 @@
      * @param underlyingNetworks the new list of underlying networks.
      * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
      */
-    public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
+    public final void setUnderlyingNetworks(
+            @SuppressLint("NullableCollection") @Nullable List<Network> underlyingNetworks) {
         final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
                 ? new ArrayList<>(underlyingNetworks) : null;
         queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray));
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 8bfa77a..26d14cb 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -762,12 +762,14 @@
         final int originalSignalStrength = mSignalStrength;
         final int originalOwnerUid = getOwnerUid();
         final int[] originalAdministratorUids = getAdministratorUids();
+        final TransportInfo originalTransportInfo = getTransportInfo();
         clearAll();
         mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
                 | (1 << TRANSPORT_TEST);
         mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
         mNetworkSpecifier = originalSpecifier;
         mSignalStrength = originalSignalStrength;
+        mTransportInfo = originalTransportInfo;
 
         // Only retain the owner and administrator UIDs if they match the app registering the remote
         // caller that registered the network.
@@ -1786,6 +1788,15 @@
         return 0;
     }
 
+    private <T extends Parcelable> void writeParcelableArraySet(Parcel in,
+            @Nullable ArraySet<T> val, int flags) {
+        final int size = (val != null) ? val.size() : -1;
+        in.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            in.writeParcelable(val.valueAt(i), flags);
+        }
+    }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(mNetworkCapabilities);
@@ -1796,7 +1807,7 @@
         dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
         dest.writeParcelable((Parcelable) mTransportInfo, flags);
         dest.writeInt(mSignalStrength);
-        dest.writeArraySet(mUids);
+        writeParcelableArraySet(dest, mUids, flags);
         dest.writeString(mSSID);
         dest.writeBoolean(mPrivateDnsBroken);
         dest.writeIntArray(getAdministratorUids());
@@ -1819,8 +1830,7 @@
                 netCap.mNetworkSpecifier = in.readParcelable(null);
                 netCap.mTransportInfo = in.readParcelable(null);
                 netCap.mSignalStrength = in.readInt();
-                netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
-                        null /* ClassLoader, null for default */);
+                netCap.mUids = readParcelableArraySet(in, null /* ClassLoader, null for default */);
                 netCap.mSSID = in.readString();
                 netCap.mPrivateDnsBroken = in.readBoolean();
                 netCap.setAdministratorUids(in.createIntArray());
@@ -1833,6 +1843,20 @@
             public NetworkCapabilities[] newArray(int size) {
                 return new NetworkCapabilities[size];
             }
+
+            private @Nullable <T extends Parcelable> ArraySet<T> readParcelableArraySet(Parcel in,
+                    @Nullable ClassLoader loader) {
+                final int size = in.readInt();
+                if (size < 0) {
+                    return null;
+                }
+                final ArraySet<T> result = new ArraySet<>(size);
+                for (int i = 0; i < size; i++) {
+                    final T value = in.readParcelable(loader);
+                    result.append(value);
+                }
+                return result;
+            }
         };
 
     @Override
@@ -2061,9 +2085,10 @@
     /**
      * Check if private dns is broken.
      *
-     * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken.
+     * @return {@code true} if private DNS is broken on this network.
      * @hide
      */
+    @SystemApi
     public boolean isPrivateDnsBroken() {
         return mPrivateDnsBroken;
     }
@@ -2306,6 +2331,17 @@
         }
 
         /**
+         * Completely clears the contents of this object, removing even the capabilities that are
+         * set by default when the object is constructed.
+         * @return this builder
+         */
+        @NonNull
+        public Builder clearAll() {
+            mCaps.clearAll();
+            return this;
+        }
+
+        /**
          * Sets the owner UID.
          *
          * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 04011fc..4e3085f 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -86,17 +86,14 @@
      *       callbacks about the single, highest scoring current network
      *       (if any) that matches the specified NetworkCapabilities, or
      *
-     *     - TRACK_DEFAULT, a hybrid of the two designed such that the
-     *       framework will issue callbacks for the single, highest scoring
-     *       current network (if any) that matches the capabilities of the
-     *       default Internet request (mDefaultRequest), but which cannot cause
-     *       the framework to either create or retain the existence of any
-     *       specific network. Note that from the point of view of the request
-     *       matching code, TRACK_DEFAULT is identical to REQUEST: its special
-     *       behaviour is not due to different semantics, but to the fact that
-     *       the system will only ever create a TRACK_DEFAULT with capabilities
-     *       that are identical to the default request's capabilities, thus
-     *       causing it to share fate in every way with the default request.
+     *     - TRACK_DEFAULT, which causes the framework to issue callbacks for
+     *       the single, highest scoring current network (if any) that will
+     *       be chosen for an app, but which cannot cause the framework to
+     *       either create or retain the existence of any specific network.
+     *
+     *     - TRACK_SYSTEM_DEFAULT, which causes the framework to send callbacks
+     *       for the network (if any) that satisfies the default Internet
+     *       request.
      *
      *     - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
      *       to retain the NET_CAPABILITY_FOREGROUND capability. A network with
@@ -119,6 +116,7 @@
         TRACK_DEFAULT,
         REQUEST,
         BACKGROUND_REQUEST,
+        TRACK_SYSTEM_DEFAULT,
     };
 
     /**
@@ -435,25 +433,7 @@
      * @hide
      */
     public boolean isRequest() {
-        return isForegroundRequest() || isBackgroundRequest();
-    }
-
-    /**
-     * Returns true iff. the contained NetworkRequest is one that:
-     *
-     *     - should be associated with at most one satisfying network
-     *       at a time;
-     *
-     *     - should cause a network to be kept up and in the foreground if
-     *       it is the best network which can satisfy the NetworkRequest.
-     *
-     * For full detail of how isRequest() is used for pairing Networks with
-     * NetworkRequests read rematchNetworkAndRequests().
-     *
-     * @hide
-     */
-    public boolean isForegroundRequest() {
-        return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
+        return type == Type.REQUEST || type == Type.BACKGROUND_REQUEST;
     }
 
     /**
@@ -550,6 +530,8 @@
                 return NetworkRequestProto.TYPE_REQUEST;
             case BACKGROUND_REQUEST:
                 return NetworkRequestProto.TYPE_BACKGROUND_REQUEST;
+            case TRACK_SYSTEM_DEFAULT:
+                return NetworkRequestProto.TYPE_TRACK_SYSTEM_DEFAULT;
             default:
                 return NetworkRequestProto.TYPE_UNKNOWN;
         }
@@ -567,7 +549,7 @@
         proto.end(token);
     }
 
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkRequest == false) return false;
         NetworkRequest that = (NetworkRequest)obj;
         return (that.legacyType == this.legacyType &&
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index 8be4af7..9ccb04a 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -29,7 +29,6 @@
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.SocketException;
-import java.net.UnknownHostException;
 import java.util.Locale;
 import java.util.TreeSet;
 
@@ -232,46 +231,6 @@
     }
 
     /**
-     *  Masks a raw IP address byte array with the specified prefix length.
-     */
-    public static void maskRawAddress(byte[] array, int prefixLength) {
-        if (prefixLength < 0 || prefixLength > array.length * 8) {
-            throw new RuntimeException("IP address with " + array.length +
-                    " bytes has invalid prefix length " + prefixLength);
-        }
-
-        int offset = prefixLength / 8;
-        int remainder = prefixLength % 8;
-        byte mask = (byte)(0xFF << (8 - remainder));
-
-        if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
-
-        offset++;
-
-        for (; offset < array.length; offset++) {
-            array[offset] = 0;
-        }
-    }
-
-    /**
-     * Get InetAddress masked with prefixLength.  Will never return null.
-     * @param address the IP address to mask with
-     * @param prefixLength the prefixLength used to mask the IP
-     */
-    public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
-        byte[] array = address.getAddress();
-        maskRawAddress(array, prefixLength);
-
-        InetAddress netPart = null;
-        try {
-            netPart = InetAddress.getByAddress(array);
-        } catch (UnknownHostException e) {
-            throw new RuntimeException("getNetworkPart error - " + e.toString());
-        }
-        return netPart;
-    }
-
-    /**
      * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/packages/Connectivity/framework/src/android/net/Proxy.java
index 03b07e0..77c8a4f 100644
--- a/packages/Connectivity/framework/src/android/net/Proxy.java
+++ b/packages/Connectivity/framework/src/android/net/Proxy.java
@@ -16,8 +16,10 @@
 
 package android.net;
 
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
@@ -30,8 +32,6 @@
 import java.net.ProxySelector;
 import java.net.URI;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * A convenience class for accessing the user and default proxy
@@ -64,40 +64,9 @@
     @Deprecated
     public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
 
-    /** @hide */
-    public static final int PROXY_VALID             = 0;
-    /** @hide */
-    public static final int PROXY_HOSTNAME_EMPTY    = 1;
-    /** @hide */
-    public static final int PROXY_HOSTNAME_INVALID  = 2;
-    /** @hide */
-    public static final int PROXY_PORT_EMPTY        = 3;
-    /** @hide */
-    public static final int PROXY_PORT_INVALID      = 4;
-    /** @hide */
-    public static final int PROXY_EXCLLIST_INVALID  = 5;
-
     private static ConnectivityManager sConnectivityManager = null;
 
-    // Hostname / IP REGEX validation
-    // Matches blank input, ips, and domain names
-    private static final String NAME_IP_REGEX =
-        "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
-
-    private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
-
-    private static final Pattern HOSTNAME_PATTERN;
-
-    private static final String EXCL_REGEX =
-        "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*";
-
-    private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$";
-
-    private static final Pattern EXCLLIST_PATTERN;
-
     static {
-        HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
-        EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
         sDefaultProxySelector = ProxySelector.getDefault();
     }
 
@@ -216,36 +185,21 @@
         return false;
     }
 
-    /**
-     * Validate syntax of hostname, port and exclusion list entries
-     * {@hide}
-     */
-    public static int validate(String hostname, String port, String exclList) {
-        Matcher match = HOSTNAME_PATTERN.matcher(hostname);
-        Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
-
-        if (!match.matches()) return PROXY_HOSTNAME_INVALID;
-
-        if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID;
-
-        if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY;
-
-        if (port.length() > 0) {
-            if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY;
-            int portVal = -1;
-            try {
-                portVal = Integer.parseInt(port);
-            } catch (NumberFormatException ex) {
-                return PROXY_PORT_INVALID;
-            }
-            if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID;
-        }
-        return PROXY_VALID;
-    }
-
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final void setHttpProxySystemProperty(ProxyInfo p) {
+    @Deprecated
+    public static void setHttpProxySystemProperty(ProxyInfo p) {
+        setHttpProxyConfiguration(p);
+    }
+
+    /**
+     * Set HTTP proxy configuration for the process to match the provided ProxyInfo.
+     *
+     * If the provided ProxyInfo is null, the proxy configuration will be cleared.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static void setHttpProxyConfiguration(@Nullable ProxyInfo p) {
         String host = null;
         String port = null;
         String exclList = null;
@@ -256,11 +210,11 @@
             exclList = ProxyUtils.exclusionListAsString(p.getExclusionList());
             pacFileUrl = p.getPacFileUrl();
         }
-        setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
+        setHttpProxyConfiguration(host, port, exclList, pacFileUrl);
     }
 
     /** @hide */
-    public static final void setHttpProxySystemProperty(String host, String port, String exclList,
+    public static void setHttpProxyConfiguration(String host, String port, String exclList,
             Uri pacFileUrl) {
         if (exclList != null) exclList = exclList.replace(",", "|");
         if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
index c9bca28..229db0d 100644
--- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java
+++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
@@ -23,6 +23,8 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.net.module.util.ProxyUtils;
+
 import java.net.InetSocketAddress;
 import java.net.URLConnection;
 import java.util.List;
@@ -233,7 +235,7 @@
      */
     public boolean isValid() {
         if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
-        return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
+        return ProxyUtils.PROXY_VALID == ProxyUtils.validate(mHost == null ? "" : mHost,
                 mPort == 0 ? "" : Integer.toString(mPort),
                 mExclusionList == null ? "" : mExclusionList);
     }
@@ -275,7 +277,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!(o instanceof ProxyInfo)) return false;
         ProxyInfo p = (ProxyInfo)o;
         // If PAC URL is present in either then they must be equal.
diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.java b/packages/Connectivity/framework/src/android/net/RouteInfo.java
index 94f849f..5b6684a 100644
--- a/packages/Connectivity/framework/src/android/net/RouteInfo.java
+++ b/packages/Connectivity/framework/src/android/net/RouteInfo.java
@@ -534,7 +534,7 @@
      * Compares this RouteInfo object against the specified object and indicates if they are equal.
      * @return {@code true} if the objects are equal, {@code false} otherwise.
      */
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
 
         if (!(obj instanceof RouteInfo)) return false;
@@ -570,7 +570,7 @@
         }
 
         @Override
-        public boolean equals(Object o) {
+        public boolean equals(@Nullable Object o) {
             if (!(o instanceof RouteKey)) {
                 return false;
             }
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
index 4e89414..a174a7b 100644
--- a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
@@ -41,7 +41,6 @@
 
     /**
      * Prefix for tap interfaces created by this class.
-     * @hide
      */
     public static final String TEST_TAP_PREFIX = "testtap";
 
diff --git a/packages/Connectivity/framework/src/android/net/VpnManager.java b/packages/Connectivity/framework/src/android/net/VpnManager.java
deleted file mode 100644
index c87b827..0000000
--- a/packages/Connectivity/framework/src/android/net/VpnManager.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.net;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.RemoteException;
-
-import com.android.internal.net.VpnProfile;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.security.GeneralSecurityException;
-
-/**
- * This class provides an interface for apps to manage platform VPN profiles
- *
- * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
- * further app intermediation. When a VPN profile is present and the app is selected as an always-on
- * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
- * app (unlike VpnService).
- *
- * <p>VPN apps using supported protocols should preferentially use this API over the {@link
- * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
- * the guarantee that VPN network traffic is not subjected to on-device packet interception.
- *
- * @see Ikev2VpnProfile
- */
-public class VpnManager {
-    /** Type representing a lack of VPN @hide */
-    public static final int TYPE_VPN_NONE = -1;
-    /** VPN service type code @hide */
-    public static final int TYPE_VPN_SERVICE = 1;
-    /** Platform VPN type code @hide */
-    public static final int TYPE_VPN_PLATFORM = 2;
-
-    /** @hide */
-    @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface VpnType {}
-
-    @NonNull private final Context mContext;
-    @NonNull private final IConnectivityManager mService;
-
-    private static Intent getIntentForConfirmation() {
-        final Intent intent = new Intent();
-        final ComponentName componentName = ComponentName.unflattenFromString(
-                Resources.getSystem().getString(
-                        com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
-        intent.setComponent(componentName);
-        return intent;
-    }
-
-    /**
-     * Create an instance of the VpnManager with the given context.
-     *
-     * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
-     * {@link Context.getSystemService()} method call.
-     *
-     * @hide
-     */
-    public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
-        mContext = checkNotNull(ctx, "missing Context");
-        mService = checkNotNull(service, "missing IConnectivityManager");
-    }
-
-    /**
-     * Install a VpnProfile configuration keyed on the calling app's package name.
-     *
-     * <p>This method returns {@code null} if user consent has already been granted, or an {@link
-     * Intent} to a system activity. If an intent is returned, the application should launch the
-     * activity using {@link Activity#startActivityForResult} to request user consent. The activity
-     * may pop up a dialog to require user action, and the result will come back via its {@link
-     * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
-     * consented, and the VPN profile can be started.
-     *
-     * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
-     *     stored for this package.
-     * @return an Intent requesting user consent to start the VPN, or null if consent is not
-     *     required based on privileges or previous user consent.
-     */
-    @Nullable
-    public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
-        final VpnProfile internalProfile;
-
-        try {
-            internalProfile = profile.toVpnProfile();
-        } catch (GeneralSecurityException | IOException e) {
-            // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
-            // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
-            // string as required by the VpnProfile.
-            throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
-        }
-
-        try {
-            // Profile can never be null; it either gets set, or an exception is thrown.
-            if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
-                return null;
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-        return getIntentForConfirmation();
-    }
-
-    /**
-     * Delete the VPN profile configuration that was provisioned by the calling app
-     *
-     * @throws SecurityException if this would violate user settings
-     */
-    public void deleteProvisionedVpnProfile() {
-        try {
-            mService.deleteVpnProfile(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Request the startup of a previously provisioned VPN.
-     *
-     * @throws SecurityException exception if user or device settings prevent this VPN from being
-     *     setup, or if user consent has not been granted
-     */
-    public void startProvisionedVpnProfile() {
-        try {
-            mService.startVpnProfile(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** Tear down the VPN provided by the calling app (if any) */
-    public void stopProvisionedVpnProfile() {
-        try {
-            mService.stopVpnProfile(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
new file mode 100644
index 0000000..0242ba0
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.net;
+
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.internal.util.MessageUtils;
+
+import java.util.Objects;
+
+/**
+ * Container for VPN-specific transport information.
+ *
+ * @see android.net.TransportInfo
+ * @see NetworkCapabilities#getTransportInfo()
+ *
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class VpnTransportInfo implements TransportInfo, Parcelable {
+    private static final SparseArray<String> sTypeToString =
+            MessageUtils.findMessageNames(new Class[]{VpnManager.class}, new String[]{"TYPE_VPN_"});
+
+    /** Type of this VPN. */
+    @VpnManager.VpnType public final int type;
+
+    public VpnTransportInfo(@VpnManager.VpnType int type) {
+        this.type = type;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof VpnTransportInfo)) return false;
+
+        VpnTransportInfo that = (VpnTransportInfo) o;
+        return this.type == that.type;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type);
+    }
+
+    @Override
+    public String toString() {
+        final String typeString = sTypeToString.get(type, "VPN_TYPE_???");
+        return String.format("VpnTransportInfo{%s}", typeString);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(type);
+    }
+
+    public static final @NonNull Creator<VpnTransportInfo> CREATOR =
+            new Creator<VpnTransportInfo>() {
+        public VpnTransportInfo createFromParcel(Parcel in) {
+            return new VpnTransportInfo(in.readInt());
+        }
+        public VpnTransportInfo[] newArray(int size) {
+            return new VpnTransportInfo[size];
+        }
+    };
+}
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index 8fc3181..f20b89f 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_library_shared {
     name: "libservice-connectivity",
     // TODO: build against the NDK (sdk_version: "30" for example)
@@ -25,7 +34,6 @@
     ],
     srcs: [
         "jni/com_android_server_TestNetworkService.cpp",
-        "jni/com_android_server_connectivity_Vpn.cpp",
         "jni/onload.cpp",
     ],
     shared_libs: [
diff --git a/packages/Connectivity/service/jni/onload.cpp b/packages/Connectivity/service/jni/onload.cpp
index 3afcb0e..0012879 100644
--- a/packages/Connectivity/service/jni/onload.cpp
+++ b/packages/Connectivity/service/jni/onload.cpp
@@ -19,7 +19,6 @@
 
 namespace android {
 
-int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_TestNetworkService(JNIEnv* env);
 
 extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
@@ -29,12 +28,11 @@
         return JNI_ERR;
     }
 
-    if (register_android_server_connectivity_Vpn(env) < 0
-        || register_android_server_TestNetworkService(env) < 0) {
+    if (register_android_server_TestNetworkService(env) < 0) {
         return JNI_ERR;
     }
 
     return JNI_VERSION_1_6;
 }
 
-};
\ No newline at end of file
+};
diff --git a/packages/CtsShim/Android.bp b/packages/CtsShim/Android.bp
index 49608b3..31cd760 100644
--- a/packages/CtsShim/Android.bp
+++ b/packages/CtsShim/Android.bp
@@ -17,6 +17,15 @@
 //##########################################################
 // Variant: Privileged app
 
+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_app_import {
     name: "CtsShimPrivPrebuilt",
 
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index 14a3376..0b3f9bb 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -17,6 +17,15 @@
 //##########################################################
 // Variant: Privileged app upgrade
 
+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_app {
     name: "CtsShimPrivUpgrade",
     // this needs to be a privileged application
diff --git a/packages/CtsShim/build/jni/Android.bp b/packages/CtsShim/build/jni/Android.bp
index 4a1973c..ba586db 100644
--- a/packages/CtsShim/build/jni/Android.bp
+++ b/packages/CtsShim/build/jni/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_library_shared {
     name: "libshim_jni",
     srcs: ["Shim.c"],
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
index f1a18ae..0433320 100644
--- a/packages/DynamicSystemInstallationService/Android.bp
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -1,3 +1,22 @@
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_DynamicSystemInstallationService_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_DynamicSystemInstallationService_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "DynamicSystemInstallationService",
 
diff --git a/packages/DynamicSystemInstallationService/tests/Android.bp b/packages/DynamicSystemInstallationService/tests/Android.bp
index 3bdf829..50b65b4 100644
--- a/packages/DynamicSystemInstallationService/tests/Android.bp
+++ b/packages/DynamicSystemInstallationService/tests/Android.bp
@@ -1,3 +1,14 @@
+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_packages_DynamicSystemInstallationService_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_base_packages_DynamicSystemInstallationService_license",
+    ],
+}
+
 android_test {
     name: "DynamicSystemInstallationServiceTests",
 
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
index b858ab0..f8785f2 100644
--- a/packages/EasterEgg/Android.bp
+++ b/packages/EasterEgg/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     // the build system in pi-dev can't quite handle R.java in kt
     // so we will have a mix of java and kotlin files
diff --git a/packages/EncryptedLocalTransport/Android.bp b/packages/EncryptedLocalTransport/Android.bp
index dd30ad1..f851bc4 100644
--- a/packages/EncryptedLocalTransport/Android.bp
+++ b/packages/EncryptedLocalTransport/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "EncryptedLocalTransport",
     srcs: ["src/**/*.java"],
diff --git a/packages/ExtShared/Android.bp b/packages/ExtShared/Android.bp
index a9823b9..8e51215 100644
--- a/packages/ExtShared/Android.bp
+++ b/packages/ExtShared/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_base_packages_ExtShared_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_ExtShared_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "ExtShared",
     srcs: ["src/**/*.java"],
diff --git a/packages/ExternalStorageProvider/Android.bp b/packages/ExternalStorageProvider/Android.bp
index 973fef3..8718cc5 100644
--- a/packages/ExternalStorageProvider/Android.bp
+++ b/packages/ExternalStorageProvider/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_app {
     name: "ExternalStorageProvider",
 
diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp
index 04cf01a..633f186 100644
--- a/packages/ExternalStorageProvider/tests/Android.bp
+++ b/packages/ExternalStorageProvider/tests/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: "ExternalStorageProviderTests",
 
diff --git a/packages/FakeOemFeatures/Android.bp b/packages/FakeOemFeatures/Android.bp
index b265158..276132f 100644
--- a/packages/FakeOemFeatures/Android.bp
+++ b/packages/FakeOemFeatures/Android.bp
@@ -1,3 +1,22 @@
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_FakeOemFeatures_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_FakeOemFeatures_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "FakeOemFeatures",
     srcs: ["src/**/*.java"],
diff --git a/packages/FusedLocation/Android.bp b/packages/FusedLocation/Android.bp
index c70ab71..ee459fe 100644
--- a/packages/FusedLocation/Android.bp
+++ b/packages/FusedLocation/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_FusedLocation_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_FusedLocation_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "FusedLocation",
     srcs: ["src/**/*.java"],
@@ -43,4 +62,4 @@
         "truth-prebuilt",
     ],
     test_suites: ["device-tests"]
-}
\ No newline at end of file
+}
diff --git a/packages/InputDevices/Android.bp b/packages/InputDevices/Android.bp
index 7532aea..8aa8bb8 100644
--- a/packages/InputDevices/Android.bp
+++ b/packages/InputDevices/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_InputDevices_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_InputDevices_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "InputDevices",
 
diff --git a/packages/InputDevices/OWNERS b/packages/InputDevices/OWNERS
index 0313a40..f0d6db8 100644
--- a/packages/InputDevices/OWNERS
+++ b/packages/InputDevices/OWNERS
@@ -1,2 +1 @@
-michaelwr@google.com
-svv@google.com
+include /services/core/java/com/android/server/input/OWNERS
diff --git a/packages/LocalTransport/Android.bp b/packages/LocalTransport/Android.bp
index 2c990fe..185ab50 100644
--- a/packages/LocalTransport/Android.bp
+++ b/packages/LocalTransport/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "LocalTransport",
     srcs: ["src/**/*.java"],
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index 75bd32e..bf0520f 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_PackageInstaller_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_PackageInstaller_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "PackageInstaller",
 
diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS
index 252670a..8e1774b 100644
--- a/packages/PackageInstaller/OWNERS
+++ b/packages/PackageInstaller/OWNERS
@@ -1,5 +1,4 @@
 svetoslavganov@google.com
-moltmann@google.com
 toddke@google.com
 suprabh@google.com
 
diff --git a/packages/PrintRecommendationService/Android.bp b/packages/PrintRecommendationService/Android.bp
index 6d28bdb..c907e4e 100644
--- a/packages/PrintRecommendationService/Android.bp
+++ b/packages/PrintRecommendationService/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_PrintRecommendationService_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_PrintRecommendationService_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "PrintRecommendationService",
     srcs: ["src/**/*.java"],
diff --git a/packages/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
index c40a81791..99769b7 100644
--- a/packages/PrintSpooler/Android.bp
+++ b/packages/PrintSpooler/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_PrintSpooler_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_PrintSpooler_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "PrintSpooler",
 
diff --git a/packages/PrintSpooler/jni/Android.bp b/packages/PrintSpooler/jni/Android.bp
index 789312e..44df70e 100644
--- a/packages/PrintSpooler/jni/Android.bp
+++ b/packages/PrintSpooler/jni/Android.bp
@@ -1,3 +1,14 @@
+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_packages_PrintSpooler_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_base_packages_PrintSpooler_license",
+    ],
+}
+
 cc_library_shared {
     name: "libprintspooler_jni",
 
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
index 0e028b0..69a1d7f 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.bp
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -12,6 +12,17 @@
 // 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_packages_PrintSpooler_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_base_packages_PrintSpooler_license",
+    ],
+}
+
 android_test {
     name: "PrintSpoolerOutOfProcessTests",
 
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index d2848564..800ab67 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/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_library {
     name: "SettingsLibActionBarShadow",
 
diff --git a/packages/SettingsLib/ActionButtonsPreference/Android.bp b/packages/SettingsLib/ActionButtonsPreference/Android.bp
index cd3fb0c..51c9c39 100644
--- a/packages/SettingsLib/ActionButtonsPreference/Android.bp
+++ b/packages/SettingsLib/ActionButtonsPreference/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_library {
     name: "SettingsLibActionButtonsPreference",
 
diff --git a/packages/SettingsLib/AdaptiveIcon/Android.bp b/packages/SettingsLib/AdaptiveIcon/Android.bp
index 7f4442d..934aacf 100644
--- a/packages/SettingsLib/AdaptiveIcon/Android.bp
+++ b/packages/SettingsLib/AdaptiveIcon/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_library {
     name: "SettingsLibAdaptiveIcon",
 
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 5afe2f3d..b0b6387 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/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_library {
 
     name: "SettingsLib",
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index b07176a..1817a77 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/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_library {
     name: "SettingsLibAppPreference",
 
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
index 477e897..ae26066 100644
--- a/packages/SettingsLib/BarChartPreference/Android.bp
+++ b/packages/SettingsLib/BarChartPreference/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_library {
     name: "SettingsLibBarChartPreference",
 
diff --git a/packages/SettingsLib/DisplayDensityUtils/Android.bp b/packages/SettingsLib/DisplayDensityUtils/Android.bp
index 27d0cb5..b7bfb5f 100644
--- a/packages/SettingsLib/DisplayDensityUtils/Android.bp
+++ b/packages/SettingsLib/DisplayDensityUtils/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_library {
     name: "SettingsLibDisplayDensityUtils",
 
diff --git a/packages/SettingsLib/EntityHeaderWidgets/Android.bp b/packages/SettingsLib/EntityHeaderWidgets/Android.bp
index 280848a..bd83cdc 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/Android.bp
+++ b/packages/SettingsLib/EntityHeaderWidgets/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_library {
     name: "SettingsLibEntityHeaderWidgets",
 
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 285131d..5826047 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/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_library {
     name: "SettingsLibHelpUtils",
 
diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp
index a1f9a76..8a4e53d 100644
--- a/packages/SettingsLib/LayoutPreference/Android.bp
+++ b/packages/SettingsLib/LayoutPreference/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_library {
     name: "SettingsLibLayoutPreference",
 
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
index eae21d8..b5bc8f7 100644
--- a/packages/SettingsLib/ProgressBar/Android.bp
+++ b/packages/SettingsLib/ProgressBar/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_library {
     name: "SettingsLibProgressBar",
 
@@ -6,4 +15,4 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
index 136d6da..b309c01 100644
--- a/packages/SettingsLib/RadioButtonPreference/Android.bp
+++ b/packages/SettingsLib/RadioButtonPreference/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_library {
     name: "SettingsLibRadioButtonPreference",
 
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index b2f0882..c0623ed 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/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_library {
     name: "SettingsLibRestrictedLockUtils",
 
@@ -10,4 +19,4 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/SchedulesProvider/Android.bp b/packages/SettingsLib/SchedulesProvider/Android.bp
index ef59252..c4373bb 100644
--- a/packages/SettingsLib/SchedulesProvider/Android.bp
+++ b/packages/SettingsLib/SchedulesProvider/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_library {
     name: "SettingsLibSchedulesProvider",
 
diff --git a/packages/SettingsLib/SearchProvider/Android.bp b/packages/SettingsLib/SearchProvider/Android.bp
index 5254dde..f96011a 100644
--- a/packages/SettingsLib/SearchProvider/Android.bp
+++ b/packages/SettingsLib/SearchProvider/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_library {
     name: "SettingsLibSearchProvider",
 
diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp
index 7541ca45..b7367b4 100644
--- a/packages/SettingsLib/SearchWidget/Android.bp
+++ b/packages/SettingsLib/SearchWidget/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_library {
     name: "SettingsLibSearchWidget",
 
diff --git a/packages/SettingsLib/SettingsSpinner/Android.bp b/packages/SettingsLib/SettingsSpinner/Android.bp
index f18917c..be0567c 100644
--- a/packages/SettingsLib/SettingsSpinner/Android.bp
+++ b/packages/SettingsLib/SettingsSpinner/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_library {
     name: "SettingsLibSettingsSpinner",
 
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 6d505bf..e45c0ca 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/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_library {
     name: "SettingsLibSettingsTheme",
 
diff --git a/packages/SettingsLib/Tile/Android.bp b/packages/SettingsLib/Tile/Android.bp
index bf16ef3..cc570cc 100644
--- a/packages/SettingsLib/Tile/Android.bp
+++ b/packages/SettingsLib/Tile/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_library {
     name: "SettingsLibTile",
 
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index c5f0ee6..1cf42ff 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/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"],
+}
+
 android_library {
     name: "SettingsLibUtils",
 
diff --git a/packages/SettingsLib/search/Android.bp b/packages/SettingsLib/search/Android.bp
index d398aa5..45746d9 100644
--- a/packages/SettingsLib/search/Android.bp
+++ b/packages/SettingsLib/search/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_library {
     name: "SettingsLib-search",
     srcs: ["src/**/*.java"],
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 2ccff1e..24ca1fb 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/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: "SettingsLibTests",
     defaults: [
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index 3756c3b..dc661c2 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -16,6 +16,15 @@
 // SettingsLib Shell app just for Robolectric test target.  #
 //###########################################################
 
+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_app {
     name: "SettingsLibShell",
     defaults: ["SettingsLibDefaults"],
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 9d042a4..5f8bfef 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -1,3 +1,22 @@
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_SettingsProvider_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_SettingsProvider_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "SettingsProvider",
     resource_dirs: ["res"],
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index c5d4fa9..cb610fc 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -89,15 +89,7 @@
                         return value == null || value.length() < MAX_LENGTH;
                     }
                 });
-        VALIDATORS.put(
-                System.FONT_SCALE,
-                value -> {
-                    try {
-                        return Float.parseFloat(value) >= 0;
-                    } catch (NumberFormatException | NullPointerException e) {
-                        return false;
-                    }
-                });
+        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.85f, 1.3f));
         VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 System.DISPLAY_COLOR_MODE,
diff --git a/packages/SharedStorageBackup/Android.bp b/packages/SharedStorageBackup/Android.bp
index 5380832..db682ff 100644
--- a/packages/SharedStorageBackup/Android.bp
+++ b/packages/SharedStorageBackup/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "SharedStorageBackup",
     srcs: ["src/**/*.java"],
diff --git a/packages/Shell/Android.bp b/packages/Shell/Android.bp
index aaaf044..279cb84 100644
--- a/packages/Shell/Android.bp
+++ b/packages/Shell/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_app {
     name: "Shell",
     srcs: ["src/**/*.java",":dumpstate_aidl"],
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 135356c..c3fc019 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <!--  TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
     <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
     <uses-permission android:name="android.permission.MOVE_PACKAGE" />
+    <uses-permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
@@ -121,6 +122,8 @@
     <uses-permission android:name="android.permission.CREATE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
+    <uses-permission android:name="android.permission.QUERY_USERS" />
+    <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
     <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
     <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
@@ -355,6 +358,7 @@
     <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
+    <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
 
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 6ba1fcb..6d738f8 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -6,7 +6,7 @@
 svetoslavganov@google.com
 hackbod@google.com
 yamasani@google.com
-moltmann@google.com
 toddke@google.com
 cbrubaker@google.com
 omakoto@google.com
+michaelwr@google.com
diff --git a/packages/Shell/tests/Android.bp b/packages/Shell/tests/Android.bp
index 8536c4f..70e8c10 100644
--- a/packages/Shell/tests/Android.bp
+++ b/packages/Shell/tests/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: "ShellTests",
     srcs: ["src/**/*.java"],
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
index ff26710..1aeebf5 100644
--- a/packages/SimAppDialog/Android.bp
+++ b/packages/SimAppDialog/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_app {
     name: "SimAppDialog",
 
diff --git a/packages/SoundPicker/Android.bp b/packages/SoundPicker/Android.bp
index 3be7ca9..31fc77c 100644
--- a/packages/SoundPicker/Android.bp
+++ b/packages/SoundPicker/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_app {
     name: "SoundPicker",
     manifest: "AndroidManifest.xml",
diff --git a/packages/StatementService/Android.bp b/packages/StatementService/Android.bp
index 3831fd9..dcb9b32 100644
--- a/packages/StatementService/Android.bp
+++ b/packages/StatementService/Android.bp
@@ -11,6 +11,15 @@
 // 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_app {
     name: "StatementService",
     srcs: ["src/**/*.java"],
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 249b194..f113516 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -14,6 +14,23 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_SystemUI_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_library {
     name: "SystemUI-proto",
 
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index df5561a..ad39eae 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/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_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
 java_library {
 
     name: "SystemUIPluginLib",
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.bp b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
index c6c80f3..3f0fded 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/Android.bp
+++ b/packages/SystemUI/plugin/ExamplePlugin/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_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
 android_app {
 
     name: "ExamplePlugin",
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 581fef7..34d31d9 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/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_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
 java_library {
     sdk_version: "current",
     name: "PluginCoreLib",
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 68f4b746..db7e7b5 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/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_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
 genrule {
     name: "statslog-SystemUI-java-gen",
     tools: ["stats-log-api-gen"],
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 75f4809..dfa1b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -62,6 +62,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.View;
 import android.view.ViewGroup;
@@ -294,6 +295,13 @@
      */
     private final SparseIntArray mLastSimStates = new SparseIntArray();
 
+    /**
+     * Indicates if a SIM card had the SIM PIN enabled during the initialization, before
+     * reaching the SIM_STATE_READY state. The flag is reset to false at SIM_STATE_READY.
+     * Index is the slotId - in case of multiple SIM cards.
+     */
+    private final SparseBooleanArray mSimWasLocked = new SparseBooleanArray();
+
     private boolean mDeviceInteractive;
     private boolean mGoingToSleep;
 
@@ -465,10 +473,10 @@
                 }
             }
 
-            boolean simWasLocked;
+            boolean lastSimStateWasLocked;
             synchronized (KeyguardViewMediator.this) {
                 int lastState = mLastSimStates.get(slotId);
-                simWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
+                lastSimStateWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
                         || lastState == TelephonyManager.SIM_STATE_PUK_REQUIRED);
                 mLastSimStates.append(slotId, simState);
             }
@@ -492,17 +500,19 @@
                         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
                             // MVNO SIMs can become transiently NOT_READY when switching networks,
                             // so we should only lock when they are ABSENT.
-                            if (simWasLocked) {
+                            if (lastSimStateWasLocked) {
                                 if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
                                         + "previous state was locked. Reset the state.");
                                 resetStateLocked();
                             }
+                            mSimWasLocked.append(slotId, false);
                         }
                     }
                     break;
                 case TelephonyManager.SIM_STATE_PIN_REQUIRED:
                 case TelephonyManager.SIM_STATE_PUK_REQUIRED:
                     synchronized (KeyguardViewMediator.this) {
+                        mSimWasLocked.append(slotId, true);
                         if (!mShowing) {
                             if (DEBUG_SIM_STATES) Log.d(TAG,
                                     "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
@@ -529,9 +539,10 @@
                 case TelephonyManager.SIM_STATE_READY:
                     synchronized (KeyguardViewMediator.this) {
                         if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
-                        if (mShowing && simWasLocked) {
+                        if (mShowing && mSimWasLocked.get(slotId, false)) {
                             if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
-                                    + "previous state was locked. Reset the state.");
+                                    + "previously was locked. Reset the state.");
+                            mSimWasLocked.append(slotId, false);
                             resetStateLocked();
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index e6f43c1..328cb8a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -187,12 +187,12 @@
      */
     void end() {
         mMediaRecorder.stop();
-        mMediaProjection.stop();
         mMediaRecorder.release();
-        mMediaRecorder = null;
-        mMediaProjection = null;
         mInputSurface.release();
         mVirtualDisplay.release();
+        mMediaProjection.stop();
+        mMediaRecorder = null;
+        mMediaProjection = null;
         stopInternalAudioRecording();
 
         Log.d(TAG, "end recording");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index c5a35ea..d18902a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -27,12 +27,11 @@
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IConnectivityManager;
 import android.net.Network;
 import android.net.NetworkRequest;
+import android.net.VpnManager;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.security.KeyChain;
@@ -75,7 +74,7 @@
 
     private final Context mContext;
     private final ConnectivityManager mConnectivityManager;
-    private final IConnectivityManager mConnectivityManagerService;
+    private final VpnManager mVpnManager;
     private final DevicePolicyManager mDevicePolicyManager;
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
@@ -107,8 +106,7 @@
                 context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mConnectivityManager = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+        mVpnManager = context.getSystemService(VpnManager.class);
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mBgExecutor = bgExecutor;
@@ -346,25 +344,19 @@
     private void updateState() {
         // Find all users with an active VPN
         SparseArray<VpnConfig> vpns = new SparseArray<>();
-        try {
-            for (UserInfo user : mUserManager.getUsers()) {
-                VpnConfig cfg = mConnectivityManagerService.getVpnConfig(user.id);
-                if (cfg == null) {
+        for (UserInfo user : mUserManager.getUsers()) {
+            VpnConfig cfg = mVpnManager.getVpnConfig(user.id);
+            if (cfg == null) {
+                continue;
+            } else if (cfg.legacy) {
+                // Legacy VPNs should do nothing if the network is disconnected. Third-party
+                // VPN warnings need to continue as traffic can still go to the app.
+                LegacyVpnInfo legacyVpn = mVpnManager.getLegacyVpnInfo(user.id);
+                if (legacyVpn == null || legacyVpn.state != LegacyVpnInfo.STATE_CONNECTED) {
                     continue;
-                } else if (cfg.legacy) {
-                    // Legacy VPNs should do nothing if the network is disconnected. Third-party
-                    // VPN warnings need to continue as traffic can still go to the app.
-                    LegacyVpnInfo legacyVpn = mConnectivityManagerService.getLegacyVpnInfo(user.id);
-                    if (legacyVpn == null || legacyVpn.state != LegacyVpnInfo.STATE_CONNECTED) {
-                        continue;
-                    }
                 }
-                vpns.put(user.id, cfg);
             }
-        } catch (RemoteException rme) {
-            // Roll back to previous state
-            Log.e(TAG, "Unable to list active VPNs", rme);
-            return;
+            vpns.put(user.id, cfg);
         }
         mCurrentVpns = vpns;
     }
diff --git a/packages/VpnDialogs/Android.bp b/packages/VpnDialogs/Android.bp
index 6f2f50c..05135b2 100644
--- a/packages/VpnDialogs/Android.bp
+++ b/packages/VpnDialogs/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "VpnDialogs",
     certificate: "platform",
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
index 4d95ef1..3502baa 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
@@ -20,14 +20,11 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.net.IConnectivityManager;
+import android.net.VpnManager;
 import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.SpannableStringBuilder;
@@ -45,7 +42,7 @@
 
     private static final String TAG = "VpnDisconnected";
 
-    private IConnectivityManager mService;
+    private VpnManager mService;
     private int mUserId;
     private String mVpnPackage;
 
@@ -53,10 +50,9 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mService = IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
         mUserId = UserHandle.myUserId();
-        mVpnPackage = getAlwaysOnVpnPackage();
+        final VpnManager vm = getSystemService(VpnManager.class);
+        mVpnPackage = vm.getAlwaysOnVpnPackageForUser(mUserId);
         if (mVpnPackage == null) {
             finish();
             return;
@@ -102,15 +98,6 @@
         }
     }
 
-    private String getAlwaysOnVpnPackage() {
-        try {
-            return mService.getAlwaysOnVpnPackage(mUserId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Can't getAlwaysOnVpnPackage()", e);
-            return null;
-        }
-    }
-
     private CharSequence getVpnLabel() {
         try {
             return VpnConfig.getVpnLabel(this, mVpnPackage);
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index e66f2cc..fb23678 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -18,15 +18,11 @@
 
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
-import android.net.IConnectivityManager;
 import android.net.VpnManager;
 import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.Html;
@@ -48,7 +44,7 @@
 
     private String mPackage;
 
-    private IConnectivityManager mService;
+    private VpnManager mVm;
 
     public ConfirmDialog() {
         this(VpnManager.TYPE_VPN_SERVICE);
@@ -62,10 +58,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mPackage = getCallingPackage();
-        mService = IConnectivityManager.Stub.asInterface(
-                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+        mVm = getSystemService(VpnManager.class);
 
-        if (prepareVpn()) {
+        if (mVm.prepareVpn(mPackage, null, UserHandle.myUserId())) {
             setResult(RESULT_OK);
             finish();
             return;
@@ -74,7 +69,7 @@
             finish();
             return;
         }
-        final String alwaysOnVpnPackage = getAlwaysOnVpnPackage();
+        final String alwaysOnVpnPackage = mVm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());
         // Can't prepare new vpn app when another vpn is always-on
         if (alwaysOnVpnPackage != null && !alwaysOnVpnPackage.equals(mPackage)) {
             finish();
@@ -97,24 +92,6 @@
         button.setFilterTouchesWhenObscured(true);
     }
 
-    private String getAlwaysOnVpnPackage() {
-        try {
-           return mService.getAlwaysOnVpnPackage(UserHandle.myUserId());
-        } catch (RemoteException e) {
-            Log.e(TAG, "fail to call getAlwaysOnVpnPackage", e);
-            // Fallback to null to show the dialog
-            return null;
-        }
-    }
-
-    private boolean prepareVpn() {
-        try {
-            return mService.prepareVpn(mPackage, null, UserHandle.myUserId());
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
     private CharSequence getVpnLabel() {
         try {
             return VpnConfig.getVpnLabel(this, mPackage);
@@ -146,10 +123,10 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         try {
-            if (mService.prepareVpn(null, mPackage, UserHandle.myUserId())) {
+            if (mVm.prepareVpn(null, mPackage, UserHandle.myUserId())) {
                 // Authorize this app to initiate VPN connections in the future without user
                 // intervention.
-                mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), mVpnType);
+                mVm.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), mVpnType);
                 setResult(RESULT_OK);
             }
         } catch (Exception e) {
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 01dca7e..1fc74f7 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -16,13 +16,11 @@
 
 package com.android.vpndialogs;
 
-import android.content.Context;
 import android.content.DialogInterface;
-import android.net.IConnectivityManager;
+import android.net.VpnManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
@@ -41,7 +39,7 @@
 
     private VpnConfig mConfig;
 
-    private IConnectivityManager mService;
+    private VpnManager mVm;
 
     private TextView mDuration;
     private TextView mDataTransmitted;
@@ -55,11 +53,9 @@
         super.onCreate(savedInstanceState);
 
         try {
+            mVm = getSystemService(VpnManager.class);
 
-            mService = IConnectivityManager.Stub.asInterface(
-                    ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-
-            mConfig = mService.getVpnConfig(UserHandle.myUserId());
+            mConfig = mVm.getVpnConfig(UserHandle.myUserId());
 
             // mConfig can be null if we are a restricted user, in that case don't show this dialog
             if (mConfig == null) {
@@ -118,9 +114,9 @@
             } else if (which == DialogInterface.BUTTON_NEUTRAL) {
                 final int myUserId = UserHandle.myUserId();
                 if (mConfig.legacy) {
-                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
+                    mVm.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
                 } else {
-                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
+                    mVm.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
                 }
             }
         } catch (Exception e) {
diff --git a/packages/WAPPushManager/Android.bp b/packages/WAPPushManager/Android.bp
index 083dac9..eb4f14b 100644
--- a/packages/WAPPushManager/Android.bp
+++ b/packages/WAPPushManager/Android.bp
@@ -1,5 +1,24 @@
 // Copyright 2007-2008 The Android Open Source Project
 
+package {
+    default_applicable_licenses: [
+        "frameworks_base_packages_WAPPushManager_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_packages_WAPPushManager_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 android_app {
     name: "WAPPushManager",
     srcs: ["src/**/*.java"],
diff --git a/packages/WAPPushManager/tests/Android.bp b/packages/WAPPushManager/tests/Android.bp
index 25c6121..0a17938 100644
--- a/packages/WAPPushManager/tests/Android.bp
+++ b/packages/WAPPushManager/tests/Android.bp
@@ -12,6 +12,17 @@
 // 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_packages_WAPPushManager_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_base_packages_WAPPushManager_license",
+    ],
+}
+
 android_test {
     name: "WAPPushManagerTests",
     libs: [
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 748eb40..03bdf93 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "WallpaperBackup",
     srcs: ["src/**/*.java"],
diff --git a/packages/WallpaperCropper/Android.bp b/packages/WallpaperCropper/Android.bp
index ac38b27..6c14d0f 100644
--- a/packages/WallpaperCropper/Android.bp
+++ b/packages/WallpaperCropper/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_app {
     name: "WallpaperCropper",
     srcs: ["src/**/*.java"],
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index 999ab08..94c47b9 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -16,6 +16,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := frameworks-base-overlays
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_REQUIRED_MODULES := \
 	AccentColorBlackOverlay \
 	AccentColorCinnamonOverlay \
@@ -83,6 +86,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := frameworks-base-overlays-debug
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 
 include $(BUILD_PHONY_PACKAGE)
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/overlays/tests/Android.bp b/packages/overlays/tests/Android.bp
index 343367a..b117a31 100644
--- a/packages/overlays/tests/Android.bp
+++ b/packages/overlays/tests/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: "OverlayTests",
 
diff --git a/packages/services/PacProcessor/Android.bp b/packages/services/PacProcessor/Android.bp
index 494a818..6f90334 100644
--- a/packages/services/PacProcessor/Android.bp
+++ b/packages/services/PacProcessor/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "PacProcessor",
     srcs: ["src/**/*.java"],
diff --git a/packages/services/PacProcessor/jni/Android.bp b/packages/services/PacProcessor/jni/Android.bp
index 0e7e101..9651437 100644
--- a/packages/services/PacProcessor/jni/Android.bp
+++ b/packages/services/PacProcessor/jni/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_library_shared {
     name: "libjni_pacprocessor",
 
diff --git a/packages/services/Proxy/Android.bp b/packages/services/Proxy/Android.bp
index d93c9f8..4d76db7 100644
--- a/packages/services/Proxy/Android.bp
+++ b/packages/services/Proxy/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_app {
     name: "ProxyHandler",
     srcs: ["src/**/*.java"],
diff --git a/proto/Android.bp b/proto/Android.bp
index 86d8ee3..a5e1335 100644
--- a/proto/Android.bp
+++ b/proto/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_static {
     name: "framework-protos",
     host_supported: true,
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 95697e6..1a11359 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -29,6 +29,9 @@
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 LOCAL_MODULE:= librs_jni
+LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS:= notice
+LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
 LOCAL_MODULE_TAGS := optional
 LOCAL_REQUIRED_MODULES := libRS
 
diff --git a/samples/demo/haptic-assessment/Android.bp b/samples/demo/haptic-assessment/Android.bp
index 1c00609..4d54550 100644
--- a/samples/demo/haptic-assessment/Android.bp
+++ b/samples/demo/haptic-assessment/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "HapticAssessment",
     manifest: "AndroidManifest.xml",
@@ -31,4 +40,4 @@
         "res",
     ],
     dxflags: ["--multi-dex"],
-}
\ No newline at end of file
+}
diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp
index 5889f76..cbd19c3 100644
--- a/sax/tests/saxtests/Android.bp
+++ b/sax/tests/saxtests/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: "FrameworksSaxTests",
     // Include all test java files.
diff --git a/services/Android.bp b/services/Android.bp
index dfc8711..872b118 100644
--- a/services/Android.bp
+++ b/services/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_defaults {
     name: "services_defaults",
     plugins: [
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index 21a0c74..a492a5f 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/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"],
+}
+
 filegroup {
     name: "services.accessibility-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fcf270b..ac2ce5c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -766,6 +766,10 @@
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+            if (Binder.getCallingPid() == OWN_PROCESS_ID) {
+                return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices);
+            }
             return getUserStateLocked(resolvedUserId).mInstalledServices;
         }
     }
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
index c12f62f..ec98151 100644
--- a/services/appprediction/Android.bp
+++ b/services/appprediction/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"],
+}
+
 filegroup {
     name: "services.appprediction-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp
index 83a9aa4..d3cb5ee 100644
--- a/services/appwidget/Android.bp
+++ b/services/appwidget/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"],
+}
+
 filegroup {
     name: "services.appwidget-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index 1e65e84..bbb6cd8 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/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"],
+}
+
 filegroup {
     name: "services.autofill-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/backup/Android.bp b/services/backup/Android.bp
index 56b788e..89f6b54 100644
--- a/services/backup/Android.bp
+++ b/services/backup/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"],
+}
+
 filegroup {
     name: "services.backup-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 3c5268c..ba2a63a 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -3,6 +3,7 @@
 aabhinav@google.com
 bryanmawhinney@google.com
 jstemmer@google.com
+millmore@google.com
 nathch@google.com
 niagra@google.com
 niamhfw@google.com
diff --git a/services/backup/backuplib/Android.bp b/services/backup/backuplib/Android.bp
index 00f51c9..5a28891 100644
--- a/services/backup/backuplib/Android.bp
+++ b/services/backup/backuplib/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"],
+}
+
 filegroup {
     name: "backuplib-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/companion/Android.bp b/services/companion/Android.bp
index e251042..8f33a48 100644
--- a/services/companion/Android.bp
+++ b/services/companion/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"],
+}
+
 filegroup {
     name: "services.companion-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 66bbf66..cfbfe73 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -31,6 +31,8 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
 import android.companion.Association;
 import android.companion.AssociationRequest;
 import android.companion.CompanionDeviceManager;
@@ -665,6 +667,12 @@
         }
     }
 
+    void onDeviceConnected(String address) {
+    }
+
+    void onDeviceDisconnected(String address) {
+    }
+
     private class ShellCmd extends ShellCommand {
         public static final String USAGE = "help\n"
                 + "list USER_ID\n"
@@ -709,4 +717,19 @@
         }
     }
 
+
+    private class BluetoothDeviceConnectedListener
+            extends BluetoothAdapter.BluetoothConnectionCallback {
+        @Override
+        public void onDeviceConnected(BluetoothDevice device) {
+            CompanionDeviceManagerService.this.onDeviceConnected(device.getAddress());
+        }
+
+        @Override
+        public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {
+            Slog.d(LOG_TAG, device.getAddress() + " disconnected w/ reason: (" + reason + ") "
+                    + BluetoothAdapter.BluetoothConnectionCallback.disconnectReasonText(reason));
+            CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress());
+        }
+    }
 }
diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp
index 7006430..bdc706e 100644
--- a/services/contentcapture/Android.bp
+++ b/services/contentcapture/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"],
+}
+
 filegroup {
     name: "services.contentcapture-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
index 3fe3cd2..c1fbcbf 100644
--- a/services/contentsuggestions/Android.bp
+++ b/services/contentsuggestions/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"],
+}
+
 filegroup {
     name: "services.contentsuggestions-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4bebe39..a195647 100644
--- a/services/core/Android.bp
+++ b/services/core/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"],
+}
+
 filegroup {
     name: "services.core-sources",
     srcs: ["java/**/*.java"],
@@ -95,10 +104,9 @@
     libs: [
         "services.net",
         "android.hardware.light-V2.0-java",
-        "android.hardware.power-java",
+        "android.hardware.power-V1-java",
         "android.hardware.power-V1.0-java",
-        "android.hardware.vibrator-java",
-        "android.net.ipsec.ike.stubs.module_lib",
+        "android.hardware.vibrator-V1-java",
         "app-compat-annotations",
         "framework-tethering.stubs.module_lib",
         "service-permission.stubs.system_server",
@@ -120,7 +128,7 @@
         "android.hardware.health-V1.0-java",
         "android.hardware.health-V2.0-java",
         "android.hardware.health-V2.1-java",
-        "android.hardware.light-java",
+        "android.hardware.light-V1-java",
         "android.hardware.tv.cec-V1.0-java",
         "android.hardware.weaver-V1.0-java",
         "android.hardware.biometrics.face-V1.0-java",
@@ -128,11 +136,11 @@
         "android.hardware.oemlock-V1.0-java",
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
-        "android.hardware.rebootescrow-java",
+        "android.hardware.rebootescrow-V1-java",
         "android.hardware.soundtrigger-V2.3-java",
         "android.hidl.manager-V1.2-java",
         "capture_state_listener-aidl-java",
-        "dnsresolver_aidl_interface-java",
+        "dnsresolver_aidl_interface-V7-java",
         "icu4j_calendar_astronomer",
         "netd-client",
         "overlayable_policy_aidl-java",
@@ -207,8 +215,5 @@
         "java/com/android/server/connectivity/QosCallbackAgentConnection.java",
         "java/com/android/server/connectivity/QosCallbackTracker.java",
         "java/com/android/server/connectivity/TcpKeepaliveController.java",
-        "java/com/android/server/connectivity/Vpn.java",
-        "java/com/android/server/connectivity/VpnIkev2Utils.java",
-        "java/com/android/server/net/LockdownVpnTracker.java",
     ],
 }
diff --git a/services/core/java/android/content/pm/OWNERS b/services/core/java/android/content/pm/OWNERS
new file mode 100644
index 0000000..5eed0b5
--- /dev/null
+++ b/services/core/java/android/content/pm/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/pm/OWNERS
\ No newline at end of file
diff --git a/services/core/java/android/os/OWNERS b/services/core/java/android/os/OWNERS
new file mode 100644
index 0000000..d0a2daf
--- /dev/null
+++ b/services/core/java/android/os/OWNERS
@@ -0,0 +1 @@
+per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f2e1920..f4138d1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
@@ -46,6 +45,8 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -89,11 +90,13 @@
 import android.net.IConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.INetworkActivityListener;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
+import android.net.IOnSetOemNetworkPreferenceListener;
 import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
 import android.net.InetAddresses;
@@ -120,6 +123,7 @@
 import android.net.NetworkTestResultParcelable;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
+import android.net.OemNetworkPreferences;
 import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
 import android.net.QosCallbackException;
@@ -130,12 +134,13 @@
 import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
 import android.net.TetheringManager;
+import android.net.TransportInfo;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
 import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
 import android.net.VpnManager;
-import android.net.VpnService;
+import android.net.VpnTransportInfo;
 import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
@@ -143,13 +148,13 @@
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
+import android.os.BatteryStatsManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
@@ -159,6 +164,7 @@
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
@@ -166,10 +172,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.security.Credentials;
-import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
@@ -183,17 +188,16 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.BitUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.LocationPermissionChecker;
 import com.android.internal.util.MessageUtils;
 import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.PermissionUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.AutodestructReference;
 import com.android.server.connectivity.DataConnectionStats;
@@ -210,9 +214,7 @@
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
-import com.android.server.net.LockdownVpnTracker;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.utils.PriorityDump;
 
@@ -222,6 +224,7 @@
 import java.io.PrintWriter;
 import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -280,15 +283,18 @@
     // connect anyway?" dialog after the user selects a network that doesn't validate.
     private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
 
-    // Default to 30s linger time-out. Modifiable only for testing.
+    // Default to 30s linger time-out, and 5s for nascent network. Modifiable only for testing.
     private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
     private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+    private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
 
     // The maximum number of network request allowed per uid before an exception is thrown.
     private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
 
     @VisibleForTesting
     protected int mLingerDelayMs;  // Can't be final, or test subclass constructors can't change it.
+    @VisibleForTesting
+    protected int mNascentDelayMs;
 
     // How long to delay to removal of a pending intent based request.
     // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
@@ -301,18 +307,7 @@
 
     private final PerUidCounter mNetworkRequestCounter;
 
-    private KeyStore mKeyStore;
-
-    @VisibleForTesting
-    @GuardedBy("mVpns")
-    protected final SparseArray<Vpn> mVpns = new SparseArray<>();
-
-    // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
-    // a direct call to LockdownVpnTracker.isEnabled().
-    @GuardedBy("mVpns")
-    private boolean mLockdownEnabled;
-    @GuardedBy("mVpns")
-    private LockdownVpnTracker mLockdownTracker;
+    private volatile boolean mLockdownEnabled;
 
     /**
      * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
@@ -563,6 +558,17 @@
     private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
 
     /**
+     * used internally when setting the default networks for OemNetworkPreferences.
+     * obj = OemNetworkPreferences
+     */
+    private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
+
+    /**
+     * Used to indicate the system default network becomes active.
+     */
+    private static final int EVENT_REPORT_NETWORK_ACTIVITY = 49;
+
+    /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
@@ -739,14 +745,35 @@
         }
 
         private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
-                boolean isFallbackNetwork) {
+                boolean isDefaultNetwork) {
             if (DBG) {
                 log("Sending " + state
                         + " broadcast for type " + type + " " + nai.toShortString()
-                        + " isFallbackNetwork=" + isFallbackNetwork);
+                        + " isDefaultNetwork=" + isDefaultNetwork);
             }
         }
 
+        // When a lockdown VPN connects, send another CONNECTED broadcast for the underlying
+        // network type, to preserve previous behaviour.
+        private void maybeSendLegacyLockdownBroadcast(@NonNull NetworkAgentInfo vpnNai) {
+            if (vpnNai != mService.getLegacyLockdownNai()) return;
+
+            if (vpnNai.declaredUnderlyingNetworks == null
+                    || vpnNai.declaredUnderlyingNetworks.length != 1) {
+                Log.wtf(TAG, "Legacy lockdown VPN must have exactly one underlying network: "
+                        + Arrays.toString(vpnNai.declaredUnderlyingNetworks));
+                return;
+            }
+            final NetworkAgentInfo underlyingNai = mService.getNetworkAgentInfoForNetwork(
+                    vpnNai.declaredUnderlyingNetworks[0]);
+            if (underlyingNai == null) return;
+
+            final int type = underlyingNai.networkInfo.getType();
+            final DetailedState state = DetailedState.CONNECTED;
+            maybeLogBroadcast(underlyingNai, state, type, true /* isDefaultNetwork */);
+            mService.sendLegacyNetworkBroadcast(underlyingNai, state, type);
+        }
+
         /** Adds the given network to the specified legacy type list. */
         public void add(int type, NetworkAgentInfo nai) {
             if (!isTypeSupported(type)) {
@@ -762,11 +789,19 @@
                 list.add(nai);
             }
 
-            // Send a broadcast if this is the first network of its type or if it's the fallback.
-            final boolean isFallbackNetwork = mService.isFallbackNetwork(nai);
-            if ((list.size() == 1) || isFallbackNetwork) {
-                maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isFallbackNetwork);
-                mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
+            // Send a broadcast if this is the first network of its type or if it's the default.
+            final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
+
+            // If a legacy lockdown VPN is active, override the NetworkInfo state in all broadcasts
+            // to preserve previous behaviour.
+            final DetailedState state = mService.getLegacyLockdownState(DetailedState.CONNECTED);
+            if ((list.size() == 1) || isDefaultNetwork) {
+                maybeLogBroadcast(nai, state, type, isDefaultNetwork);
+                mService.sendLegacyNetworkBroadcast(nai, state, type);
+            }
+
+            if (type == TYPE_VPN && state == DetailedState.CONNECTED) {
+                maybeSendLegacyLockdownBroadcast(nai);
             }
         }
 
@@ -794,7 +829,7 @@
                               ", sending connected broadcast");
                 final NetworkAgentInfo replacement = list.get(0);
                 maybeLogBroadcast(replacement, DetailedState.CONNECTED, type,
-                        mService.isFallbackNetwork(replacement));
+                        mService.isDefaultNetwork(replacement));
                 mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type);
             }
         }
@@ -810,14 +845,14 @@
         // send out another legacy broadcast - currently only used for suspend/unsuspend
         // toggle
         public void update(NetworkAgentInfo nai) {
-            final boolean isFallback = mService.isFallbackNetwork(nai);
+            final boolean isDefault = mService.isDefaultNetwork(nai);
             final DetailedState state = nai.networkInfo.getDetailedState();
             for (int type = 0; type < mTypeLists.length; type++) {
                 final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
                 final boolean contains = (list != null && list.contains(nai));
                 final boolean isFirst = contains && (nai == list.get(0));
-                if (isFirst || contains && isFallback) {
-                    maybeLogBroadcast(nai, state, type, isFallback);
+                if (isFirst || contains && isDefault) {
+                    maybeLogBroadcast(nai, state, type, isDefault);
                     mService.sendLegacyNetworkBroadcast(nai, state, type);
                 }
             }
@@ -961,13 +996,6 @@
         }
 
         /**
-         * Get a reference to the system keystore.
-         */
-        public KeyStore getKeyStore() {
-            return KeyStore.getInstance();
-        }
-
-        /**
          * @see ProxyTracker
          */
         public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -990,6 +1018,15 @@
         }
 
         /**
+         * Gets the UID that owns a socket connection. Needed because opening SOCK_DIAG sockets
+         * requires CAP_NET_ADMIN, which the unit tests do not have.
+         */
+        public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+                InetSocketAddress remote) {
+            return InetDiagMessage.getConnectionOwnerUid(protocol, local, remote);
+        }
+
+        /**
          * @see MultinetworkPolicyTracker
          */
         public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
@@ -1022,12 +1059,13 @@
 
         mMetricsLog = logger;
         mNetworkRanker = new NetworkRanker();
-        final NetworkRequest fallbackRequest = createDefaultInternetRequestForTransport(
-                -1, NetworkRequest.Type.REQUEST);
-        mFallbackRequest = new NetworkRequestInfo(null, fallbackRequest, new Binder());
-        mNetworkRequests.put(fallbackRequest, mFallbackRequest);
-        mDefaultNetworkRequests.add(mFallbackRequest);
-        mNetworkRequestInfoLogs.log("REGISTER " + mFallbackRequest);
+        final NetworkRequest defaultInternetRequest = createDefaultRequest();
+        mDefaultRequest = new NetworkRequestInfo(
+                defaultInternetRequest, null, new Binder(),
+                null /* attributionTags */);
+        mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
+        mDefaultNetworkRequests.add(mDefaultRequest);
+        mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
 
         mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
@@ -1053,6 +1091,8 @@
                 Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
 
         mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
+        // TODO: Consider making the timer customizable.
+        mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
 
         mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
@@ -1064,7 +1104,6 @@
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
-        mKeyStore = mDeps.getKeyStore();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1153,45 +1192,17 @@
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
-        // Set up the listener for user state for creating user VPNs.
+        // Listen for user add/removes to inform PermissionMonitor.
         // Should run on mHandler to avoid any races.
         IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_STARTED);
-        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
         intentFilter.addAction(Intent.ACTION_USER_ADDED);
         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
 
         mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
-        mUserAllContext.registerReceiver(
-                mIntentReceiver,
-                intentFilter,
-                null /* broadcastPermission */,
-                mHandler);
-        mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
-                mUserPresentReceiver,
-                new IntentFilter(Intent.ACTION_USER_PRESENT),
-                null /* broadcastPermission */,
-                null /* scheduler */);
+        mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+                null /* broadcastPermission */, mHandler);
 
-        // Listen to package add and removal events for all users.
-        intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        intentFilter.addDataScheme("package");
-        mUserAllContext.registerReceiver(
-                mIntentReceiver,
-                intentFilter,
-                null /* broadcastPermission */,
-                mHandler);
-
-        // Listen to lockdown VPN reset.
-        intentFilter = new IntentFilter();
-        intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
-        mUserAllContext.registerReceiver(
-                mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
-
-        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
 
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
@@ -1217,6 +1228,14 @@
 
         mDnsManager = new DnsManager(mContext, mDnsResolver);
         registerPrivateDnsSettingsCallbacks();
+
+        mNoServiceNetwork =  new NetworkAgentInfo(null,
+                new Network(NO_SERVICE_NET_ID),
+                new NetworkInfo(TYPE_NONE, 0, "", ""),
+                new LinkProperties(), new NetworkCapabilities(), 0, mContext,
+                null, new NetworkAgentConfig(), this, null,
+                null, null, 0, INVALID_UID,
+                mQosCallbackTracker);
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1227,14 +1246,24 @@
         return netCap;
     }
 
+    private NetworkRequest createDefaultRequest() {
+        return createDefaultInternetRequestForTransport(
+                TYPE_NONE, NetworkRequest.Type.REQUEST);
+    }
+
     private NetworkRequest createDefaultInternetRequestForTransport(
             int transportType, NetworkRequest.Type type) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
         netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
-        if (transportType > -1) {
+        if (transportType > TYPE_NONE) {
             netCap.addTransportType(transportType);
         }
+        return createNetworkRequest(type, netCap);
+    }
+
+    private NetworkRequest createNetworkRequest(
+            NetworkRequest.Type type, NetworkCapabilities netCap) {
         return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
     }
 
@@ -1284,7 +1313,8 @@
 
         if (enable) {
             handleRegisterNetworkRequest(new NetworkRequestInfo(
-                    null, networkRequest, new Binder()));
+                    networkRequest, null, new Binder(),
+                    null /* attributionTags */));
         } else {
             handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
                     /* callOnUnavailable */ false);
@@ -1357,16 +1387,14 @@
     }
 
     private Network[] getVpnUnderlyingNetworks(int uid) {
-        synchronized (mVpns) {
-            if (mLockdownEnabled) return null;
-        }
+        if (mLockdownEnabled) return null;
         final NetworkAgentInfo nai = getVpnForUid(uid);
         if (nai != null) return nai.declaredUnderlyingNetworks;
         return null;
     }
 
     private NetworkState getUnfilteredActiveNetworkState(int uid) {
-        NetworkAgentInfo nai = getFallbackNetwork();
+        NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
 
         final Network[] networks = getVpnUnderlyingNetworks(uid);
         if (networks != null) {
@@ -1444,11 +1472,9 @@
         if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
             networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
         }
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) {
-                mLockdownTracker.augmentNetworkInfo(networkInfo);
-            }
-        }
+        networkInfo.setDetailedState(
+                getLegacyLockdownState(networkInfo.getDetailedState()),
+                "" /* reason */, null /* extraInfo */);
     }
 
     /**
@@ -1486,7 +1512,7 @@
 
     @Override
     public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         return getActiveNetworkForUidInternal(uid, ignoreBlocked);
     }
 
@@ -1499,7 +1525,7 @@
             }
         }
 
-        NetworkAgentInfo nai = getFallbackNetwork();
+        NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
         if (nai == null || isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid,
                 ignoreBlocked)) {
             return null;
@@ -1507,17 +1533,9 @@
         return nai.network;
     }
 
-    // Public because it's used by mLockdownTracker.
-    public NetworkInfo getActiveNetworkInfoUnfiltered() {
-        enforceAccessPermission();
-        final int uid = mDeps.getCallingUid();
-        NetworkState state = getUnfilteredActiveNetworkState(uid);
-        return state.networkInfo;
-    }
-
     @Override
     public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         final NetworkState state = getUnfilteredActiveNetworkState(uid);
         filterNetworkStateForUid(state, uid, ignoreBlocked);
         return state.networkInfo;
@@ -1619,7 +1637,7 @@
 
     @Override
     public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
-                int userId, String callingPackageName) {
+                int userId, String callingPackageName, @Nullable String callingAttributionTag) {
         // The basic principle is: if an app's traffic could possibly go over a
         // network, without the app doing anything multinetwork-specific,
         // (hence, by "default"), then include that network's capabilities in
@@ -1638,25 +1656,34 @@
 
         HashMap<Network, NetworkCapabilities> result = new HashMap<>();
 
-        final NetworkAgentInfo nai = getFallbackNetwork();
-        NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
-        if (nc != null) {
-            result.put(
-                    nai.network,
-                    createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                            nc, mDeps.getCallingUid(), callingPackageName));
+        for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
+            if (!nri.isBeingSatisfied()) {
+                continue;
+            }
+            final NetworkAgentInfo nai = nri.getSatisfier();
+            final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
+            if (null != nc
+                    && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                    && !result.containsKey(nai.network)) {
+                result.put(
+                        nai.network,
+                        createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+                                nc, mDeps.getCallingUid(), callingPackageName,
+                                callingAttributionTag));
+            }
         }
 
         // No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null.
         final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid());
-        if (networks != null) {
-            for (Network network : networks) {
-                nc = getNetworkCapabilitiesInternal(network);
-                if (nc != null) {
+        if (null != networks) {
+            for (final Network network : networks) {
+                final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
+                if (null != nc) {
                     result.put(
                             network,
                             createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                    nc, mDeps.getCallingUid(), callingPackageName));
+                                    nc, mDeps.getCallingUid(), callingPackageName,
+                                    callingAttributionTag));
                 }
             }
         }
@@ -1674,9 +1701,7 @@
 
     /**
      * Return LinkProperties for the active (i.e., connected) default
-     * network interface.  It is assumed that at most one default network
-     * is active at a time. If more than one is active, it is indeterminate
-     * which will be returned.
+     * network interface for the calling uid.
      * @return the ip properties for the active network, or {@code null} if
      * none is active
      */
@@ -1733,12 +1758,13 @@
     }
 
     @Override
-    public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+    public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName,
+            @Nullable String callingAttributionTag) {
         mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
         enforceAccessPermission();
         return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                 getNetworkCapabilitiesInternal(network),
-                mDeps.getCallingUid(), callingPackageName);
+                mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
     }
 
     @VisibleForTesting
@@ -1757,11 +1783,12 @@
         return newNc;
     }
 
-    private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName) {
+    private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
+            @Nullable String callingAttributionTag) {
         final long token = Binder.clearCallingIdentity();
         try {
             return mLocationPermissionChecker.checkLocationPermission(
-                    callerPkgName, null /* featureId */, callerUid, null /* message */);
+                    callerPkgName, callingAttributionTag, callerUid, null /* message */);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -1770,7 +1797,8 @@
     @VisibleForTesting
     @Nullable
     NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-            @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+            @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
+            @Nullable String callingAttributionTag) {
         if (nc == null) {
             return null;
         }
@@ -1779,7 +1807,8 @@
         // Avoid doing location permission check if the transport info has no location sensitive
         // data.
         if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
-            hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+            hasLocationPermission =
+                    hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
             newNc = new NetworkCapabilities(nc, hasLocationPermission);
         } else {
             newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
@@ -1796,7 +1825,8 @@
         }
         if (hasLocationPermission == null) {
             // Location permission not checked yet, check now for masking owner UID.
-            hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+            hasLocationPermission =
+                    hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
         }
         // Reset owner uid if the app has no location permission.
         if (!hasLocationPermission) {
@@ -1849,12 +1879,13 @@
     @Override
     public NetworkState[] getAllNetworkState() {
         // This contains IMSI details, so make sure the caller is privileged.
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
 
         final ArrayList<NetworkState> result = new ArrayList<>();
         for (Network network : getAllNetworks()) {
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-            if (nai != null) {
+            // TODO: Consider include SUSPENDED networks.
+            if (nai != null && nai.networkInfo.isConnected()) {
                 // TODO (b/73321673) : NetworkState contains a copy of the
                 // NetworkCapabilities, which may contain UIDs of apps to which the
                 // network applies. Should the UIDs be cleared so as not to leak or
@@ -2007,7 +2038,7 @@
                 mHandler.sendMessage(mHandler.obtainMessage(
                         EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
                         new PrivateDnsValidationUpdate(netId,
-                                InetAddress.parseNumericAddress(ipAddress),
+                                InetAddresses.parseNumericAddress(ipAddress),
                                 hostname, validated)));
             } catch (IllegalArgumentException e) {
                 loge("Error parsing ip address in validation event");
@@ -2025,7 +2056,7 @@
             // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
             // callback from each caller type. Need to re-factor NetdEventListenerService to allow
             // multiple NetworkMonitor registrants.
-            if (nai != null && nai.satisfies(mFallbackRequest.mRequests.get(0))) {
+            if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
                 nai.networkMonitor().notifyDnsResponse(returnCode);
             }
         }
@@ -2119,24 +2150,8 @@
 
     private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered,
             boolean isBackgroundRestricted) {
-        return NetworkPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
-                isNetworkMetered, isBackgroundRestricted);
-    }
-
-    /**
-     * Require that the caller is either in the same user or has appropriate permission to interact
-     * across users.
-     *
-     * @param userId Target user for whatever operation the current IPC is supposed to perform.
-     */
-    private void enforceCrossUserPermission(int userId) {
-        if (userId == UserHandle.getCallingUserId()) {
-            // Not a cross-user call.
-            return;
-        }
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                "ConnectivityService");
+        return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
+                isBackgroundRestricted);
     }
 
     private boolean checkAnyPermissionOf(String... permissions) {
@@ -2219,12 +2234,6 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
     }
 
-    private void enforceControlAlwaysOnVpnPermission() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
-                "ConnectivityService");
-    }
-
     private void enforceNetworkStackOrSettingsPermission() {
         enforceAnyPermissionOf(
                 android.Manifest.permission.NETWORK_SETTINGS,
@@ -2249,6 +2258,12 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
+    private void enforceOemNetworkPreferencesPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE,
+                "ConnectivityService");
+    }
+
     private boolean checkNetworkStackPermission() {
         return checkAnyPermissionOf(
                 android.Manifest.permission.NETWORK_STACK,
@@ -2288,7 +2303,7 @@
 
     // Public because it's used by mLockdownTracker.
     public void sendConnectedBroadcast(NetworkInfo info) {
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
 
@@ -2297,13 +2312,6 @@
     }
 
     private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) {
-                info = new NetworkInfo(info);
-                mLockdownTracker.augmentNetworkInfo(info);
-            }
-        }
-
         Intent intent = new Intent(bcastType);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
@@ -2397,10 +2405,6 @@
             }
         }
 
-        // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
-        // for user to unlock device too.
-        updateLockdownVpn();
-
         // Create network requests for always-on networks.
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
     }
@@ -2410,7 +2414,7 @@
      */
     @Override
     public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
-        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+        mNetworkActivityTracker.registerNetworkActivityListener(l);
     }
 
     /**
@@ -2418,7 +2422,7 @@
      */
     @Override
     public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
-        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+        mNetworkActivityTracker.unregisterNetworkActivityListener(l);
     }
 
     /**
@@ -2426,8 +2430,7 @@
      */
     @Override
     public boolean isDefaultNetworkActive() {
-        // TODO: Replace isNetworkActive() in NMS.
-        return false;
+        return mNetworkActivityTracker.isDefaultNetworkActive();
     }
 
     /**
@@ -2564,13 +2567,13 @@
         if (!checkDumpPermission(mContext, TAG, pw)) return;
         if (asProto) return;
 
-        if (ArrayUtils.contains(args, DIAG_ARG)) {
+        if (CollectionUtils.contains(args, DIAG_ARG)) {
             dumpNetworkDiagnostics(pw);
             return;
-        } else if (ArrayUtils.contains(args, NETWORK_ARG)) {
+        } else if (CollectionUtils.contains(args, NETWORK_ARG)) {
             dumpNetworks(pw);
             return;
-        } else if (ArrayUtils.contains(args, REQUEST_ARG)) {
+        } else if (CollectionUtils.contains(args, REQUEST_ARG)) {
             dumpNetworkRequests(pw);
             return;
         }
@@ -2582,15 +2585,21 @@
         pw.println();
         pw.println();
 
-        final NetworkAgentInfo fallbackNai = getFallbackNetwork();
+        final NetworkAgentInfo defaultNai = getDefaultNetwork();
         pw.print("Active default network: ");
-        if (fallbackNai == null) {
+        if (defaultNai == null) {
             pw.println("none");
         } else {
-            pw.println(fallbackNai.network.getNetId());
+            pw.println(defaultNai.network.getNetId());
         }
         pw.println();
 
+        pw.print("Current per-app default networks: ");
+        pw.increaseIndent();
+        dumpPerAppNetworkPreferences(pw);
+        pw.decreaseIndent();
+        pw.println();
+
         pw.println("Current Networks:");
         pw.increaseIndent();
         dumpNetworks(pw);
@@ -2635,7 +2644,7 @@
 
         pw.println();
 
-        if (ArrayUtils.contains(args, SHORT_ARG) == false) {
+        if (!CollectionUtils.contains(args, SHORT_ARG)) {
             pw.println();
             pw.println("mNetworkRequestInfoLogs (most recent first):");
             pw.increaseIndent();
@@ -2686,6 +2695,12 @@
         pw.increaseIndent();
         mPermissionMonitor.dump(pw);
         pw.decreaseIndent();
+
+        pw.println();
+        pw.println("Legacy network activity:");
+        pw.increaseIndent();
+        mNetworkActivityTracker.dump(pw);
+        pw.decreaseIndent();
     }
 
     private void dumpNetworks(IndentingPrintWriter pw) {
@@ -2703,9 +2718,43 @@
                 pw.println(nai.requestAt(i).toString());
             }
             pw.decreaseIndent();
-            pw.println("Lingered:");
+            pw.println("Inactivity Timers:");
             pw.increaseIndent();
-            nai.dumpLingerTimers(pw);
+            nai.dumpInactivityTimers(pw);
+            pw.decreaseIndent();
+            pw.decreaseIndent();
+        }
+    }
+
+    private void dumpPerAppNetworkPreferences(IndentingPrintWriter pw) {
+        pw.println("Per-App Network Preference:");
+        pw.increaseIndent();
+        if (0 == mOemNetworkPreferences.getNetworkPreferences().size()) {
+            pw.println("none");
+        } else {
+            pw.println(mOemNetworkPreferences.toString());
+        }
+        pw.decreaseIndent();
+
+        for (final NetworkRequestInfo defaultRequest : mDefaultNetworkRequests) {
+            if (mDefaultRequest == defaultRequest) {
+                continue;
+            }
+
+            final boolean isActive = null != defaultRequest.getSatisfier();
+            pw.println("Is per-app network active:");
+            pw.increaseIndent();
+            pw.println(isActive);
+            if (isActive) {
+                pw.println("Active network: " + defaultRequest.getSatisfier().network.netId);
+            }
+            pw.println("Tracked UIDs:");
+            pw.increaseIndent();
+            if (0 == defaultRequest.mRequests.size()) {
+                pw.println("none, this should never occur.");
+            } else {
+                pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
+            }
             pw.decreaseIndent();
             pw.decreaseIndent();
         }
@@ -2844,7 +2893,15 @@
                         Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
                         break;
                     }
+
                     final List<Network> underlying = (List<Network>) arg.second;
+
+                    if (isLegacyLockdownNai(nai)
+                            && (underlying == null || underlying.size() != 1)) {
+                        Log.wtf(TAG, "Legacy lockdown VPN " + nai.toShortString()
+                                + " must have exactly one underlying network: " + underlying);
+                    }
+
                     final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
                     nai.declaredUnderlyingNetworks = (underlying != null)
                             ? underlying.toArray(new Network[0]) : null;
@@ -2970,7 +3027,7 @@
 
             final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
             final boolean wasValidated = nai.lastValidated;
-            final boolean wasFallback = isFallbackNetwork(nai);
+            final boolean wasDefault = isDefaultNetwork(nai);
 
             if (DBG) {
                 final String logMsg = !TextUtils.isEmpty(redirectUrl)
@@ -2979,7 +3036,7 @@
                 log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
             }
             if (valid != nai.lastValidated) {
-                if (wasFallback) {
+                if (wasDefault) {
                     mMetricsLog.logDefaultNetworkValidity(valid);
                 }
                 final int oldScore = nai.getCurrentScore();
@@ -3300,27 +3357,27 @@
     }
 
     /**
-     * Updates the linger state from the network requests inside the NAI.
+     * Updates the inactivity state from the network requests inside the NAI.
      * @param nai the agent info to update
      * @param now the timestamp of the event causing this update
-     * @return whether the network was lingered as a result of this update
+     * @return whether the network was inactive as a result of this update
      */
-    private boolean updateLingerState(@NonNull final NetworkAgentInfo nai, final long now) {
-        // 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
-        // 2. If the network was lingering and there are now requests, unlinger it.
+    private boolean updateInactivityState(@NonNull final NetworkAgentInfo nai, final long now) {
+        // 1. Update the inactivity timer. If it's changed, reschedule or cancel the alarm.
+        // 2. If the network was inactive and there are now requests, unset inactive.
         // 3. If this network is unneeded (which implies it is not lingering), and there is at least
-        //    one lingered request, start lingering.
-        nai.updateLingerTimer();
-        if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
-            if (DBG) log("Unlingering " + nai.toShortString());
-            nai.unlinger();
+        //    one lingered request, set inactive.
+        nai.updateInactivityTimer();
+        if (nai.isInactive() && nai.numForegroundNetworkRequests() > 0) {
+            if (DBG) log("Unsetting inactive " + nai.toShortString());
+            nai.unsetInactive();
             logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
-        } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
+        } else if (unneeded(nai, UnneededFor.LINGER) && nai.getInactivityExpiry() > 0) {
             if (DBG) {
-                final int lingerTime = (int) (nai.getLingerExpiry() - now);
-                log("Lingering " + nai.toShortString() + " for " + lingerTime + "ms");
+                final int lingerTime = (int) (nai.getInactivityExpiry() - now);
+                log("Setting inactive " + nai.toShortString() + " for " + lingerTime + "ms");
             }
-            nai.linger();
+            nai.setInactive();
             logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
             return true;
         }
@@ -3334,7 +3391,6 @@
                 if (VDBG) log("NetworkFactory connected");
                 // Finish setting up the full connection
                 NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo);
-                npi.completeConnection();
                 sendAllRequestsToProvider(npi);
             } else {
                 loge("Error connecting NetworkFactory");
@@ -3355,13 +3411,13 @@
             loge("Error connecting NetworkAgent");
             mNetworkAgentInfos.remove(nai);
             if (nai != null) {
-                final boolean wasFallback = isFallbackNetwork(nai);
+                final boolean wasDefault = isDefaultNetwork(nai);
                 synchronized (mNetworkForNetId) {
                     mNetworkForNetId.remove(nai.network.getNetId());
                 }
                 mNetIdManager.releaseNetId(nai.network.getNetId());
                 // Just in case.
-                mLegacyTypeTracker.remove(nai, wasFallback);
+                mLegacyTypeTracker.remove(nai, wasDefault);
             }
         }
     }
@@ -3400,8 +3456,8 @@
             nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
                     null, null);
         }
-        final boolean wasFallback = isFallbackNetwork(nai);
-        if (wasFallback) {
+        final boolean wasDefault = isDefaultNetwork(nai);
+        if (wasDefault) {
             mDefaultInetConditionPublished = 0;
             // Log default network disconnection before required book-keeping.
             // Let rematchAllNetworksAndRequests() below record a new default network event
@@ -3436,31 +3492,33 @@
         propagateUnderlyingNetworkCapabilities(nai.network);
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
-            NetworkRequest request = nai.requestAt(i);
+            final NetworkRequest request = nai.requestAt(i);
             final NetworkRequestInfo nri = mNetworkRequests.get(request);
             final NetworkAgentInfo currentNetwork = nri.getSatisfier();
             if (currentNetwork != null
                     && currentNetwork.network.getNetId() == nai.network.getNetId()) {
+                // uid rules for this network will be removed in destroyNativeNetwork(nai).
                 nri.setSatisfier(null, null);
-                sendUpdatedScoreToFactories(request, null);
+                if (request.isRequest()) {
+                    sendUpdatedScoreToFactories(request, null);
+                }
 
-                if (mFallbackRequest == nri) {
+                if (mDefaultRequest == nri) {
                     // TODO : make battery stats aware that since 2013 multiple interfaces may be
-                    //  active at the same time. For now keep calling this with the fallback
+                    //  active at the same time. For now keep calling this with the default
                     //  network, because while incorrect this is the closest to the old (also
                     //  incorrect) behavior.
                     mNetworkActivityTracker.updateDataActivityTracking(
                             null /* newNetwork */, nai);
-                    notifyLockdownVpn(nai);
                     ensureNetworkTransitionWakelock(nai.toShortString());
                 }
             }
         }
-        nai.clearLingerState();
+        nai.clearInactivityState();
         // TODO: mLegacyTypeTracker.remove seems redundant given there's a full rematch right after.
-        //  Currently, deleting it breaks tests that check for the fallback network disconnecting.
+        //  Currently, deleting it breaks tests that check for the default network disconnecting.
         //  Find out why, fix the rematch code, and delete this.
-        mLegacyTypeTracker.remove(nai, wasFallback);
+        mLegacyTypeTracker.remove(nai, wasDefault);
         rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
         if (nai.created) {
@@ -3468,10 +3526,9 @@
             // (routing rules, DNS, etc).
             // This may be slow as it requires a lot of netd shelling out to ip and
             // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
-            // after we've rematched networks with requests which should make a potential
-            // fallback network the default or requested a new network from the
-            // NetworkProviders, so network traffic isn't interrupted for an unnecessarily
-            // long time.
+            // after we've rematched networks with requests (which might change the default
+            // network or service a new request from an app), so network traffic isn't interrupted
+            // for an unnecessarily long time.
             destroyNativeNetwork(nai);
             mDnsManager.removeNetwork(nai.network);
         }
@@ -3542,32 +3599,38 @@
     }
 
     private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
+        handleRegisterNetworkRequests(Collections.singleton(nri));
+    }
+
+    private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
         ensureRunningOnConnectivityServiceThread();
-        mNetworkRequestInfoLogs.log("REGISTER " + nri);
-        for (final NetworkRequest req : nri.mRequests) {
-            mNetworkRequests.put(req, nri);
-            if (req.isListen()) {
-                for (final NetworkAgentInfo network : mNetworkAgentInfos) {
-                    if (req.networkCapabilities.hasSignalStrength()
-                            && network.satisfiesImmutableCapabilitiesOf(req)) {
-                        updateSignalStrengthThresholds(network, "REGISTER", req);
+        for (final NetworkRequestInfo nri : nris) {
+            mNetworkRequestInfoLogs.log("REGISTER " + nri);
+            for (final NetworkRequest req : nri.mRequests) {
+                mNetworkRequests.put(req, nri);
+                if (req.isListen()) {
+                    for (final NetworkAgentInfo network : mNetworkAgentInfos) {
+                        if (req.networkCapabilities.hasSignalStrength()
+                                && network.satisfiesImmutableCapabilitiesOf(req)) {
+                            updateSignalStrengthThresholds(network, "REGISTER", req);
+                        }
                     }
                 }
             }
         }
-        rematchAllNetworksAndRequests();
-        // If an active request exists, return as its score has already been sent if needed.
-        if (null != nri.getActiveRequest()) {
-            return;
-        }
 
-        // As this request was not satisfied on rematch and thus never had any scores sent to the
-        // factories, send null now for each request of type REQUEST.
-        for (final NetworkRequest req : nri.mRequests) {
-            if (!req.isRequest()) {
-                continue;
+        rematchAllNetworksAndRequests();
+        for (final NetworkRequestInfo nri : nris) {
+            // If the nri is satisfied, return as its score has already been sent if needed.
+            if (nri.isBeingSatisfied()) {
+                return;
             }
-            sendUpdatedScoreToFactories(req, null);
+
+            // As this request was not satisfied on rematch and thus never had any scores sent to
+            // the factories, send null now for each request of type REQUEST.
+            for (final NetworkRequest req : nri.mRequests) {
+                if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
+            }
         }
     }
 
@@ -3607,7 +3670,7 @@
                 return true;
         }
 
-        if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
+        if (!nai.everConnected || nai.isVPN() || nai.isInactive() || numRequests > 0) {
             return false;
         }
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -3670,7 +3733,15 @@
 
     private NetworkRequestInfo getNriForAppRequest(
             NetworkRequest request, int callingUid, String requestedOperation) {
-        final NetworkRequestInfo nri = mNetworkRequests.get(request);
+        // Looking up the app passed param request in mRequests isn't possible since it may return
+        // null for a request managed by a per-app default. Therefore use getNriForAppRequest() to
+        // do the lookup since that will also find per-app default managed requests.
+        // Additionally, this lookup needs to be relatively fast (hence the lookup optimization)
+        // to avoid potential race conditions when validating a package->uid mapping when sending
+        // the callback on the very low-chance that an application shuts down prior to the callback
+        // being sent.
+        final NetworkRequestInfo nri = mNetworkRequests.get(request) != null
+                ? mNetworkRequests.get(request) : getNriForAppRequest(request);
 
         if (nri != null) {
             if (Process.SYSTEM_UID != callingUid && Process.NETWORK_STACK_UID != callingUid
@@ -3700,7 +3771,7 @@
         if (mNetworkRequests.get(nri.mRequests.get(0)) == null) {
             return;
         }
-        if (nri.getSatisfier() != null) {
+        if (nri.isBeingSatisfied()) {
             return;
         }
         if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) {
@@ -3719,8 +3790,6 @@
         if (nri == null) {
             return;
         }
-        // handleReleaseNetworkRequest() paths don't apply to multilayer requests.
-        ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequest");
         if (VDBG || (DBG && request.isRequest())) {
             log("releasing " + request + " (release request)");
         }
@@ -3732,7 +3801,6 @@
 
     private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) {
         ensureRunningOnConnectivityServiceThread();
-
         nri.unlinkDeathRecipient();
         for (final NetworkRequest req : nri.mRequests) {
             mNetworkRequests.remove(req);
@@ -3740,11 +3808,12 @@
                 removeListenRequestFromNetworks(req);
             }
         }
+        mDefaultNetworkRequests.remove(nri);
         mNetworkRequestCounter.decrementCount(nri.mUid);
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
 
         if (null != nri.getActiveRequest()) {
-            if (nri.getActiveRequest().isRequest()) {
+            if (!nri.getActiveRequest().isListen()) {
                 removeSatisfiedNetworkRequestFromNetwork(nri);
             } else {
                 nri.setSatisfier(null, null);
@@ -3754,6 +3823,16 @@
         cancelNpiRequests(nri);
     }
 
+    private void handleRemoveNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
+        for (final NetworkRequestInfo nri : nris) {
+            if (mDefaultRequest == nri) {
+                // Make sure we never remove the default request.
+                continue;
+            }
+            handleRemoveNetworkRequest(nri);
+        }
+    }
+
     private void cancelNpiRequests(@NonNull final NetworkRequestInfo nri) {
         for (final NetworkRequest req : nri.mRequests) {
             cancelNpiRequest(req);
@@ -3799,7 +3878,7 @@
             // If there are still lingered requests on this network, don't tear it down,
             // but resume lingering instead.
             final long now = SystemClock.elapsedRealtime();
-            if (updateLingerState(nai, now)) {
+            if (updateInactivityState(nai, now)) {
                 notifyNetworkLosing(nai, now);
             }
             if (unneeded(nai, UnneededFor.TEARDOWN)) {
@@ -4260,7 +4339,7 @@
 
     @Override
     public NetworkRequest getDefaultRequest() {
-        return mFallbackRequest.mRequests.get(0);
+        return mDefaultRequest.mRequests.get(0);
     }
 
     private class InternalHandler extends Handler {
@@ -4378,6 +4457,19 @@
                 case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
                     handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
                     break;
+                case EVENT_SET_OEM_NETWORK_PREFERENCE:
+                    final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
+                            (Pair<OemNetworkPreferences,
+                                    IOnSetOemNetworkPreferenceListener>) msg.obj;
+                    try {
+                        handleSetOemNetworkPreference(arg.first, arg.second);
+                    } catch (RemoteException e) {
+                        loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
+                    }
+                    break;
+                case EVENT_REPORT_NETWORK_ACTIVITY:
+                    mNetworkActivityTracker.handleReportNetworkActivity();
+                    break;
             }
         }
     }
@@ -4506,7 +4598,7 @@
         // revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
         final NetworkAgentInfo nai;
         if (network == null) {
-            nai = getFallbackNetwork();
+            nai = getDefaultNetwork();
         } else {
             nai = getNetworkAgentInfoForNetwork(network);
         }
@@ -4525,7 +4617,7 @@
             Network network, int uid, boolean hasConnectivity) {
         final NetworkAgentInfo nai;
         if (network == null) {
-            nai = getFallbackNetwork();
+            nai = getDefaultNetwork();
         } else {
             nai = getNetworkAgentInfoForNetwork(network);
         }
@@ -4594,7 +4686,7 @@
 
     @Override
     public void setGlobalProxy(final ProxyInfo proxyProperties) {
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         mProxyTracker.setGlobalProxy(proxyProperties);
     }
 
@@ -4680,183 +4772,6 @@
     }
 
     /**
-     * Prepare for a VPN application.
-     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
-     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
-     *
-     * @param oldPackage Package name of the application which currently controls VPN, which will
-     *                   be replaced. If there is no such application, this should should either be
-     *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
-     * @param newPackage Package name of the application which should gain control of VPN, or
-     *                   {@code null} to disable.
-     * @param userId User for whom to prepare the new VPN.
-     *
-     * @hide
-     */
-    @Override
-    public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
-            int userId) {
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            Vpn vpn = mVpns.get(userId);
-            if (vpn != null) {
-                return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
-            } else {
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Set whether the VPN package has the ability to launch VPNs without user intervention. This
-     * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
-     * class. If the caller is not {@code userId}, {@link
-     * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
-     *
-     * @param packageName The package for which authorization state should change.
-     * @param userId User for whom {@code packageName} is installed.
-     * @param authorized {@code true} if this app should be able to start a VPN connection without
-     *     explicit user approval, {@code false} if not.
-     * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
-     *     permissions should be granted. When unauthorizing an app, {@link
-     *     VpnManager.TYPE_VPN_NONE} should be used.
-     * @hide
-     */
-    @Override
-    public void setVpnPackageAuthorization(
-            String packageName, int userId, @VpnManager.VpnType int vpnType) {
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn != null) {
-                vpn.setPackageAuthorization(packageName, vpnType);
-            }
-        }
-    }
-
-    /**
-     * Configure a TUN interface and return its file descriptor. Parameters
-     * are encoded and opaque to this class. This method is used by VpnBuilder
-     * and not available in ConnectivityManager. Permissions are checked in
-     * Vpn class.
-     * @hide
-     */
-    @Override
-    public ParcelFileDescriptor establishVpn(VpnConfig config) {
-        int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            return mVpns.get(user).establish(config);
-        }
-    }
-
-    /**
-     * Stores the given VPN profile based on the provisioning package name.
-     *
-     * <p>If there is already a VPN profile stored for the provisioning package, this call will
-     * overwrite the profile.
-     *
-     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
-     * exclusively by the Settings app, and passed into the platform at startup time.
-     *
-     * @return {@code true} if user consent has already been granted, {@code false} otherwise.
-     * @hide
-     */
-    @Override
-    public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
-        }
-    }
-
-    /**
-     * Deletes the stored VPN profile for the provisioning package
-     *
-     * <p>If there are no profiles for the given package, this method will silently succeed.
-     *
-     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
-     * exclusively by the Settings app, and passed into the platform at startup time.
-     *
-     * @hide
-     */
-    @Override
-    public void deleteVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
-        }
-    }
-
-    /**
-     * Starts the VPN based on the stored profile for the given package
-     *
-     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
-     * exclusively by the Settings app, and passed into the platform at startup time.
-     *
-     * @throws IllegalArgumentException if no profile was found for the given package name.
-     * @hide
-     */
-    @Override
-    public void startVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            mVpns.get(user).startVpnProfile(packageName, mKeyStore);
-        }
-    }
-
-    /**
-     * Stops the Platform VPN if the provided package is running one.
-     *
-     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
-     * exclusively by the Settings app, and passed into the platform at startup time.
-     *
-     * @hide
-     */
-    @Override
-    public void stopVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            mVpns.get(user).stopVpnProfile(packageName);
-        }
-    }
-
-    /**
-     * Start legacy VPN, controlling native daemons as needed. Creates a
-     * secondary thread to perform connection work, returning quickly.
-     */
-    @Override
-    public void startLegacyVpn(VpnProfile profile) {
-        int user = UserHandle.getUserId(mDeps.getCallingUid());
-        final LinkProperties egress = getActiveLinkProperties();
-        if (egress == null) {
-            throw new IllegalStateException("Missing active network connection");
-        }
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
-        }
-    }
-
-    /**
-     * Return the information of the ongoing legacy VPN. This method is used
-     * by VpnSettings and not available in ConnectivityManager. Permissions
-     * are checked in Vpn class.
-     */
-    @Override
-    public LegacyVpnInfo getLegacyVpnInfo(int userId) {
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            return mVpns.get(userId).getLegacyVpnInfo();
-        }
-    }
-
-    /**
      * Return the information of all ongoing VPNs.
      *
      * <p>This method is used to update NetworkStatsService.
@@ -4865,10 +4780,8 @@
      */
     private UnderlyingNetworkInfo[] getAllVpnInfo() {
         ensureRunningOnConnectivityServiceThread();
-        synchronized (mVpns) {
-            if (mLockdownEnabled) {
-                return new UnderlyingNetworkInfo[0];
-            }
+        if (mLockdownEnabled) {
+            return new UnderlyingNetworkInfo[0];
         }
         List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
@@ -4891,13 +4804,14 @@
         // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
         // the underlyingNetworks list.
         if (underlyingNetworks == null) {
-            final NetworkAgentInfo defaultNai = getFallbackNetwork();
+            final NetworkAgentInfo defaultNai = getDefaultNetworkForUid(
+                    nai.networkCapabilities.getOwnerUid());
             if (defaultNai != null) {
                 underlyingNetworks = new Network[] { defaultNai.network };
             }
         }
 
-        if (ArrayUtils.isEmpty(underlyingNetworks)) return null;
+        if (CollectionUtils.isEmpty(underlyingNetworks)) return null;
 
         List<String> interfaces = new ArrayList<>();
         for (Network network : underlyingNetworks) {
@@ -4923,27 +4837,10 @@
                 nai.linkProperties.getInterfaceName(), interfaces);
     }
 
-    /**
-     * Returns the information of the ongoing VPN for {@code userId}. This method is used by
-     * VpnDialogs and not available in ConnectivityManager.
-     * Permissions are checked in Vpn class.
-     * @hide
-     */
-    @Override
-    public VpnConfig getVpnConfig(int userId) {
-        enforceCrossUserPermission(userId);
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn != null) {
-                return vpn.getVpnConfig();
-            } else {
-                return null;
-            }
-        }
-    }
-
-    private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
-        final Network defaultNetwork = getNetwork(getFallbackNetwork());
+    // TODO This needs to be the default network that applies to the NAI.
+    private Network[] underlyingNetworksOrDefault(final int ownerUid,
+            Network[] underlyingNetworks) {
+        final Network defaultNetwork = getNetwork(getDefaultNetworkForUid(ownerUid));
         if (underlyingNetworks == null && defaultNetwork != null) {
             // null underlying networks means to track the default.
             underlyingNetworks = new Network[] { defaultNetwork };
@@ -4956,8 +4853,9 @@
         // TODO: support more than one level of underlying networks, either via a fixed-depth search
         // (e.g., 2 levels of underlying networks), or via loop detection, or....
         if (!nai.supportsUnderlyingNetworks()) return false;
-        final Network[] underlying = underlyingNetworksOrDefault(nai.declaredUnderlyingNetworks);
-        return ArrayUtils.contains(underlying, network);
+        final Network[] underlying = underlyingNetworksOrDefault(
+                nai.networkCapabilities.getOwnerUid(), nai.declaredUnderlyingNetworks);
+        return CollectionUtils.contains(underlying, network);
     }
 
     /**
@@ -4990,7 +4888,7 @@
 
     @Override
     public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
-        NetworkStack.checkNetworkStackPermission(mContext);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
                 encodeBool(requireVpn), 0 /* arg2 */, ranges));
     }
@@ -5026,195 +4924,54 @@
         mVpnBlockedUidRanges = newVpnBlockedUidRanges;
     }
 
-    private boolean isLockdownVpnEnabled() {
-        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
-    }
-
     @Override
-    public boolean updateLockdownVpn() {
-        // Allow the system UID for the system server and for Settings.
-        // Also, for unit tests, allow the process that ConnectivityService is running in.
-        if (mDeps.getCallingUid() != Process.SYSTEM_UID
-                && Binder.getCallingPid() != Process.myPid()) {
-            logw("Lockdown VPN only available to system process or AID_SYSTEM");
-            return false;
-        }
-
-        synchronized (mVpns) {
-            // Tear down existing lockdown if profile was removed
-            mLockdownEnabled = isLockdownVpnEnabled();
-            if (mLockdownEnabled) {
-                byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
-                if (profileTag == null) {
-                    loge("Lockdown VPN configured but cannot be read from keystore");
-                    return false;
-                }
-                String profileName = new String(profileTag);
-                final VpnProfile profile = VpnProfile.decode(
-                        profileName, mKeyStore.get(Credentials.VPN + profileName));
-                if (profile == null) {
-                    loge("Lockdown VPN configured invalid profile " + profileName);
-                    setLockdownTracker(null);
-                    return true;
-                }
-                int user = UserHandle.getUserId(mDeps.getCallingUid());
-                Vpn vpn = mVpns.get(user);
-                if (vpn == null) {
-                    logw("VPN for user " + user + " not ready yet. Skipping lockdown");
-                    return false;
-                }
-                setLockdownTracker(
-                        new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn,  profile));
-            } else {
-                setLockdownTracker(null);
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Internally set new {@link LockdownVpnTracker}, shutting down any existing
-     * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
-     */
-    @GuardedBy("mVpns")
-    private void setLockdownTracker(LockdownVpnTracker tracker) {
-        // Shutdown any existing tracker
-        final LockdownVpnTracker existing = mLockdownTracker;
-        // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
-        // necessary onBlockedStatusChanged callbacks.
-        mLockdownTracker = null;
-        if (existing != null) {
-            existing.shutdown();
-        }
-
-        if (tracker != null) {
-            mLockdownTracker = tracker;
-            mLockdownTracker.init();
-        }
-    }
-
-    /**
-     * Throws if there is any currently running, always-on Legacy VPN.
-     *
-     * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
-     * running across the entire system. Tracking for app-based VPNs is done on a per-user,
-     * per-package basis in Vpn.java
-     */
-    @GuardedBy("mVpns")
-    private void throwIfLockdownEnabled() {
-        if (mLockdownEnabled) {
-            throw new IllegalStateException("Unavailable in lockdown mode");
-        }
-    }
-
-    /**
-     * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
-     * some setup and then call {@code establish()} to connect.
-     *
-     * @return {@code true} if the service was started, the service was already connected, or there
-     *         was no always-on VPN to start. {@code false} otherwise.
-     */
-    private boolean startAlwaysOnVpn(int userId) {
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                // Shouldn't happen as all code paths that point here should have checked the Vpn
-                // exists already.
-                Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
-                return false;
-            }
-
-            return vpn.startAlwaysOnVpn(mKeyStore);
-        }
-    }
-
-    @Override
-    public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
+    public void setLegacyLockdownVpnEnabled(boolean enabled) {
         enforceSettingsPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                logw("User " + userId + " has no Vpn configuration");
-                return false;
-            }
-            return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
-        }
+        mHandler.post(() -> mLockdownEnabled = enabled);
     }
 
-    @Override
-    public boolean setAlwaysOnVpnPackage(
-            int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            // Can't set always-on VPN if legacy VPN is already in lockdown mode.
-            if (isLockdownVpnEnabled()) {
-                return false;
-            }
-
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                logw("User " + userId + " has no Vpn configuration");
-                return false;
-            }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
-                return false;
-            }
-            if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
-                return false;
-            }
-        }
-        return true;
+    private boolean isLegacyLockdownNai(NetworkAgentInfo nai) {
+        return mLockdownEnabled
+                && getVpnType(nai) == VpnManager.TYPE_VPN_LEGACY
+                && nai.networkCapabilities.appliesToUid(Process.FIRST_APPLICATION_UID);
     }
 
-    @Override
-    public String getAlwaysOnVpnPackage(int userId) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                logw("User " + userId + " has no Vpn configuration");
-                return null;
-            }
-            return vpn.getAlwaysOnPackage();
+    private NetworkAgentInfo getLegacyLockdownNai() {
+        if (!mLockdownEnabled) {
+            return null;
         }
-    }
+        // The legacy lockdown VPN always only applies to userId 0.
+        final NetworkAgentInfo nai = getVpnForUid(Process.FIRST_APPLICATION_UID);
+        if (nai == null || !isLegacyLockdownNai(nai)) return null;
 
-    @Override
-    public boolean isVpnLockdownEnabled(int userId) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                logw("User " + userId + " has no Vpn configuration");
-                return false;
-            }
-            return vpn.getLockdown();
+        // The legacy lockdown VPN must always have exactly one underlying network.
+        // This code may run on any thread and declaredUnderlyingNetworks may change, so store it in
+        // a local variable. There is no need to make a copy because its contents cannot change.
+        final Network[] underlying = nai.declaredUnderlyingNetworks;
+        if (underlying == null ||  underlying.length != 1) {
+            return null;
         }
-    }
 
-    @Override
-    public List<String> getVpnLockdownWhitelist(int userId) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                logw("User " + userId + " has no Vpn configuration");
-                return null;
-            }
-            return vpn.getLockdownAllowlist();
+        // The legacy lockdown VPN always uses the default network.
+        // If the VPN's underlying network is no longer the current default network, it means that
+        // the default network has just switched, and the VPN is about to disconnect.
+        // Report that the VPN is not connected, so when the state of NetworkInfo objects
+        // overwritten by getLegacyLockdownState will be set to CONNECTING and not CONNECTED.
+        final NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+        if (defaultNetwork == null || !defaultNetwork.network.equals(underlying[0])) {
+            return null;
         }
+
+        return nai;
+    };
+
+    private DetailedState getLegacyLockdownState(DetailedState origState) {
+        if (origState != DetailedState.CONNECTED) {
+            return origState;
+        }
+        return (mLockdownEnabled && getLegacyLockdownNai() == null)
+                ? DetailedState.CONNECTING
+                : DetailedState.CONNECTED;
     }
 
     @Override
@@ -5249,111 +5006,12 @@
         }
     }
 
-    private void onUserStarted(int userId) {
-        synchronized (mVpns) {
-            Vpn userVpn = mVpns.get(userId);
-            if (userVpn != null) {
-                loge("Starting user already has a VPN");
-                return;
-            }
-            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
-            mVpns.put(userId, userVpn);
-            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
-                updateLockdownVpn();
-            }
-        }
+    private void onUserAdded(UserHandle user) {
+        mPermissionMonitor.onUserAdded(user);
     }
 
-    private void onUserStopped(int userId) {
-        synchronized (mVpns) {
-            Vpn userVpn = mVpns.get(userId);
-            if (userVpn == null) {
-                loge("Stopped user has no VPN");
-                return;
-            }
-            userVpn.onUserStopped();
-            mVpns.delete(userId);
-        }
-    }
-
-    private void onUserAdded(int userId) {
-        mPermissionMonitor.onUserAdded(userId);
-        synchronized (mVpns) {
-            final int vpnsSize = mVpns.size();
-            for (int i = 0; i < vpnsSize; i++) {
-                Vpn vpn = mVpns.valueAt(i);
-                vpn.onUserAdded(userId);
-            }
-        }
-    }
-
-    private void onUserRemoved(int userId) {
-        mPermissionMonitor.onUserRemoved(userId);
-        synchronized (mVpns) {
-            final int vpnsSize = mVpns.size();
-            for (int i = 0; i < vpnsSize; i++) {
-                Vpn vpn = mVpns.valueAt(i);
-                vpn.onUserRemoved(userId);
-            }
-        }
-    }
-
-    private void onPackageReplaced(String packageName, int uid) {
-        if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
-            return;
-        }
-        final int userId = UserHandle.getUserId(uid);
-        synchronized (mVpns) {
-            final Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                return;
-            }
-            // Legacy always-on VPN won't be affected since the package name is not set.
-            if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
-                log("Restarting always-on VPN package " + packageName + " for user "
-                        + userId);
-                vpn.startAlwaysOnVpn(mKeyStore);
-            }
-        }
-    }
-
-    private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
-        if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
-            return;
-        }
-
-        final int userId = UserHandle.getUserId(uid);
-        synchronized (mVpns) {
-            final Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                return;
-            }
-            // Legacy always-on VPN won't be affected since the package name is not set.
-            if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
-                log("Removing always-on VPN package " + packageName + " for user "
-                        + userId);
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
-            }
-        }
-    }
-
-    private void onUserUnlocked(int userId) {
-        synchronized (mVpns) {
-            // User present may be sent because of an unlock, which might mean an unlocked keystore.
-            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
-                updateLockdownVpn();
-            } else {
-                startAlwaysOnVpn(userId);
-            }
-        }
-    }
-
-    private void onVpnLockdownReset() {
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) mLockdownTracker.reset();
-        }
+    private void onUserRemoved(UserHandle user) {
+        mPermissionMonitor.onUserRemoved(user);
     }
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -5361,80 +5019,45 @@
         public void onReceive(Context context, Intent intent) {
             ensureRunningOnConnectivityServiceThread();
             final String action = intent.getAction();
-            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
-            final Uri packageData = intent.getData();
-            final String packageName =
-                    packageData != null ? packageData.getSchemeSpecificPart() : null;
+            final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
 
-            if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
-                onVpnLockdownReset();
+            // User should be filled for below intents, check the existence.
+            if (user == null) {
+                Log.wtf(TAG, intent.getAction() + " broadcast without EXTRA_USER");
+                return;
             }
 
-            // UserId should be filled for below intents, check the existence.
-            if (userId == UserHandle.USER_NULL) return;
-
-            if (Intent.ACTION_USER_STARTED.equals(action)) {
-                onUserStarted(userId);
-            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                onUserStopped(userId);
-            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
-                onUserAdded(userId);
+            if (Intent.ACTION_USER_ADDED.equals(action)) {
+                onUserAdded(user);
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                onUserRemoved(userId);
-            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
-                onUserUnlocked(userId);
-            } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
-                onPackageReplaced(packageName, uid);
-            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
-                final boolean isReplacing = intent.getBooleanExtra(
-                        Intent.EXTRA_REPLACING, false);
-                onPackageRemoved(packageName, uid, isReplacing);
-            } else {
+                onUserRemoved(user);
+            }  else {
                 Log.wtf(TAG, "received unexpected intent: " + action);
             }
         }
     };
 
-    private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // Try creating lockdown tracker, since user present usually means
-            // unlocked keystore.
-            updateLockdownVpn();
-            // Use the same context that registered receiver before to unregister it. Because use
-            // different context to unregister receiver will cause exception.
-            context.unregisterReceiver(this);
-        }
-    };
-
     private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
 
     private static class NetworkProviderInfo {
         public final String name;
         public final Messenger messenger;
-        private final AsyncChannel mAsyncChannel;
         private final IBinder.DeathRecipient mDeathRecipient;
         public final int providerId;
 
         NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
-                int providerId, IBinder.DeathRecipient deathRecipient) {
+                int providerId, @NonNull IBinder.DeathRecipient deathRecipient) {
             this.name = name;
             this.messenger = messenger;
             this.providerId = providerId;
-            mAsyncChannel = asyncChannel;
             mDeathRecipient = deathRecipient;
 
-            if ((mAsyncChannel == null) == (mDeathRecipient == null)) {
-                throw new AssertionError("Must pass exactly one of asyncChannel or deathRecipient");
+            if (mDeathRecipient == null) {
+                throw new AssertionError("Must pass a deathRecipient");
             }
         }
 
-        boolean isLegacyNetworkFactory() {
-            return mAsyncChannel != null;
-        }
-
         void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) {
             try {
                 messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj));
@@ -5445,38 +5068,19 @@
         }
 
         void requestNetwork(NetworkRequest request, int score, int servingProviderId) {
-            if (isLegacyNetworkFactory()) {
-                mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
-                        servingProviderId, request);
-            } else {
-                sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score,
+            sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score,
                             servingProviderId, request);
-            }
         }
 
         void cancelRequest(NetworkRequest request) {
-            if (isLegacyNetworkFactory()) {
-                mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request);
-            } else {
-                sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request);
-            }
+            sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request);
         }
 
         void connect(Context context, Handler handler) {
-            if (isLegacyNetworkFactory()) {
-                mAsyncChannel.connect(context, handler, messenger);
-            } else {
-                try {
-                    messenger.getBinder().linkToDeath(mDeathRecipient, 0);
-                } catch (RemoteException e) {
-                    mDeathRecipient.binderDied();
-                }
-            }
-        }
-
-        void completeConnection() {
-            if (isLegacyNetworkFactory()) {
-                mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+            try {
+                messenger.getBinder().linkToDeath(mDeathRecipient, 0);
+            } catch (RemoteException e) {
+                mDeathRecipient.binderDied();
             }
         }
     }
@@ -5512,9 +5116,8 @@
             mActiveRequest = activeRequest;
         }
 
-        // The network currently satisfying this request, or null if none. Must only be touched
-        // on the handler thread. This only makes sense for network requests and not for listens,
-        // as defined by NetworkRequest#isRequest(). For listens, this is always null.
+        // The network currently satisfying this NRI. Only one request in an NRI can have a
+        // satisfier. For non-multilayer requests, only non-listen requests can have a satisfier.
         @Nullable
         private NetworkAgentInfo mSatisfier;
         NetworkAgentInfo getSatisfier() {
@@ -5532,32 +5135,81 @@
 
         final PendingIntent mPendingIntent;
         boolean mPendingIntentSent;
+        @Nullable
+        final Messenger mMessenger;
+        @Nullable
         private final IBinder mBinder;
         final int mPid;
         final int mUid;
-        final Messenger messenger;
+        @Nullable
+        final String mCallingAttributionTag;
+        // In order to preserve the mapping of NetworkRequest-to-callback when apps register
+        // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
+        // maintained for keying off of. This is only a concern when the original nri
+        // mNetworkRequests changes which happens currently for apps that register callbacks to
+        // track the default network. In those cases, the nri is updated to have mNetworkRequests
+        // that match the per-app default nri that currently tracks the calling app's uid so that
+        // callbacks are fired at the appropriate time. When the callbacks fire,
+        // mNetworkRequestForCallback will be used so as to preserve the caller's mapping. When
+        // callbacks are updated to key off of an nri vs NetworkRequest, this stops being an issue.
+        // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects.
+        @NonNull
+        private final NetworkRequest mNetworkRequestForCallback;
+        NetworkRequest getNetworkRequestForCallback() {
+            return mNetworkRequestForCallback;
+        }
 
-        NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
+        /**
+         * Get the list of UIDs this nri applies to.
+         */
+        @NonNull
+        private Set<UidRange> getUids() {
+            // networkCapabilities.getUids() returns a defensive copy.
+            // multilayer requests will all have the same uids so return the first one.
+            final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids()
+                    ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids();
+            return uids;
+        }
+
+        NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
+                @Nullable String callingAttributionTag) {
+            this(Collections.singletonList(r), r, pi, callingAttributionTag);
+        }
+
+        NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+                @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
+                @Nullable String callingAttributionTag) {
+            ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
-            ensureAllNetworkRequestsHaveType(mRequests);
+            mNetworkRequestForCallback = requestForCallback;
             mPendingIntent = pi;
-            messenger = null;
+            mMessenger = null;
             mBinder = null;
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mCallingAttributionTag = callingAttributionTag;
         }
 
-        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
+        NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
+                @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+            this(Collections.singletonList(r), r, m, binder, callingAttributionTag);
+        }
+
+        NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+                @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
+                @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
             super();
-            messenger = m;
+            ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
-            ensureAllNetworkRequestsHaveType(mRequests);
+            mNetworkRequestForCallback = requestForCallback;
+            mMessenger = m;
             mBinder = binder;
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mPendingIntent = null;
             mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mCallingAttributionTag = callingAttributionTag;
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -5566,17 +5218,43 @@
             }
         }
 
-        NetworkRequestInfo(NetworkRequest r) {
-            this(r, null);
+        NetworkRequestInfo(@NonNull final NetworkRequestInfo nri,
+                @NonNull final List<NetworkRequest> r) {
+            super();
+            ensureAllNetworkRequestsHaveType(r);
+            mRequests = initializeRequests(r);
+            mNetworkRequestForCallback = nri.getNetworkRequestForCallback();
+            mMessenger = nri.mMessenger;
+            mBinder = nri.mBinder;
+            mPid = nri.mPid;
+            mUid = nri.mUid;
+            mPendingIntent = nri.mPendingIntent;
+            mCallingAttributionTag = nri.mCallingAttributionTag;
+        }
+
+        NetworkRequestInfo(@NonNull final NetworkRequest r) {
+            this(Collections.singletonList(r));
+        }
+
+        NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
+            this(r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+        }
+
+        // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
+        // set to the mNoServiceNetwork in which case mActiveRequest will be null thus returning
+        // false.
+        boolean isBeingSatisfied() {
+            return (null != mSatisfier && null != mActiveRequest);
         }
 
         boolean isMultilayerRequest() {
             return mRequests.size() > 1;
         }
 
-        private List<NetworkRequest> initializeRequests(NetworkRequest r) {
-            final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
-            tempRequests.add(new NetworkRequest(r));
+        private List<NetworkRequest> initializeRequests(List<NetworkRequest> r) {
+            // Creating a defensive copy to prevent the sender from modifying the list being
+            // reflected in the return value of this method.
+            final List<NetworkRequest> tempRequests = new ArrayList<>(r);
             return Collections.unmodifiableList(tempRequests);
         }
 
@@ -5595,7 +5273,9 @@
 
         @Override
         public String toString() {
-            return "uid/pid:" + mUid + "/" + mPid + " " + mRequests
+            return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
+                    + (mActiveRequest == null ? null : mActiveRequest.requestId)
+                    + " " + mRequests
                     + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
         }
     }
@@ -5639,8 +5319,7 @@
                 }
             }
         }
-        // TODO: use NetworkStackUtils.convertToIntArray after moving it
-        return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds));
+        return CollectionUtils.toIntArray(new ArrayList<>(thresholds));
     }
 
     private void updateSignalStrengthThresholds(
@@ -5703,6 +5382,7 @@
                 throw new SecurityException("Insufficient permissions to specify legacy type");
             }
         }
+        final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
         final int callingUid = mDeps.getCallingUid();
         final NetworkRequest.Type reqType;
         try {
@@ -5713,11 +5393,16 @@
         switch (reqType) {
             case TRACK_DEFAULT:
                 // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
-                // is unused and will be replaced by the one from the default network request.
-                // This allows callers to keep track of the system default network.
-                networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
+                // is unused and will be replaced by ones appropriate for the caller.
+                // This allows callers to keep track of the default network for their app.
+                networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
+                        defaultNc, callingUid, callingPackageName);
                 enforceAccessPermission();
                 break;
+            case TRACK_SYSTEM_DEFAULT:
+                enforceSettingsPermission();
+                networkCapabilities = new NetworkCapabilities(defaultNc);
+                break;
             case BACKGROUND_REQUEST:
                 enforceNetworkStackOrSettingsPermission();
                 // Fall-through since other checks are the same with normal requests.
@@ -5736,6 +5421,7 @@
         ensureRequestableCapabilities(networkCapabilities);
         ensureSufficientPermissionsForRequest(networkCapabilities,
                 Binder.getCallingPid(), callingUid, callingPackageName);
+
         // Set the UID range for this request to the single UID of the requester, or to an empty
         // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
         // This will overwrite any allowed UIDs in the requested capabilities. Though there
@@ -5749,11 +5435,23 @@
         }
         ensureValid(networkCapabilities);
 
-        NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
+        final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId(), reqType);
-        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+        final NetworkRequestInfo nri = getNriToRegister(
+                networkRequest, messenger, binder, callingAttributionTag);
         if (DBG) log("requestNetwork for " + nri);
 
+        // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
+        // copied from the default request above. (This is necessary to ensure, for example, that
+        // the callback does not leak sensitive information to unprivileged apps.) Check that the
+        // changes don't alter request matching.
+        if (reqType == NetworkRequest.Type.TRACK_SYSTEM_DEFAULT &&
+                (!networkCapabilities.equalRequestableCapabilities(defaultNc))) {
+            throw new IllegalStateException(
+                    "TRACK_SYSTEM_DEFAULT capabilities don't match default request: "
+                    + networkCapabilities + " vs. " + defaultNc);
+        }
+
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
         if (timeoutMs > 0) {
             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
@@ -5762,6 +5460,30 @@
         return networkRequest;
     }
 
+    /**
+     * Return the nri to be used when registering a network request. Specifically, this is used with
+     * requests registered to track the default request. If there is currently a per-app default
+     * tracking the app requestor, then we need to create a version of this nri that mirrors that of
+     * the tracking per-app default so that callbacks are sent to the app requestor appropriately.
+     * @param nr the network request for the nri.
+     * @param msgr the messenger for the nri.
+     * @param binder the binder for the nri.
+     * @param callingAttributionTag the calling attribution tag for the nri.
+     * @return the nri to register.
+     */
+    private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
+            @Nullable final Messenger msgr, @Nullable final IBinder binder,
+            @Nullable String callingAttributionTag) {
+        final List<NetworkRequest> requests;
+        if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
+            requests = copyDefaultNetworkRequestsForUid(
+                    nr.getRequestorUid(), nr.getRequestorPackageName());
+        } else {
+            requests = Collections.singletonList(nr);
+        }
+        return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag);
+    }
+
     private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
             String callingPackageName, String callingAttributionTag) {
         if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
@@ -5840,7 +5562,8 @@
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
                 nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
-        NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+        NetworkRequestInfo nri =
+                new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
         if (DBG) log("pendingRequest for " + nri);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
                 nri));
@@ -5884,7 +5607,8 @@
 
     @Override
     public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, IBinder binder, @NonNull String callingPackageName) {
+            Messenger messenger, IBinder binder, @NonNull String callingPackageName,
+            @Nullable String callingAttributionTag) {
         final int callingUid = mDeps.getCallingUid();
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
@@ -5904,7 +5628,8 @@
 
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
-        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+        NetworkRequestInfo nri =
+                new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
         if (VDBG) log("listenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5913,7 +5638,8 @@
 
     @Override
     public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
-            PendingIntent operation, @NonNull String callingPackageName) {
+            PendingIntent operation, @NonNull String callingPackageName,
+            @Nullable String callingAttributionTag) {
         Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         final int callingUid = mDeps.getCallingUid();
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
@@ -5927,7 +5653,8 @@
 
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
-        NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+        NetworkRequestInfo nri =
+                new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
         if (VDBG) log("pendingListenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5951,15 +5678,6 @@
                 EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest));
     }
 
-    @Override
-    public int registerNetworkFactory(Messenger messenger, String name) {
-        enforceNetworkFactoryPermission();
-        NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger, new AsyncChannel(),
-                nextNetworkProviderId(), null /* deathRecipient */);
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
-        return npi.providerId;
-    }
-
     private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
         if (mNetworkProviderInfos.containsKey(npi.messenger)) {
             // Avoid creating duplicates. even if an app makes a direct AIDL call.
@@ -5973,10 +5691,7 @@
         if (DBG) log("Got NetworkProvider Messenger for " + npi.name);
         mNetworkProviderInfos.put(npi.messenger, npi);
         npi.connect(mContext, mTrackerHandler);
-        if (!npi.isLegacyNetworkFactory()) {
-            // Legacy NetworkFactories get their requests when their AsyncChannel connects.
-            sendAllRequestsToProvider(npi);
-        }
+        sendAllRequestsToProvider(npi);
     }
 
     @Override
@@ -5995,11 +5710,6 @@
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_PROVIDER, messenger));
     }
 
-    @Override
-    public void unregisterNetworkFactory(Messenger messenger) {
-        unregisterNetworkProvider(messenger);
-    }
-
     private void handleUnregisterNetworkProvider(Messenger messenger) {
         NetworkProviderInfo npi = mNetworkProviderInfos.remove(messenger);
         if (npi == null) {
@@ -6047,13 +5757,136 @@
     @GuardedBy("mBlockedAppUids")
     private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
 
+    // Current OEM network preferences.
+    @NonNull
+    private OemNetworkPreferences mOemNetworkPreferences =
+            new OemNetworkPreferences.Builder().build();
+
     // The always-on request for an Internet-capable network that apps without a specific default
     // fall back to.
+    @VisibleForTesting
     @NonNull
-    private final NetworkRequestInfo mFallbackRequest;
+    final NetworkRequestInfo mDefaultRequest;
     // Collection of NetworkRequestInfo's used for default networks.
+    @VisibleForTesting
     @NonNull
-    private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
+    final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
+
+    private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) {
+        return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri);
+    }
+
+    /**
+     * Return the default network request currently tracking the given uid.
+     * @param uid the uid to check.
+     * @return the NetworkRequestInfo tracking the given uid.
+     */
+    @NonNull
+    private NetworkRequestInfo getDefaultRequestTrackingUid(@NonNull final int uid) {
+        for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
+            if (nri == mDefaultRequest) {
+                continue;
+            }
+            // Checking the first request is sufficient as only multilayer requests will have more
+            // than one request and for multilayer, all requests will track the same uids.
+            if (nri.mRequests.get(0).networkCapabilities.appliesToUid(uid)) {
+                return nri;
+            }
+        }
+        return mDefaultRequest;
+    }
+
+    /**
+     * Get a copy of the network requests of the default request that is currently tracking the
+     * given uid.
+     * @param requestorUid the uid to check the default for.
+     * @param requestorPackageName the requestor's package name.
+     * @return a copy of the default's NetworkRequest that is tracking the given uid.
+     */
+    @NonNull
+    private List<NetworkRequest> copyDefaultNetworkRequestsForUid(
+            @NonNull final int requestorUid, @NonNull final String requestorPackageName) {
+        return copyNetworkRequestsForUid(
+                getDefaultRequestTrackingUid(requestorUid).mRequests,
+                requestorUid, requestorPackageName);
+    }
+
+    /**
+     * Copy the given nri's NetworkRequest collection.
+     * @param requestsToCopy the NetworkRequest collection to be copied.
+     * @param requestorUid the uid to set on the copied collection.
+     * @param requestorPackageName the package name to set on the copied collection.
+     * @return the copied NetworkRequest collection.
+     */
+    @NonNull
+    private List<NetworkRequest> copyNetworkRequestsForUid(
+            @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid,
+            @NonNull final String requestorPackageName) {
+        final List<NetworkRequest> requests = new ArrayList<>();
+        for (final NetworkRequest nr : requestsToCopy) {
+            requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid(
+                            nr.networkCapabilities, requestorUid, requestorPackageName),
+                    nr.legacyType, nextNetworkRequestId(), nr.type));
+        }
+        return requests;
+    }
+
+    @NonNull
+    private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid(
+            @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid,
+            @NonNull final String requestorPackageName) {
+        final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy);
+        netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
+        netCap.setSingleUid(requestorUid);
+        netCap.setUids(new ArraySet<>());
+        restrictRequestUidsForCallerAndSetRequestorInfo(
+                netCap, requestorUid, requestorPackageName);
+        return netCap;
+    }
+
+    /**
+     * Get the nri that is currently being tracked for callbacks by per-app defaults.
+     * @param nr the network request to check for equality against.
+     * @return the nri if one exists, null otherwise.
+     */
+    @Nullable
+    private NetworkRequestInfo getNriForAppRequest(@NonNull final NetworkRequest nr) {
+        for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+            if (nri.getNetworkRequestForCallback().equals(nr)) {
+                return nri;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check if an nri is currently being managed by per-app default networking.
+     * @param nri the nri to check.
+     * @return true if this nri is currently being managed by per-app default networking.
+     */
+    private boolean isPerAppTrackedNri(@NonNull final NetworkRequestInfo nri) {
+        // nri.mRequests.get(0) is only different from the original request filed in
+        // nri.getNetworkRequestForCallback() if nri.mRequests was changed by per-app default
+        // functionality therefore if these two don't match, it means this particular nri is
+        // currently being managed by a per-app default.
+        return nri.getNetworkRequestForCallback() != nri.mRequests.get(0);
+    }
+
+    /**
+     * Determine if an nri is a managed default request that disallows default networking.
+     * @param nri the request to evaluate
+     * @return true if device-default networking is disallowed
+     */
+    private boolean isDefaultBlocked(@NonNull final NetworkRequestInfo nri) {
+        // Check if this nri is a managed default that supports the default network at its
+        // lowest priority request.
+        final NetworkRequest defaultNetworkRequest = mDefaultRequest.mRequests.get(0);
+        final NetworkCapabilities lowestPriorityNetCap =
+                nri.mRequests.get(nri.mRequests.size() - 1).networkCapabilities;
+        return isPerAppDefaultRequest(nri)
+                && !(defaultNetworkRequest.networkCapabilities.equalRequestableCapabilities(
+                        lowestPriorityNetCap));
+    }
 
     // Request used to optionally keep mobile data active even when higher
     // priority networks like Wi-Fi are active.
@@ -6066,10 +5899,37 @@
     // Request used to optionally keep vehicle internal network always active
     private final NetworkRequest mDefaultVehicleRequest;
 
-    // TODO: b/178729499 update this in favor of a method taking in a UID.
-    // The NetworkAgentInfo currently satisfying the fallback request, if any.
-    private NetworkAgentInfo getFallbackNetwork() {
-        return mFallbackRequest.mSatisfier;
+    // TODO replace with INetd.DUMMY_NET_ID when available.
+    private static final int NO_SERVICE_NET_ID = 51;
+    // Sentinel NAI used to direct apps with default networks that should have no connectivity to a
+    // network with no service. This NAI should never be matched against, nor should any public API
+    // ever return the associated network. For this reason, this NAI is not in the list of available
+    // NAIs. It is used in computeNetworkReassignment() to be set as the satisfier for non-device
+    // default requests that don't support using the device default network which will ultimately
+    // allow ConnectivityService to use this no-service network when calling makeDefaultForApps().
+    @VisibleForTesting
+    final NetworkAgentInfo mNoServiceNetwork;
+
+    // The NetworkAgentInfo currently satisfying the default request, if any.
+    private NetworkAgentInfo getDefaultNetwork() {
+        return mDefaultRequest.mSatisfier;
+    }
+
+    private NetworkAgentInfo getDefaultNetworkForUid(final int uid) {
+        for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
+            // Currently, all network requests will have the same uids therefore checking the first
+            // one is sufficient. If/when uids are tracked at the nri level, this can change.
+            final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids();
+            if (null == uids) {
+                continue;
+            }
+            for (final UidRange range : uids) {
+                if (range.contains(uid)) {
+                    return nri.getSatisfier();
+                }
+            }
+        }
+        return getDefaultNetwork();
     }
 
     @Nullable
@@ -6086,8 +5946,8 @@
     }
 
     @VisibleForTesting
-    protected boolean isFallbackNetwork(NetworkAgentInfo nai) {
-        return nai == getFallbackNetwork();
+    protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
+        return nai == getDefaultNetwork();
     }
 
     // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
@@ -6156,8 +6016,6 @@
 
         LinkProperties lp = new LinkProperties(linkProperties);
 
-        // TODO: Instead of passing mFallbackRequest, provide an API to determine whether a Network
-        // satisfies mFallbackRequest.
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
@@ -6234,7 +6092,7 @@
 //        for (LinkProperties lp : newLp.getStackedLinks()) {
 //            updateMtu(lp, null);
 //        }
-        if (isFallbackNetwork(networkAgent)) {
+        if (isDefaultNetwork(networkAgent)) {
             updateTcpBufferSizes(newLp.getTcpBufferSizes());
         }
 
@@ -6246,7 +6104,7 @@
         // updateDnses will fetch the private DNS configuration from DnsManager.
         mDnsManager.updatePrivateDnsStatus(netId, newLp);
 
-        if (isFallbackNetwork(networkAgent)) {
+        if (isDefaultNetwork(networkAgent)) {
             handleApplyDefaultProxy(newLp.getHttpProxy());
         } else {
             updateProxy(newLp, oldLp);
@@ -6311,20 +6169,18 @@
                     Math.max(naData.getRefreshTimeMillis(), apiData.getRefreshTimeMillis()));
         }
 
-        // Prioritize the user portal URL from the network agent.
-        if (apiData.getUserPortalUrl() != null && (naData.getUserPortalUrl() == null
-                || TextUtils.isEmpty(naData.getUserPortalUrl().toSafeString()))) {
-            captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl());
+        // Prioritize the user portal URL from the network agent if the source is authenticated.
+        if (apiData.getUserPortalUrl() != null && naData.getUserPortalUrlSource()
+                != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
+            captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl(),
+                    apiData.getUserPortalUrlSource());
         }
-        // Prioritize the venue information URL from the network agent.
-        if (apiData.getVenueInfoUrl() != null && (naData.getVenueInfoUrl() == null
-                || TextUtils.isEmpty(naData.getVenueInfoUrl().toSafeString()))) {
-            captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl());
-
-            // Note that venue friendly name can only come from the network agent because it is not
-            // in use in RFC8908. However, if using the Capport venue URL, make sure that the
-            // friendly name is not set from the network agent.
-            captivePortalBuilder.setVenueFriendlyName(null);
+        // Prioritize the venue information URL from the network agent if the source is
+        // authenticated.
+        if (apiData.getVenueInfoUrl() != null && naData.getVenueInfoUrlSource()
+                != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
+            captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl(),
+                    apiData.getVenueInfoUrlSource());
         }
         return captivePortalBuilder.build();
     }
@@ -6580,8 +6436,9 @@
     @VisibleForTesting
     void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
             @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
-        underlyingNetworks = underlyingNetworksOrDefault(underlyingNetworks);
-        int[] transportTypes = agentCaps.getTransportTypes();
+        underlyingNetworks = underlyingNetworksOrDefault(
+                agentCaps.getOwnerUid(), underlyingNetworks);
+        long transportTypes = BitUtils.packBits(agentCaps.getTransportTypes());
         int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
         int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
         // metered if any underlying is metered, or originally declared metered by the agent.
@@ -6600,7 +6457,7 @@
                 final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
                 hadUnderlyingNetworks = true;
                 for (int underlyingType : underlyingCaps.getTransportTypes()) {
-                    transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+                    transportTypes |= 1L << underlyingType;
                 }
 
                 // Merge capabilities of this underlying network. For bandwidth, assume the
@@ -6631,7 +6488,7 @@
             suspended = false;
         }
 
-        newNc.setTransportTypes(transportTypes);
+        newNc.setTransportTypes(BitUtils.unpackBits(transportTypes));
         newNc.setLinkDownstreamBandwidthKbps(downKbps);
         newNc.setLinkUpstreamBandwidthKbps(upKbps);
         newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
@@ -6952,8 +6809,8 @@
     private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest nr = nai.requestAt(i);
-            // Don't send listening requests to factories. b/17393458
-            if (nr.isListen()) continue;
+            // Don't send listening or track default request to factories. b/17393458
+            if (!nr.isRequest()) continue;
             sendUpdatedScoreToFactories(nr, nai);
         }
     }
@@ -7015,10 +6872,10 @@
         ensureRunningOnConnectivityServiceThread();
         for (final NetworkRequestInfo nri : getNrisFromGlobalRequests()) {
             for (final NetworkRequest req : nri.mRequests) {
-                if (req.isListen() && nri.getActiveRequest() == req) {
+                if (!req.isRequest() && nri.getActiveRequest() == req) {
                     break;
                 }
-                if (req.isListen()) {
+                if (!req.isRequest()) {
                     continue;
                 }
                 // Only set the nai for the request it is satisfying.
@@ -7086,20 +6943,16 @@
     private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
             @NonNull final NetworkAgentInfo networkAgent, final int notificationType,
             final int arg1) {
-        if (nri.messenger == null) {
+        if (nri.mMessenger == null) {
             // Default request has no msgr. Also prevents callbacks from being invoked for
             // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
             // are Type.LISTEN, but should not have NetworkCallbacks invoked.
             return;
         }
         Bundle bundle = new Bundle();
-        // In the case of multi-layer NRIs, the first request is not necessarily the one that
-        // is satisfied. This is vexing, but the ConnectivityManager code that receives this
-        // callback is only using the request as a token to identify the callback, so it doesn't
-        // matter too much at this point as long as the callback can be found.
         // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects.
         // TODO: check if defensive copies of data is needed.
-        final NetworkRequest nrForCallback = new NetworkRequest(nri.mRequests.get(0));
+        final NetworkRequest nrForCallback = nri.getNetworkRequestForCallback();
         putParcelable(bundle, nrForCallback);
         Message msg = Message.obtain();
         if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
@@ -7113,7 +6966,8 @@
                 putParcelable(
                         bundle,
                         createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                nc, nri.mUid, nrForCallback.getRequestorPackageName()));
+                                nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+                                nri.mCallingAttributionTag));
                 putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
                         networkAgent.linkProperties, nri.mPid, nri.mUid));
                 // For this notification, arg1 contains the blocked status.
@@ -7132,7 +6986,8 @@
                 putParcelable(
                         bundle,
                         createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                netCap, nri.mUid, nrForCallback.getRequestorPackageName()));
+                                netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+                                nri.mCallingAttributionTag));
                 break;
             }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
@@ -7153,7 +7008,7 @@
                 String notification = ConnectivityManager.getCallbackName(notificationType);
                 log("sending notification " + notification + " for " + nrForCallback);
             }
-            nri.messenger.send(msg);
+            nri.mMessenger.send(msg);
         } catch (RemoteException e) {
             // may occur naturally in the race of binder death.
             loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
@@ -7168,8 +7023,8 @@
         if (nai.numRequestNetworkRequests() != 0) {
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
                 NetworkRequest nr = nai.requestAt(i);
-                // Ignore listening requests.
-                if (nr.isListen()) continue;
+                // Ignore listening and track default requests.
+                if (!nr.isRequest()) continue;
                 loge("Dead network still had at least " + nr);
                 break;
             }
@@ -7186,13 +7041,13 @@
 
         // If we get here it means that the last linger timeout for this network expired. So there
         // must be no other active linger timers, and we must stop lingering.
-        oldNetwork.clearLingerState();
+        oldNetwork.clearInactivityState();
 
         if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
             // Tear the network down.
             teardownUnneededNetwork(oldNetwork);
         } else {
-            // Put the network in the background.
+            // Put the network in the background if it doesn't satisfy any foreground request.
             updateCapabilitiesForNetwork(oldNetwork);
         }
     }
@@ -7224,35 +7079,29 @@
             log("Switching to new default network for: " + nri + " using " + newDefaultNetwork);
         }
 
-        try {
-            // TODO http://b/176191930 update netd calls in follow-up CL for multinetwork changes.
-            if (mFallbackRequest != nri) {
-                return;
-            }
-
-            if (null != newDefaultNetwork) {
-                mNetd.networkSetDefault(newDefaultNetwork.network.getNetId());
-            } else {
-                mNetd.networkClearDefault();
-            }
-        } catch (RemoteException | ServiceSpecificException e) {
-            loge("Exception setting default network :" + e);
+        // Fix up the NetworkCapabilities of any networks that have this network as underlying.
+        if (newDefaultNetwork != null) {
+            propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network);
         }
 
+        // Set an app level managed default and return since further processing only applies to the
+        // default network.
+        if (mDefaultRequest != nri) {
+            makeDefaultForApps(nri, oldDefaultNetwork, newDefaultNetwork);
+            return;
+        }
+
+        makeDefaultNetwork(newDefaultNetwork);
+
         if (oldDefaultNetwork != null) {
             mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
         }
         mNetworkActivityTracker.updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
-        notifyLockdownVpn(newDefaultNetwork);
         handleApplyDefaultProxy(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getHttpProxy() : null);
         updateTcpBufferSizes(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
-        // Fix up the NetworkCapabilities of any networks that have this network as underlying.
-        if (newDefaultNetwork != null) {
-            propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network);
-        }
 
         // Log 0 -> X and Y -> X default network transitions, where X is the new default.
         final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
@@ -7276,6 +7125,49 @@
                 prevNetwork, prevScore, prevLp, prevNc);
     }
 
+    private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri,
+            @Nullable final NetworkAgentInfo oldDefaultNetwork,
+            @Nullable final NetworkAgentInfo newDefaultNetwork) {
+        try {
+            if (VDBG) {
+                log("Setting default network for " + nri
+                        + " using UIDs " + nri.getUids()
+                        + " with old network " + (oldDefaultNetwork != null
+                        ? oldDefaultNetwork.network().getNetId() : "null")
+                        + " and new network " + (newDefaultNetwork != null
+                        ? newDefaultNetwork.network().getNetId() : "null"));
+            }
+            if (nri.getUids().isEmpty()) {
+                throw new IllegalStateException("makeDefaultForApps called without specifying"
+                        + " any applications to set as the default." + nri);
+            }
+            if (null != newDefaultNetwork) {
+                mNetd.networkAddUidRanges(
+                        newDefaultNetwork.network.getNetId(),
+                        toUidRangeStableParcels(nri.getUids()));
+            }
+            if (null != oldDefaultNetwork) {
+                mNetd.networkRemoveUidRanges(
+                        oldDefaultNetwork.network.getNetId(),
+                        toUidRangeStableParcels(nri.getUids()));
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Exception setting OEM network preference default network :" + e);
+        }
+    }
+
+    private void makeDefaultNetwork(@Nullable final NetworkAgentInfo newDefaultNetwork) {
+        try {
+            if (null != newDefaultNetwork) {
+                mNetd.networkSetDefault(newDefaultNetwork.network.getNetId());
+            } else {
+                mNetd.networkClearDefault();
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Exception setting default network :" + e);
+        }
+    }
+
     private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
         // For consistency with previous behaviour, send onLost callbacks before onAvailable.
         processNewlyLostListenRequests(nai);
@@ -7397,9 +7289,9 @@
             @Nullable final NetworkAgentInfo previousSatisfier,
             @Nullable final NetworkAgentInfo newSatisfier,
             final long now) {
-        if (newSatisfier != null) {
+        if (null != newSatisfier && mNoServiceNetwork != newSatisfier) {
             if (VDBG) log("rematch for " + newSatisfier.toShortString());
-            if (previousSatisfier != null) {
+            if (null != previousSatisfier && mNoServiceNetwork != previousSatisfier) {
                 if (VDBG || DDBG) {
                     log("   accepting network in place of " + previousSatisfier.toShortString());
                 }
@@ -7408,12 +7300,20 @@
             } else {
                 if (VDBG || DDBG) log("   accepting network in place of null");
             }
+
+            // To prevent constantly CPU wake up for nascent timer, if a network comes up
+            // and immediately satisfies a request then remove the timer. This will happen for
+            // all networks except in the case of an underlying network for a VCN.
+            if (newSatisfier.isNascent()) {
+                newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
+            }
+
             newSatisfier.unlingerRequest(newRequest.requestId);
             if (!newSatisfier.addRequest(newRequest)) {
                 Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
                         + newRequest);
             }
-        } else {
+        } else if (null != previousSatisfier) {
             if (DBG) {
                 log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
                         + " request " + previousRequest.requestId);
@@ -7464,7 +7364,11 @@
                     break;
                 }
             }
-            if (bestNetwork != nri.mSatisfier) {
+            if (null == bestNetwork && isDefaultBlocked(nri)) {
+                // Remove default networking if disallowed for managed default requests.
+                bestNetwork = mNoServiceNetwork;
+            }
+            if (nri.getSatisfier() != bestNetwork) {
                 // bestNetwork may be null if no network can satisfy this request.
                 changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
                         nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));
@@ -7546,19 +7450,19 @@
             }
         }
 
-        // Update the linger state before processing listen callbacks, because the background
-        // computation depends on whether the network is lingering. Don't send the LOSING callbacks
+        // Update the inactivity state before processing listen callbacks, because the background
+        // computation depends on whether the network is inactive. Don't send the LOSING callbacks
         // just yet though, because they have to be sent after the listens are processed to keep
         // backward compatibility.
-        final ArrayList<NetworkAgentInfo> lingeredNetworks = new ArrayList<>();
+        final ArrayList<NetworkAgentInfo> inactiveNetworks = new ArrayList<>();
         for (final NetworkAgentInfo nai : nais) {
-            // Rematching may have altered the linger state of some networks, so update all linger
-            // timers. updateLingerState reads the state from the network agent and does nothing
-            // if the state has not changed : the source of truth is controlled with
-            // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
-            // called while rematching the individual networks above.
-            if (updateLingerState(nai, now)) {
-                lingeredNetworks.add(nai);
+            // Rematching may have altered the inactivity state of some networks, so update all
+            // inactivity timers. updateInactivityState reads the state from the network agent
+            // and does nothing if the state has not changed : the source of truth is controlled
+            // with NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which
+            // have been called while rematching the individual networks above.
+            if (updateInactivityState(nai, now)) {
+                inactiveNetworks.add(nai);
             }
         }
 
@@ -7575,7 +7479,11 @@
             processNewlySatisfiedListenRequests(nai);
         }
 
-        for (final NetworkAgentInfo nai : lingeredNetworks) {
+        for (final NetworkAgentInfo nai : inactiveNetworks) {
+            // For nascent networks, if connecting with no foreground request, skip broadcasting
+            // LOSING for backward compatibility. This is typical when mobile data connected while
+            // wifi connected with mobile data always-on enabled.
+            if (nai.isNascent()) continue;
             notifyNetworkLosing(nai, now);
         }
 
@@ -7584,7 +7492,7 @@
         // Tear down all unneeded networks.
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
             if (unneeded(nai, UnneededFor.TEARDOWN)) {
-                if (nai.getLingerExpiry() > 0) {
+                if (nai.getInactivityExpiry() > 0) {
                     // This network has active linger timers and no requests, but is not
                     // lingering. Linger it.
                     //
@@ -7592,7 +7500,7 @@
                     // and became unneeded due to another network improving its score to the
                     // point where this network will no longer be able to satisfy any requests
                     // even if it validates.
-                    if (updateLingerState(nai, now)) {
+                    if (updateInactivityState(nai, now)) {
                         notifyNetworkLosing(nai, now);
                     }
                 } else {
@@ -7624,34 +7532,28 @@
     private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
             @NonNull final NetworkReassignment changes,
             @NonNull final Collection<NetworkAgentInfo> nais) {
-        final NetworkReassignment.RequestReassignment fallbackReassignment =
-                changes.getReassignment(mFallbackRequest);
-        final NetworkAgentInfo oldFallbackNetwork =
-                null != fallbackReassignment ? fallbackReassignment.mOldNetwork : null;
-        final NetworkAgentInfo newFallbackNetwork =
-                null != fallbackReassignment ? fallbackReassignment.mNewNetwork : null;
+        final NetworkReassignment.RequestReassignment reassignmentOfDefault =
+                changes.getReassignment(mDefaultRequest);
+        final NetworkAgentInfo oldDefaultNetwork =
+                null != reassignmentOfDefault ? reassignmentOfDefault.mOldNetwork : null;
+        final NetworkAgentInfo newDefaultNetwork =
+                null != reassignmentOfDefault ? reassignmentOfDefault.mNewNetwork : null;
 
-        if (oldFallbackNetwork != newFallbackNetwork) {
+        if (oldDefaultNetwork != newDefaultNetwork) {
             // Maintain the illusion : since the legacy API only understands one network at a time,
             // if the default network changed, apps should see a disconnected broadcast for the
             // old default network before they see a connected broadcast for the new one.
-            if (oldFallbackNetwork != null) {
-                mLegacyTypeTracker.remove(oldFallbackNetwork.networkInfo.getType(),
-                        oldFallbackNetwork, true);
+            if (oldDefaultNetwork != null) {
+                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
+                        oldDefaultNetwork, true);
             }
-            if (newFallbackNetwork != null) {
+            if (newDefaultNetwork != null) {
                 // The new default network can be newly null if and only if the old default
                 // network doesn't satisfy the default request any more because it lost a
                 // capability.
-                mDefaultInetConditionPublished = newFallbackNetwork.lastValidated ? 100 : 0;
+                mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
                 mLegacyTypeTracker.add(
-                        newFallbackNetwork.networkInfo.getType(), newFallbackNetwork);
-                // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
-                // to reflect the NetworkInfo of this new network. This broadcast has to be sent
-                // after the disconnect broadcasts above, but before the broadcasts sent by the
-                // legacy type tracker below.
-                // TODO : refactor this, it's too complex
-                notifyLockdownVpn(newFallbackNetwork);
+                        newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
             }
         }
 
@@ -7686,7 +7588,7 @@
         }
 
         // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
-        // because usually there are no NetworkRequests it satisfies (e.g., mFallbackRequest
+        // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
         // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
         // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
         if (nai.isVPN()) {
@@ -7697,9 +7599,9 @@
     private void updateInetCondition(NetworkAgentInfo nai) {
         // Don't bother updating until we've graduated to validated at least once.
         if (!nai.everValidated) return;
-        // For now only update icons for the fallback connection.
+        // For now only update icons for the default connection.
         // TODO: Update WiFi and cellular icons separately. b/17237507
-        if (!isFallbackNetwork(nai)) return;
+        if (!isDefaultNetwork(nai)) return;
 
         int newInetCondition = nai.lastValidated ? 100 : 0;
         // Don't repeat publish.
@@ -7709,18 +7611,6 @@
         sendInetConditionBroadcast(nai.networkInfo);
     }
 
-    private void notifyLockdownVpn(NetworkAgentInfo nai) {
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) {
-                if (nai != null && nai.isVPN()) {
-                    mLockdownTracker.onVpnStateChanged(nai.networkInfo);
-                } else {
-                    mLockdownTracker.onNetworkInfoChanged();
-                }
-            }
-        }
-    }
-
     @NonNull
     private NetworkInfo mixInInfo(@NonNull final NetworkAgentInfo nai, @NonNull NetworkInfo info) {
         final NetworkInfo newInfo = new NetworkInfo(info);
@@ -7759,7 +7649,6 @@
             oldInfo = networkAgent.networkInfo;
             networkAgent.networkInfo = newInfo;
         }
-        notifyLockdownVpn(networkAgent);
 
         if (DBG) {
             log(networkAgent.toShortString() + " EVENT_NETWORK_INFO_CHANGED, going from "
@@ -7816,6 +7705,15 @@
             // doing.
             updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
 
+            // Before first rematching networks, put an inactivity timer without any request, this
+            // allows {@code updateInactivityState} to update the state accordingly and prevent
+            // tearing down for any {@code unneeded} evaluation in this period.
+            // Note that the timer will not be rescheduled since the expiry time is
+            // fixed after connection regardless of the network satisfying other requests or not.
+            // But it will be removed as soon as the network satisfies a request for the first time.
+            networkAgent.lingerRequest(NetworkRequest.REQUEST_ID_NONE,
+                    SystemClock.elapsedRealtime(), mNascentDelayMs);
+
             // Consider network even though it is not yet validated.
             rematchAllNetworksAndRequests();
 
@@ -7869,7 +7767,7 @@
 
     // Notify the requests on this NAI that the network is now lingered.
     private void notifyNetworkLosing(@NonNull final NetworkAgentInfo nai, final long now) {
-        final int lingerTime = (int) (nai.getLingerExpiry() - now);
+        final int lingerTime = (int) (nai.getInactivityExpiry() - now);
         notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
     }
 
@@ -7967,8 +7865,8 @@
                 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
             }
             NetworkAgentInfo newDefaultAgent = null;
-            if (nai.isSatisfyingRequest(mFallbackRequest.mRequests.get(0).requestId)) {
-                newDefaultAgent = getFallbackNetwork();
+            if (nai.isSatisfyingRequest(mDefaultRequest.mRequests.get(0).requestId)) {
+                newDefaultAgent = mDefaultRequest.getSatisfier();
                 if (newDefaultAgent != null) {
                     intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
                             newDefaultAgent.networkInfo);
@@ -8016,9 +7914,14 @@
     private Network[] getDefaultNetworks() {
         ensureRunningOnConnectivityServiceThread();
         final ArrayList<Network> defaultNetworks = new ArrayList<>();
-        final NetworkAgentInfo fallbackNetwork = getFallbackNetwork();
+        final Set<Integer> activeNetIds = new ArraySet<>();
+        for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
+            if (nri.isBeingSatisfied()) {
+                activeNetIds.add(nri.getSatisfier().network().netId);
+            }
+        }
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
-            if (nai.everConnected && (nai == fallbackNetwork || nai.isVPN())) {
+            if (nai.everConnected && (activeNetIds.contains(nai.network().netId) || nai.isVPN())) {
                 defaultNetworks.add(nai.network);
             }
         }
@@ -8046,34 +7949,6 @@
     }
 
     @Override
-    public boolean addVpnAddress(String address, int prefixLength) {
-        int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            return mVpns.get(user).addAddress(address, prefixLength);
-        }
-    }
-
-    @Override
-    public boolean removeVpnAddress(String address, int prefixLength) {
-        int user = UserHandle.getUserId(mDeps.getCallingUid());
-        synchronized (mVpns) {
-            throwIfLockdownEnabled();
-            return mVpns.get(user).removeAddress(address, prefixLength);
-        }
-    }
-
-    @Override
-    public boolean setUnderlyingNetworksForVpn(Network[] networks) {
-        int user = UserHandle.getUserId(mDeps.getCallingUid());
-        final boolean success;
-        synchronized (mVpns) {
-            success = mVpns.get(user).setUnderlyingNetworks(networks);
-        }
-        return success;
-    }
-
-    @Override
     public String getCaptivePortalServerUrl() {
         enforceNetworkStackOrSettingsPermission();
         String settingUrl = mContext.getResources().getString(
@@ -8152,8 +8027,6 @@
             return;
         }
 
-        final int userId = UserHandle.getCallingUserId();
-
         final long token = Binder.clearCallingIdentity();
         try {
             final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
@@ -8165,44 +8038,6 @@
         // Turn airplane mode off
         setAirplaneMode(false);
 
-        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
-            // Remove always-on package
-            synchronized (mVpns) {
-                final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
-                if (alwaysOnPackage != null) {
-                    setAlwaysOnVpnPackage(userId, null, false, null);
-                    setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
-                }
-
-                // Turn Always-on VPN off
-                if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
-                    final long ident = Binder.clearCallingIdentity();
-                    try {
-                        mKeyStore.delete(Credentials.LOCKDOWN_VPN);
-                        mLockdownEnabled = false;
-                        setLockdownTracker(null);
-                    } finally {
-                        Binder.restoreCallingIdentity(ident);
-                    }
-                }
-
-                // Turn VPN off
-                VpnConfig vpnConfig = getVpnConfig(userId);
-                if (vpnConfig != null) {
-                    if (vpnConfig.legacy) {
-                        prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
-                    } else {
-                        // Prevent this app (packagename = vpnConfig.user) from initiating
-                        // VPN connections in the future without user intervention.
-                        setVpnPackageAuthorization(
-                                vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
-
-                        prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
-                    }
-                }
-            }
-        }
-
         // restore private DNS settings to default mode (opportunistic)
         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
             Settings.Global.putString(mContext.getContentResolver(),
@@ -8294,41 +8129,11 @@
         }
     }
 
-    @GuardedBy("mVpns")
-    private Vpn getVpnIfOwner() {
-        return getVpnIfOwner(mDeps.getCallingUid());
-    }
-
-    // TODO: stop calling into Vpn.java and get this information from data in this class.
-    @GuardedBy("mVpns")
-    private Vpn getVpnIfOwner(int uid) {
-        final int user = UserHandle.getUserId(uid);
-
-        final Vpn vpn = mVpns.get(user);
-        if (vpn == null) {
-            return null;
-        } else {
-            final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
-            return (info == null || info.ownerUid != uid) ? null : vpn;
-        }
-    }
-
-    /**
-     * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
-     * for testing.
-     */
-    private Vpn enforceActiveVpnOrNetworkStackPermission() {
-        if (checkNetworkStackPermission()) {
-            return null;
-        }
-        synchronized (mVpns) {
-            Vpn vpn = getVpnIfOwner();
-            if (vpn != null) {
-                return vpn;
-            }
-        }
-        throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
-                + "permission");
+    private @VpnManager.VpnType int getVpnType(@Nullable NetworkAgentInfo vpn) {
+        if (vpn == null) return VpnManager.TYPE_VPN_NONE;
+        final TransportInfo ti = vpn.networkCapabilities.getTransportInfo();
+        if (!(ti instanceof VpnTransportInfo)) return VpnManager.TYPE_VPN_NONE;
+        return ((VpnTransportInfo) ti).type;
     }
 
     /**
@@ -8338,45 +8143,28 @@
      * connection is not found.
      */
     public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
-        final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
-
-        // Only VpnService based VPNs should be able to get this information.
-        if (vpn != null && vpn.getActiveAppVpnType() != VpnManager.TYPE_VPN_SERVICE) {
-            throw new SecurityException(
-                    "getConnectionOwnerUid() not allowed for non-VpnService VPNs");
-        }
-
         if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
             throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
         }
 
-        final int uid = InetDiagMessage.getConnectionOwnerUid(connectionInfo.protocol,
+        final int uid = mDeps.getConnectionOwnerUid(connectionInfo.protocol,
                 connectionInfo.local, connectionInfo.remote);
 
-        /* Filter out Uids not associated with the VPN. */
-        if (vpn != null && !vpn.appliesToUid(uid)) {
+        if (uid == INVALID_UID) return uid;  // Not found.
+
+        // Connection owner UIDs are visible only to the network stack and to the VpnService-based
+        // VPN, if any, that applies to the UID that owns the connection.
+        if (checkNetworkStackPermission()) return uid;
+
+        final NetworkAgentInfo vpn = getVpnForUid(uid);
+        if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
+                || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) {
             return INVALID_UID;
         }
 
         return uid;
     }
 
-    @Override
-    public boolean isCallerCurrentAlwaysOnVpnApp() {
-        synchronized (mVpns) {
-            Vpn vpn = getVpnIfOwner();
-            return vpn != null && vpn.getAlwaysOn();
-        }
-    }
-
-    @Override
-    public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
-        synchronized (mVpns) {
-            Vpn vpn = getVpnIfOwner();
-            return vpn != null && vpn.getLockdown();
-        }
-    }
-
     /**
      * Returns a IBinder to a TestNetworkService. Will be lazily created as needed.
      *
@@ -8765,14 +8553,14 @@
         for (NetworkAgentInfo virtual : mNetworkAgentInfos) {
             if (virtual.supportsUnderlyingNetworks()
                     && virtual.networkCapabilities.getOwnerUid() == callbackUid
-                    && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+                    && CollectionUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
                 return true;
             }
         }
 
         // Administrator UIDs also contains the Owner UID
         final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
-        return ArrayUtils.contains(administratorUids, callbackUid);
+        return CollectionUtils.contains(administratorUids, callbackUid);
     }
 
     @Override
@@ -8868,13 +8656,35 @@
      * changes.
      */
     private static final class LegacyNetworkActivityTracker {
+        private static final int NO_UID = -1;
         private final Context mContext;
+        private final INetd mNetd;
         private final INetworkManagementService mNMS;
+        private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
+                new RemoteCallbackList<>();
+        // Indicate the current system default network activity is active or not.
+        @GuardedBy("mActiveIdleTimers")
+        private boolean mNetworkActive;
+        @GuardedBy("mActiveIdleTimers")
+        private final ArrayMap<String, IdleTimerParams> mActiveIdleTimers = new ArrayMap();
+        private final Handler mHandler;
 
-        LegacyNetworkActivityTracker(@NonNull Context context,
-                @NonNull INetworkManagementService nms) {
+        private class IdleTimerParams {
+            public final int timeout;
+            public final int transportType;
+
+            IdleTimerParams(int timeout, int transport) {
+                this.timeout = timeout;
+                this.transportType = transport;
+            }
+        }
+
+        LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
+                @NonNull INetworkManagementService nms, @NonNull INetd netd) {
             mContext = context;
             mNMS = nms;
+            mNetd = netd;
+            mHandler = handler;
             try {
                 mNMS.registerObserver(mDataActivityObserver);
             } catch (RemoteException e) {
@@ -8890,9 +8700,50 @@
                             long tsNanos, int uid) {
                         sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
                                 tsNanos);
+                        synchronized (mActiveIdleTimers) {
+                            mNetworkActive = active;
+                            // If there are no idle timers, it means that system is not monitoring
+                            // activity, so the system default network for those default network
+                            // unspecified apps is always considered active.
+                            //
+                            // TODO: If the mActiveIdleTimers is empty, netd will actually not send
+                            // any network activity change event. Whenever this event is received,
+                            // the mActiveIdleTimers should be always not empty. The legacy behavior
+                            // is no-op. Remove to refer to mNetworkActive only.
+                            if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
+                                mHandler.sendMessage(
+                                        mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
+                            }
+                        }
                     }
                 };
 
+        // The network activity should only be updated from ConnectivityService handler thread
+        // when mActiveIdleTimers lock is held.
+        @GuardedBy("mActiveIdleTimers")
+        private void reportNetworkActive() {
+            final int length = mNetworkActivityListeners.beginBroadcast();
+            if (DDBG) log("reportNetworkActive, notify " + length + " listeners");
+            try {
+                for (int i = 0; i < length; i++) {
+                    try {
+                        mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
+                    } catch (RemoteException | RuntimeException e) {
+                        loge("Fail to send network activie to listener " + e);
+                    }
+                }
+            } finally {
+                mNetworkActivityListeners.finishBroadcast();
+            }
+        }
+
+        @GuardedBy("mActiveIdleTimers")
+        public void handleReportNetworkActivity() {
+            synchronized (mActiveIdleTimers) {
+                reportNetworkActive();
+            }
+        }
+
         // This is deprecated and only to support legacy use cases.
         private int transportTypeToLegacyType(int type) {
             switch (type) {
@@ -8957,10 +8808,17 @@
                 return; // do not track any other networks
             }
 
+            updateRadioPowerState(true /* isActive */, type);
+
             if (timeout > 0 && iface != null) {
                 try {
-                    // TODO: Access INetd directly instead of NMS
-                    mNMS.addIdleTimer(iface, timeout, type);
+                    synchronized (mActiveIdleTimers) {
+                        // Networks start up.
+                        mNetworkActive = true;
+                        mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
+                        mNetd.idletimerAddInterface(iface, timeout, Integer.toString(type));
+                        reportNetworkActive();
+                    }
                 } catch (Exception e) {
                     // You shall not crash!
                     loge("Exception in setupDataActivityTracking " + e);
@@ -8975,16 +8833,28 @@
             final String iface = networkAgent.linkProperties.getInterfaceName();
             final NetworkCapabilities caps = networkAgent.networkCapabilities;
 
-            if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                    || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
-                try {
-                    // the call fails silently if no idle timer setup for this interface
-                    // TODO: Access INetd directly instead of NMS
-                    mNMS.removeIdleTimer(iface);
-                } catch (Exception e) {
-                    // You shall not crash!
-                    loge("Exception in removeDataActivityTracking " + e);
+            if (iface == null) return;
+
+            final int type;
+            if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                type = NetworkCapabilities.TRANSPORT_CELLULAR;
+            } else if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                type = NetworkCapabilities.TRANSPORT_WIFI;
+            } else {
+                return; // do not track any other networks
+            }
+
+            try {
+                updateRadioPowerState(false /* isActive */, type);
+                synchronized (mActiveIdleTimers) {
+                    final IdleTimerParams params = mActiveIdleTimers.remove(iface);
+                    // The call fails silently if no idle timer setup for this interface
+                    mNetd.idletimerRemoveInterface(iface, params.timeout,
+                            Integer.toString(params.transportType));
                 }
+            } catch (Exception e) {
+                // You shall not crash!
+                loge("Exception in removeDataActivityTracking " + e);
             }
         }
 
@@ -9000,7 +8870,55 @@
                 removeDataActivityTracking(oldNetwork);
             }
         }
+
+        private void updateRadioPowerState(boolean isActive, int transportType) {
+            final BatteryStatsManager bs = mContext.getSystemService(BatteryStatsManager.class);
+            switch (transportType) {
+                case NetworkCapabilities.TRANSPORT_CELLULAR:
+                    bs.reportMobileRadioPowerState(isActive, NO_UID);
+                    break;
+                case NetworkCapabilities.TRANSPORT_WIFI:
+                    bs.reportWifiRadioPowerState(isActive, NO_UID);
+                    break;
+                default:
+                    logw("Untracked transport type:" + transportType);
+            }
+        }
+
+        public boolean isDefaultNetworkActive() {
+            synchronized (mActiveIdleTimers) {
+                // If there are no idle timers, it means that system is not monitoring activity,
+                // so the default network is always considered active.
+                //
+                // TODO : Distinguish between the cases where mActiveIdleTimers is empty because
+                // tracking is disabled (negative idle timer value configured), or no active default
+                // network. In the latter case, this reports active but it should report inactive.
+                return mNetworkActive || mActiveIdleTimers.isEmpty();
+            }
+        }
+
+        public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
+            mNetworkActivityListeners.register(l);
+        }
+
+        public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
+            mNetworkActivityListeners.unregister(l);
+        }
+
+        public void dump(IndentingPrintWriter pw) {
+            synchronized (mActiveIdleTimers) {
+                pw.print("mNetworkActive="); pw.println(mNetworkActive);
+                pw.println("Idle timers:");
+                for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
+                    pw.print("  "); pw.print(ent.getKey()); pw.println(":");
+                    final IdleTimerParams params = ent.getValue();
+                    pw.print("    timeout="); pw.print(params.timeout);
+                    pw.print(" type="); pw.println(params.transportType);
+                }
+            }
+        }
     }
+
     /**
      * Registers {@link QosSocketFilter} with {@link IQosCallback}.
      *
@@ -9050,4 +8968,275 @@
     public void unregisterQosCallback(@NonNull final IQosCallback callback) {
         mQosCallbackTracker.unregisterCallback(callback);
     }
+
+    private void enforceAutomotiveDevice() {
+        final boolean isAutomotiveDevice =
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+        if (!isAutomotiveDevice) {
+            throw new UnsupportedOperationException(
+                    "setOemNetworkPreference() is only available on automotive devices.");
+        }
+    }
+
+    /**
+     * Used by automotive devices to set the network preferences used to direct traffic at an
+     * application level as per the given OemNetworkPreferences. An example use-case would be an
+     * automotive OEM wanting to provide connectivity for applications critical to the usage of a
+     * vehicle via a particular network.
+     *
+     * Calling this will overwrite the existing preference.
+     *
+     * @param preference {@link OemNetworkPreferences} The application network preference to be set.
+     * @param listener {@link ConnectivityManager.OnSetOemNetworkPreferenceListener} Listener used
+     * to communicate completion of setOemNetworkPreference();
+     */
+    @Override
+    public void setOemNetworkPreference(
+            @NonNull final OemNetworkPreferences preference,
+            @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+
+        enforceAutomotiveDevice();
+        enforceOemNetworkPreferencesPermission();
+
+        Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+        validateOemNetworkPreferences(preference);
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
+                new Pair<>(preference, listener)));
+    }
+
+    private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
+        for (@OemNetworkPreferences.OemNetworkPreference final int pref
+                : preference.getNetworkPreferences().values()) {
+            if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
+                final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
+                throw new IllegalArgumentException(msg);
+            }
+        }
+    }
+
+    private void handleSetOemNetworkPreference(
+            @NonNull final OemNetworkPreferences preference,
+            @NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException {
+        Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+        if (DBG) {
+            log("set OEM network preferences :" + preference.toString());
+        }
+        final ArraySet<NetworkRequestInfo> nris =
+                new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
+        updateDefaultNetworksForOemNetworkPreference(nris);
+        mOemNetworkPreferences = preference;
+        // TODO http://b/176496396 persist data to shared preferences.
+
+        if (null != listener) {
+            listener.onComplete();
+        }
+    }
+
+    private void updateDefaultNetworksForOemNetworkPreference(
+            @NonNull final Set<NetworkRequestInfo> nris) {
+        // Pass in a defensive copy as this collection will be updated on remove.
+        handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests));
+        addPerAppDefaultNetworkRequests(nris);
+    }
+
+    private void addPerAppDefaultNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
+        ensureRunningOnConnectivityServiceThread();
+        mDefaultNetworkRequests.addAll(nris);
+        final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate =
+                getPerAppCallbackRequestsToUpdate();
+        handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
+        final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris);
+        nrisToRegister.addAll(
+                createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate));
+        handleRegisterNetworkRequests(nrisToRegister);
+    }
+
+    /**
+     * All current requests that are tracking the default network need to be assessed as to whether
+     * or not the current set of per-application default requests will be changing their default
+     * network. If so, those requests will need to be updated so that they will send callbacks for
+     * default network changes at the appropriate time. Additionally, those requests tracking the
+     * default that were previously updated by this flow will need to be reassessed.
+     * @return the nris which will need to be updated.
+     */
+    private ArraySet<NetworkRequestInfo> getPerAppCallbackRequestsToUpdate() {
+        final ArraySet<NetworkRequestInfo> defaultCallbackRequests = new ArraySet<>();
+        // Get the distinct nris to check since for multilayer requests, it is possible to have the
+        // same nri in the map's values for each of its NetworkRequest objects.
+        final ArraySet<NetworkRequestInfo> nris = new ArraySet<>(mNetworkRequests.values());
+        for (final NetworkRequestInfo nri : nris) {
+            // Include this nri if it is currently being tracked.
+            if (isPerAppTrackedNri(nri)) {
+                defaultCallbackRequests.add(nri);
+                continue;
+            }
+            // We only track callbacks for requests tracking the default.
+            if (NetworkRequest.Type.TRACK_DEFAULT != nri.mRequests.get(0).type) {
+                continue;
+            }
+            // Include this nri if it will be tracked by the new per-app default requests.
+            final boolean isNriGoingToBeTracked =
+                    getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest;
+            if (isNriGoingToBeTracked) {
+                defaultCallbackRequests.add(nri);
+            }
+        }
+        return defaultCallbackRequests;
+    }
+
+    /**
+     * Create nris for those network requests that are currently tracking the default network that
+     * are being controlled by a per-application default.
+     * @param perAppCallbackRequestsForUpdate the baseline network requests to be used as the
+     * foundation when creating the nri. Important items include the calling uid's original
+     * NetworkRequest to be used when mapping callbacks as well as the caller's uid and name. These
+     * requests are assumed to have already been validated as needing to be updated.
+     * @return the Set of nris to use when registering network requests.
+     */
+    private ArraySet<NetworkRequestInfo> createPerAppCallbackRequestsToRegister(
+            @NonNull final ArraySet<NetworkRequestInfo> perAppCallbackRequestsForUpdate) {
+        final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>();
+        for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) {
+            final NetworkRequestInfo trackingNri =
+                    getDefaultRequestTrackingUid(callbackRequest.mUid);
+
+            // If this nri is not being tracked, the change it back to an untracked nri.
+            if (trackingNri == mDefaultRequest) {
+                callbackRequestsToRegister.add(new NetworkRequestInfo(
+                        callbackRequest,
+                        Collections.singletonList(callbackRequest.getNetworkRequestForCallback())));
+                continue;
+            }
+
+            final String requestorPackageName =
+                    callbackRequest.mRequests.get(0).getRequestorPackageName();
+            callbackRequestsToRegister.add(new NetworkRequestInfo(
+                    callbackRequest,
+                    copyNetworkRequestsForUid(
+                            trackingNri.mRequests, callbackRequest.mUid, requestorPackageName)));
+        }
+        return callbackRequestsToRegister;
+    }
+
+    /**
+     * Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}.
+     */
+    @VisibleForTesting
+    final class OemNetworkRequestFactory {
+        ArraySet<NetworkRequestInfo> createNrisFromOemNetworkPreferences(
+                @NonNull final OemNetworkPreferences preference) {
+            final ArraySet<NetworkRequestInfo> nris = new ArraySet<>();
+            final SparseArray<Set<Integer>> uids =
+                    createUidsFromOemNetworkPreferences(preference);
+            for (int i = 0; i < uids.size(); i++) {
+                final int key = uids.keyAt(i);
+                final Set<Integer> value = uids.valueAt(i);
+                final NetworkRequestInfo nri = createNriFromOemNetworkPreferences(key, value);
+                // No need to add an nri without any requests.
+                if (0 == nri.mRequests.size()) {
+                    continue;
+                }
+                nris.add(nri);
+            }
+
+            return nris;
+        }
+
+        private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
+                @NonNull final OemNetworkPreferences preference) {
+            final SparseArray<Set<Integer>> uids = new SparseArray<>();
+            final PackageManager pm = mContext.getPackageManager();
+            for (final Map.Entry<String, Integer> entry :
+                    preference.getNetworkPreferences().entrySet()) {
+                @OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
+                try {
+                    final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
+                    if (!uids.contains(pref)) {
+                        uids.put(pref, new ArraySet<>());
+                    }
+                    uids.get(pref).add(uid);
+                } catch (PackageManager.NameNotFoundException e) {
+                    // Although this may seem like an error scenario, it is ok that uninstalled
+                    // packages are sent on a network preference as the system will watch for
+                    // package installations associated with this network preference and update
+                    // accordingly. This is done so as to minimize race conditions on app install.
+                    // TODO b/177092163 add app install watching.
+                    continue;
+                }
+            }
+            return uids;
+        }
+
+        private NetworkRequestInfo createNriFromOemNetworkPreferences(
+                @OemNetworkPreferences.OemNetworkPreference final int preference,
+                @NonNull final Set<Integer> uids) {
+            final List<NetworkRequest> requests = new ArrayList<>();
+            // Requests will ultimately be evaluated by order of insertion therefore it matters.
+            switch (preference) {
+                case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID:
+                    requests.add(createUnmeteredNetworkRequest());
+                    requests.add(createOemPaidNetworkRequest());
+                    requests.add(createDefaultRequest());
+                    break;
+                case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
+                    requests.add(createUnmeteredNetworkRequest());
+                    requests.add(createOemPaidNetworkRequest());
+                    break;
+                case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
+                    requests.add(createOemPaidNetworkRequest());
+                    break;
+                case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
+                    requests.add(createOemPrivateNetworkRequest());
+                    break;
+                default:
+                    // This should never happen.
+                    throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
+                            + " called with invalid preference of " + preference);
+            }
+
+            setOemNetworkRequestUids(requests, uids);
+            return new NetworkRequestInfo(requests);
+        }
+
+        private NetworkRequest createUnmeteredNetworkRequest() {
+            final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+                    .addCapability(NET_CAPABILITY_NOT_METERED)
+                    .addCapability(NET_CAPABILITY_VALIDATED);
+            return createNetworkRequest(NetworkRequest.Type.LISTEN, netcap);
+        }
+
+        private NetworkRequest createOemPaidNetworkRequest() {
+            // NET_CAPABILITY_OEM_PAID is a restricted capability.
+            final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+                    .addCapability(NET_CAPABILITY_OEM_PAID)
+                    .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+            return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
+        }
+
+        private NetworkRequest createOemPrivateNetworkRequest() {
+            // NET_CAPABILITY_OEM_PRIVATE is a restricted capability.
+            final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+                    .addCapability(NET_CAPABILITY_OEM_PRIVATE)
+                    .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+            return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
+        }
+
+        private NetworkCapabilities createDefaultPerAppNetCap() {
+            final NetworkCapabilities netCap = new NetworkCapabilities();
+            netCap.addCapability(NET_CAPABILITY_INTERNET);
+            netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
+            return netCap;
+        }
+
+        private void setOemNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
+                @NonNull final Set<Integer> uids) {
+            final Set<UidRange> ranges = new ArraySet<>();
+            for (final int uid : uids) {
+                ranges.add(new UidRange(uid, uid));
+            }
+            for (final NetworkRequest req : requests) {
+                req.networkCapabilities.setUids(ranges);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 88ce220..e29e894 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -28,6 +28,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.image.IDynamicSystemService;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.util.Slog;
@@ -40,6 +41,7 @@
  */
 public class DynamicSystemService extends IDynamicSystemService.Stub {
     private static final String TAG = "DynamicSystemService";
+    private static final long MINIMUM_SD_MB = (30L << 10);
     private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
     private static final String PATH_DEFAULT = "/data/gsi/";
     private Context mContext;
@@ -95,6 +97,13 @@
                 if (!volume.isMountedWritable()) {
                     continue;
                 }
+                DiskInfo disk = volume.getDisk();
+                long mega = disk.size >> 20;
+                Slog.i(TAG, volume.getPath() + ": " + mega + " MB");
+                if (mega < MINIMUM_SD_MB) {
+                    Slog.i(TAG, volume.getPath() + ": insufficient storage");
+                    continue;
+                }
                 File sd_internal = volume.getInternalPathForUser(userId);
                 if (sd_internal != null) {
                     path = new File(sd_internal, dsuSlot).getPath();
diff --git a/services/core/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
index c56cef2..a83c981 100644
--- a/services/core/java/com/android/server/EntropyMixer.java
+++ b/services/core/java/com/android/server/EntropyMixer.java
@@ -16,12 +16,6 @@
 
 package com.android.server;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -33,10 +27,15 @@
 import android.os.SystemProperties;
 import android.util.Slog;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
 /**
  * A service designed to load and periodically save &quot;randomness&quot;
- * for the Linux kernel RNG and to mix in data from Hardware RNG (if present)
- * into the Linux RNG.
+ * for the Linux kernel RNG.
  *
  * <p>When a Linux system starts up, the entropy pool associated with
  * {@code /dev/random} may be in a fairly predictable state.  Applications which
@@ -45,15 +44,8 @@
  * this effect, it's helpful to carry the entropy pool information across
  * shutdowns and startups.
  *
- * <p>On systems with Hardware RNG (/dev/hw_random), a block of output from HW
- * RNG is mixed into the Linux RNG on EntropyMixer's startup and whenever
- * EntropyMixer periodically runs to save a block of output from Linux RNG on
- * disk. This mixing is done in a way that does not increase the Linux RNG's
- * entropy estimate is not increased. This is to avoid having to trust/verify
- * the quality and authenticity of the &quot;randomness&quot; of the HW RNG.
- *
  * <p>This class was modeled after the script in the
- * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">
+ * <a href="https://man7.org/linux/man-pages/man4/random.4.html">
  * random(4) manual page</a>.
  */
 public class EntropyMixer extends Binder {
@@ -64,7 +56,6 @@
     private static final long START_NANOTIME = System.nanoTime();
 
     private final String randomDevice;
-    private final String hwRandomDevice;
     private final String entropyFile;
 
     /**
@@ -80,7 +71,6 @@
                 Slog.e(TAG, "Will not process invalid message");
                 return;
             }
-            addHwRandomEntropy();
             writeEntropy();
             scheduleEntropyWriter();
         }
@@ -94,25 +84,21 @@
     };
 
     public EntropyMixer(Context context) {
-        this(context, getSystemDir() + "/entropy.dat", "/dev/urandom", "/dev/hw_random");
+        this(context, getSystemDir() + "/entropy.dat", "/dev/urandom");
     }
 
     /** Test only interface, not for public use */
     public EntropyMixer(
             Context context,
             String entropyFile,
-            String randomDevice,
-            String hwRandomDevice) {
+            String randomDevice) {
         if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
-        if (hwRandomDevice == null) { throw new NullPointerException("hwRandomDevice"); }
         if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
 
         this.randomDevice = randomDevice;
-        this.hwRandomDevice = hwRandomDevice;
         this.entropyFile = entropyFile;
         loadInitialEntropy();
         addDeviceSpecificEntropy();
-        addHwRandomEntropy();
         writeEntropy();
         scheduleEntropyWriter();
         IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
@@ -192,23 +178,6 @@
         }
     }
 
-    /**
-     * Mixes in the output from HW RNG (if present) into the Linux RNG.
-     */
-    private void addHwRandomEntropy() {
-        if (!new File(hwRandomDevice).exists()) {
-            // HW RNG not present/exposed -- ignore
-            return;
-        }
-
-        try {
-            RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false);
-            Slog.i(TAG, "Added HW RNG output to entropy pool");
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e);
-        }
-    }
-
     private static String getSystemDir() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index f648c3e..81d4b9d 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -29,6 +29,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
 import android.net.IIpSecService;
 import android.net.INetd;
 import android.net.InetAddresses;
@@ -41,12 +42,12 @@
 import android.net.IpSecTunnelInterfaceResponse;
 import android.net.IpSecUdpEncapResponse;
 import android.net.LinkAddress;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.TrafficStats;
 import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -62,6 +63,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.NetdUtils;
 
 import libcore.io.IoUtils;
 
@@ -115,9 +117,6 @@
     /* Binder context for this service */
     private final Context mContext;
 
-    /* NetworkManager instance */
-    private final INetworkManagementService mNetworkManager;
-
     /**
      * The next non-repeating global ID for tracking resources between users, this service, and
      * kernel data structures. Accessing this variable is not thread safe, so it is only read or
@@ -797,9 +796,15 @@
         }
     }
 
-    private final class TunnelInterfaceRecord extends OwnedResourceRecord {
+    /**
+     * Tracks an tunnel interface, and manages cleanup paths.
+     *
+     * <p>This class is not thread-safe, and expects that that users of this class will ensure
+     * synchronization and thread safety by holding the IpSecService.this instance lock
+     */
+    @VisibleForTesting
+    final class TunnelInterfaceRecord extends OwnedResourceRecord {
         private final String mInterfaceName;
-        private final Network mUnderlyingNetwork;
 
         // outer addresses
         private final String mLocalAddress;
@@ -810,6 +815,8 @@
 
         private final int mIfId;
 
+        private Network mUnderlyingNetwork;
+
         TunnelInterfaceRecord(
                 int resourceId,
                 String interfaceName,
@@ -870,14 +877,22 @@
             releaseNetId(mOkey);
         }
 
-        public String getInterfaceName() {
-            return mInterfaceName;
+        @GuardedBy("IpSecService.this")
+        public void setUnderlyingNetwork(Network underlyingNetwork) {
+            // When #applyTunnelModeTransform is called, this new underlying network will be used to
+            // update the output mark of the input transform.
+            mUnderlyingNetwork = underlyingNetwork;
         }
 
+        @GuardedBy("IpSecService.this")
         public Network getUnderlyingNetwork() {
             return mUnderlyingNetwork;
         }
 
+        public String getInterfaceName() {
+            return mInterfaceName;
+        }
+
         /** Returns the local, outer address for the tunnelInterface */
         public String getLocalAddress() {
             return mLocalAddress;
@@ -996,13 +1011,13 @@
      *
      * @param context Binder context for this service
      */
-    private IpSecService(Context context, INetworkManagementService networkManager) {
-        this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE);
+    private IpSecService(Context context) {
+        this(context, IpSecServiceConfiguration.GETSRVINSTANCE);
     }
 
-    static IpSecService create(Context context, INetworkManagementService networkManager)
+    static IpSecService create(Context context)
             throws InterruptedException {
-        final IpSecService service = new IpSecService(context, networkManager);
+        final IpSecService service = new IpSecService(context);
         service.connectNativeNetdService();
         return service;
     }
@@ -1016,11 +1031,9 @@
 
     /** @hide */
     @VisibleForTesting
-    public IpSecService(Context context, INetworkManagementService networkManager,
-            IpSecServiceConfiguration config) {
+    public IpSecService(Context context, IpSecServiceConfiguration config) {
         this(
                 context,
-                networkManager,
                 config,
                 (fd, uid) -> {
                     try {
@@ -1034,10 +1047,9 @@
 
     /** @hide */
     @VisibleForTesting
-    public IpSecService(Context context, INetworkManagementService networkManager,
-            IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
+    public IpSecService(Context context, IpSecServiceConfiguration config,
+            UidFdTagger uidFdTagger) {
         mContext = context;
-        mNetworkManager = Objects.requireNonNull(networkManager);
         mSrvConfig = config;
         mUidFdTagger = uidFdTagger;
     }
@@ -1317,7 +1329,7 @@
             netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
 
             Binder.withCleanCallingIdentity(() -> {
-                mNetworkManager.setInterfaceUp(intfName);
+                NetdUtils.setInterfaceUp(netd, intfName);
             });
 
             for (int selAddrFamily : ADDRESS_FAMILIES) {
@@ -1429,6 +1441,34 @@
         }
     }
 
+    /** Set TunnelInterface to use a specific underlying network. */
+    @Override
+    public synchronized void setNetworkForTunnelInterface(
+            int tunnelResourceId, Network underlyingNetwork, String callingPackage) {
+        enforceTunnelFeatureAndPermissions(callingPackage);
+        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
+
+        final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+        // Get tunnelInterface record; if no such interface is found, will throw
+        // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null
+        final TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
+
+        final ConnectivityManager connectivityManager =
+                mContext.getSystemService(ConnectivityManager.class);
+        final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork);
+        if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) {
+            throw new IllegalArgumentException(
+                    "Underlying network cannot be the network being exposed by this tunnel");
+        }
+
+        // It is meaningless to check if the network exists or is valid because the network might
+        // disconnect at any time after it passes the check.
+
+        tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork);
+    }
+
     /**
      * Delete a TunnelInterface that has been been allocated by and registered with the system
      * server
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d30a640..4405408 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -69,7 +69,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -80,7 +79,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
@@ -229,32 +227,9 @@
     @GuardedBy("mQuotaLock")
     private volatile boolean mDataSaverMode;
 
-    private final Object mIdleTimerLock = new Object();
-    /** Set of interfaces with active idle timers. */
-    private static class IdleTimerParams {
-        public final int timeout;
-        public final int type;
-        public int networkCount;
-
-        IdleTimerParams(int timeout, int type) {
-            this.timeout = timeout;
-            this.type = type;
-            this.networkCount = 1;
-        }
-    }
-    private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
-
     private volatile boolean mFirewallEnabled;
     private volatile boolean mStrictEnabled;
 
-    private boolean mMobileActivityFromRadio = false;
-    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-    private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-
-    private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
-            new RemoteCallbackList<>();
-    private boolean mNetworkActive;
-
     /**
      * Constructs a new NetworkManagementService instance
      *
@@ -397,55 +372,8 @@
      */
     private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
             int uid) {
-        final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
-        int powerState = isActive
-                ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
-                : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-        if (isMobile) {
-            if (mLastPowerStateFromRadio != powerState) {
-                mLastPowerStateFromRadio = powerState;
-                try {
-                    // TODO: The interface changes that comes from netd are handled by BSS itself.
-                    // There are still events caused by setting or removing idle timer, so keep
-                    // reporting from here until setting idler timer moved to CS.
-                    getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        if (ConnectivityManager.isNetworkTypeWifi(type)) {
-            if (mLastPowerStateFromWifi != powerState) {
-                mLastPowerStateFromWifi = powerState;
-                try {
-                    // TODO: The interface changes that comes from netd are handled by BSS itself.
-                    // There are still events caused by setting or removing idle timer, so keep
-                    // reporting from here until setting idler timer moved to CS.
-                    getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        final boolean active = isActive;
         invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
-                type, active, tsNanos, uid));
-
-        boolean report = false;
-        synchronized (mIdleTimerLock) {
-            if (mActiveIdleTimers.isEmpty()) {
-                // If there are no idle timers, we are not monitoring activity, so we
-                // are always considered active.
-                isActive = true;
-            }
-            if (mNetworkActive != isActive) {
-                mNetworkActive = isActive;
-                report = isActive;
-            }
-        }
-        if (report) {
-            reportNetworkActive();
-        }
+                type, isActive, tsNanos, uid));
     }
 
     @Override
@@ -1122,60 +1050,6 @@
     }
 
     @Override
-    public void addIdleTimer(String iface, int timeout, final int type) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        if (DBG) Slog.d(TAG, "Adding idletimer");
-
-        synchronized (mIdleTimerLock) {
-            IdleTimerParams params = mActiveIdleTimers.get(iface);
-            if (params != null) {
-                // the interface already has idletimer, update network count
-                params.networkCount++;
-                return;
-            }
-
-            try {
-                mNetdService.idletimerAddInterface(iface, timeout, Integer.toString(type));
-            } catch (RemoteException | ServiceSpecificException e) {
-                throw new IllegalStateException(e);
-            }
-            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
-
-            // Networks start up.
-            if (ConnectivityManager.isNetworkTypeMobile(type)) {
-                mNetworkActive = false;
-            }
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true,
-                    SystemClock.elapsedRealtimeNanos(), -1));
-        }
-    }
-
-    @Override
-    public void removeIdleTimer(String iface) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        if (DBG) Slog.d(TAG, "Removing idletimer");
-
-        synchronized (mIdleTimerLock) {
-            final IdleTimerParams params = mActiveIdleTimers.get(iface);
-            if (params == null || --(params.networkCount) > 0) {
-                return;
-            }
-
-            try {
-                mNetdService.idletimerRemoveInterface(iface,
-                        params.timeout, Integer.toString(params.type));
-            } catch (RemoteException | ServiceSpecificException e) {
-                throw new IllegalStateException(e);
-            }
-            mActiveIdleTimers.remove(iface);
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type, false,
-                    SystemClock.elapsedRealtimeNanos(), -1));
-        }
-    }
-
-    @Override
     public void setInterfaceQuota(String iface, long quotaBytes) {
         NetworkStack.checkNetworkStackPermission(mContext);
 
@@ -1813,44 +1687,9 @@
     }
 
     @Override
-    public void registerNetworkActivityListener(INetworkActivityListener listener) {
-        mNetworkActivityListeners.register(listener);
-    }
-
-    @Override
-    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
-        mNetworkActivityListeners.unregister(listener);
-    }
-
-    @Override
-    public boolean isNetworkActive() {
-        synchronized (mNetworkActivityListeners) {
-            return mNetworkActive || mActiveIdleTimers.isEmpty();
-        }
-    }
-
-    private void reportNetworkActive() {
-        final int length = mNetworkActivityListeners.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mNetworkActivityListeners.finishBroadcast();
-        }
-    }
-
-    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
-                pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
-        pw.print("mNetworkActive="); pw.println(mNetworkActive);
-
         synchronized (mQuotaLock) {
             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
@@ -1882,17 +1721,6 @@
                     mUidFirewallRestrictedRules);
         }
 
-        synchronized (mIdleTimerLock) {
-            pw.println("Idle timers:");
-            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
-                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
-                IdleTimerParams params = ent.getValue();
-                pw.print("    timeout="); pw.print(params.timeout);
-                pw.print(" type="); pw.print(params.type);
-                pw.print(" networkCount="); pw.println(params.networkCount);
-            }
-        }
-
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
         pw.print("Netd service status: " );
         if (mNetdService == null) {
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e96fd39..96f832d 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -50,6 +50,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.NetworkStackConstants;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -280,10 +281,12 @@
 
         // Add global routes (but as non-default, non-internet providing network)
         if (allowIPv4) {
-            lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null, iface));
+            lp.addRoute(new RouteInfo(new IpPrefix(
+                    NetworkStackConstants.IPV4_ADDR_ANY, 0), null, iface));
         }
         if (allowIPv6) {
-            lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
+            lp.addRoute(new RouteInfo(new IpPrefix(
+                    NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface));
         }
 
         final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp,
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 6a72010..329ab99 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -22,6 +22,7 @@
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -29,8 +30,10 @@
 import android.net.NetworkCapabilities;
 import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.IVcnManagementService;
+import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
 import android.net.wifi.WifiInfo;
 import android.os.Binder;
@@ -54,6 +57,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.LocationPermissionChecker;
 import com.android.server.vcn.TelephonySubscriptionTracker;
 import com.android.server.vcn.Vcn;
 import com.android.server.vcn.VcnContext;
@@ -66,6 +70,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -123,6 +128,7 @@
  *
  * @hide
  */
+// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
 public class VcnManagementService extends IVcnManagementService.Stub {
     @NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
 
@@ -146,6 +152,9 @@
     @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
     @NonNull private final VcnContext mVcnContext;
 
+    /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
+    @Nullable private LocationPermissionChecker mLocationPermissionChecker;
+
     @GuardedBy("mLock")
     @NonNull
     private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
@@ -168,6 +177,10 @@
     private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
             new ArrayMap<>();
 
+    @GuardedBy("mLock")
+    @NonNull
+    private final Map<IBinder, VcnStatusCallbackInfo> mRegisteredStatusCallbacks = new ArrayMap<>();
+
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
         mContext = requireNonNull(context, "Missing context");
@@ -290,8 +303,10 @@
         public Vcn newVcn(
                 @NonNull VcnContext vcnContext,
                 @NonNull ParcelUuid subscriptionGroup,
-                @NonNull VcnConfig config) {
-            return new Vcn(vcnContext, subscriptionGroup, config);
+                @NonNull VcnConfig config,
+                @NonNull TelephonySubscriptionSnapshot snapshot,
+                @NonNull VcnCallback vcnCallback) {
+            return new Vcn(vcnContext, subscriptionGroup, config, snapshot, vcnCallback);
         }
 
         /** Gets the subId indicated by the given {@link WifiInfo}. */
@@ -299,6 +314,11 @@
             // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
+
+        /** Creates a new LocationPermissionChecker for the provided Context. */
+        public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) {
+            return new LocationPermissionChecker(context);
+        }
     }
 
     /** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -306,6 +326,7 @@
         mContext.getSystemService(ConnectivityManager.class)
                 .registerNetworkProvider(mNetworkProvider);
         mTelephonySubscriptionTracker.register();
+        mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
     }
 
     private void enforcePrimaryUser() {
@@ -382,6 +403,7 @@
                 // delay)
                 for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
                     final VcnConfig config = mConfigs.get(entry.getKey());
+
                     if (config == null
                             || !snapshot.packageHasPermissionsForSubscriptionGroup(
                                     entry.getKey(), config.getProvisioningPackageName())) {
@@ -395,10 +417,13 @@
                                 // correct instance is torn down. This could happen as a result of a
                                 // Carrier App manually removing/adding a VcnConfig.
                                 if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
-                                    mVcns.remove(uuidToTeardown).teardownAsynchronously();
+                                    stopVcnLocked(uuidToTeardown);
                                 }
                             }
                         }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+                    } else {
+                        // If this VCN's status has not changed, update it with the new snapshot
+                        entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
                     }
                 }
             }
@@ -406,14 +431,42 @@
     }
 
     @GuardedBy("mLock")
+    private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) {
+        final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown);
+        if (vcnToTeardown == null) {
+            return;
+        }
+
+        vcnToTeardown.teardownAsynchronously();
+
+        // Now that the VCN is removed, notify all registered listeners to refresh their
+        // UnderlyingNetworkPolicy.
+        notifyAllPolicyListenersLocked();
+    }
+
+    @GuardedBy("mLock")
+    private void notifyAllPolicyListenersLocked() {
+        for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) {
+            Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged());
+        }
+    }
+
+    @GuardedBy("mLock")
     private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
         Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
 
         // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
         //                    VCN.
 
-        final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config);
+        final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup);
+
+        final Vcn newInstance =
+                mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot, vcnCallback);
         mVcns.put(subscriptionGroup, newInstance);
+
+        // Now that a new VCN has started, notify all registered listeners to refresh their
+        // UnderlyingNetworkPolicy.
+        notifyAllPolicyListenersLocked();
     }
 
     @GuardedBy("mLock")
@@ -476,9 +529,7 @@
             synchronized (mLock) {
                 mConfigs.remove(subscriptionGroup);
 
-                if (mVcns.containsKey(subscriptionGroup)) {
-                    mVcns.remove(subscriptionGroup).teardownAsynchronously();
-                }
+                stopVcnLocked(subscriptionGroup);
 
                 writeConfigsToDiskLocked();
             }
@@ -508,7 +559,7 @@
         }
     }
 
-    /** Get current configuration list for testing purposes */
+    /** Get current VCNs for testing purposes */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public Map<ParcelUuid, Vcn> getAllVcns() {
         synchronized (mLock) {
@@ -516,6 +567,14 @@
         }
     }
 
+    /** Get current VcnStatusCallbacks for testing purposes. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public Map<IBinder, VcnStatusCallbackInfo> getAllStatusCallbacks() {
+        synchronized (mLock) {
+            return Collections.unmodifiableMap(mRegisteredStatusCallbacks);
+        }
+    }
+
     /** Binder death recipient used to remove a registered policy listener. */
     private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
         @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
@@ -606,21 +665,209 @@
         }
 
         boolean isVcnManagedNetwork = false;
+        boolean isRestrictedCarrierWifi = false;
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             synchronized (mLock) {
                 ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
 
-                // TODO(b/178140910): only mark the Network as VCN-managed if not in safe mode
-                if (mVcns.containsKey(subGroup)) {
-                    isVcnManagedNetwork = true;
+                Vcn vcn = mVcns.get(subGroup);
+                if (vcn != null) {
+                    if (vcn.isActive()) {
+                        isVcnManagedNetwork = true;
+                    }
+
+                    if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                        // Carrier WiFi always restricted if VCN exists (even in safe mode).
+                        isRestrictedCarrierWifi = true;
+                    }
                 }
             }
         }
+
         if (isVcnManagedNetwork) {
             networkCapabilities.removeCapability(
                     NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
         }
 
+        if (isRestrictedCarrierWifi) {
+            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
         return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
     }
+
+    /** Binder death recipient used to remove registered VcnStatusCallbacks. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    class VcnStatusCallbackInfo implements Binder.DeathRecipient {
+        @NonNull final ParcelUuid mSubGroup;
+        @NonNull final IVcnStatusCallback mCallback;
+        @NonNull final String mPkgName;
+        final int mUid;
+
+        private VcnStatusCallbackInfo(
+                @NonNull ParcelUuid subGroup,
+                @NonNull IVcnStatusCallback callback,
+                @NonNull String pkgName,
+                int uid) {
+            mSubGroup = subGroup;
+            mCallback = callback;
+            mPkgName = pkgName;
+            mUid = uid;
+        }
+
+        @Override
+        public void binderDied() {
+            Log.e(TAG, "app died without unregistering VcnStatusCallback");
+            unregisterVcnStatusCallback(mCallback);
+        }
+    }
+
+    /** Registers the provided callback for receiving VCN status updates. */
+    @Override
+    public void registerVcnStatusCallback(
+            @NonNull ParcelUuid subGroup,
+            @NonNull IVcnStatusCallback callback,
+            @NonNull String opPkgName) {
+        final int callingUid = mDeps.getBinderCallingUid();
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            requireNonNull(subGroup, "subGroup must not be null");
+            requireNonNull(callback, "callback must not be null");
+            requireNonNull(opPkgName, "opPkgName must not be null");
+
+            mContext.getSystemService(AppOpsManager.class).checkPackage(callingUid, opPkgName);
+
+            final IBinder cbBinder = callback.asBinder();
+            final VcnStatusCallbackInfo cbInfo =
+                    new VcnStatusCallbackInfo(
+                            subGroup, callback, opPkgName, mDeps.getBinderCallingUid());
+
+            try {
+                cbBinder.linkToDeath(cbInfo, 0 /* flags */);
+            } catch (RemoteException e) {
+                // Remote binder already died - don't add to mRegisteredStatusCallbacks and exit
+                return;
+            }
+
+            synchronized (mLock) {
+                if (mRegisteredStatusCallbacks.containsKey(cbBinder)) {
+                    throw new IllegalStateException(
+                            "Attempting to register a callback that is already in use");
+                }
+
+                mRegisteredStatusCallbacks.put(cbBinder, cbInfo);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /** Unregisters the provided callback from receiving future VCN status updates. */
+    @Override
+    public void unregisterVcnStatusCallback(@NonNull IVcnStatusCallback callback) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            requireNonNull(callback, "callback must not be null");
+
+            final IBinder cbBinder = callback.asBinder();
+            synchronized (mLock) {
+                VcnStatusCallbackInfo cbInfo = mRegisteredStatusCallbacks.remove(cbBinder);
+
+                if (cbInfo != null) {
+                    cbBinder.unlinkToDeath(cbInfo, 0 /* flags */);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
+    /** Callback for Vcn signals sent up to VcnManagementService. */
+    public interface VcnCallback {
+        /** Called by a Vcn to signal that it has entered safe mode. */
+        void onEnteredSafeMode();
+
+        /** Called by a Vcn to signal that an error occurred. */
+        void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable String exceptionClass,
+                @Nullable String exceptionMessage);
+    }
+
+    /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
+    private class VcnCallbackImpl implements VcnCallback {
+        @NonNull private final ParcelUuid mSubGroup;
+
+        private VcnCallbackImpl(@NonNull final ParcelUuid subGroup) {
+            mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
+        }
+
+        private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) {
+            if (!mSubGroup.equals(cbInfo.mSubGroup)) {
+                return false;
+            }
+
+            if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(
+                    mSubGroup, cbInfo.mPkgName)) {
+                return false;
+            }
+
+            if (!mLocationPermissionChecker.checkLocationPermission(
+                    cbInfo.mPkgName,
+                    "VcnStatusCallback" /* featureId */,
+                    cbInfo.mUid,
+                    null /* message */)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public void onEnteredSafeMode() {
+            synchronized (mLock) {
+                // Ignore if this subscription group doesn't exist anymore
+                if (!mVcns.containsKey(mSubGroup)) {
+                    return;
+                }
+
+                notifyAllPolicyListenersLocked();
+
+                // Notify all registered StatusCallbacks for this subGroup
+                for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
+                    if (isCallbackPermissioned(cbInfo)) {
+                        Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode());
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable String exceptionClass,
+                @Nullable String exceptionMessage) {
+            synchronized (mLock) {
+                // Ignore if this subscription group doesn't exist anymore
+                if (!mVcns.containsKey(mSubGroup)) {
+                    return;
+                }
+
+                // Notify all registered StatusCallbacks for this subGroup
+                for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
+                    if (isCallbackPermissioned(cbInfo)) {
+                        Binder.withCleanCallingIdentity(
+                                () ->
+                                        cbInfo.mCallback.onGatewayConnectionError(
+                                                networkCapabilities,
+                                                errorCode,
+                                                exceptionClass,
+                                                exceptionMessage));
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
new file mode 100644
index 0000000..5d89bf1
--- /dev/null
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -0,0 +1,918 @@
+/*
+ * 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 com.android.server;
+
+import static android.Manifest.permission.NETWORK_STACK;
+
+import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.IVpnManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkStack;
+import android.net.UnderlyingNetworkInfo;
+import android.net.Uri;
+import android.net.VpnManager;
+import android.net.VpnService;
+import android.net.util.NetdService;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.connectivity.Vpn;
+import com.android.server.net.LockdownVpnTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Service that tracks and manages VPNs, and backs the VpnService and VpnManager APIs.
+ * @hide
+ */
+public class VpnManagerService extends IVpnManager.Stub {
+    private static final String TAG = VpnManagerService.class.getSimpleName();
+
+    @VisibleForTesting
+    protected final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+
+    private final Context mContext;
+    private final Context mUserAllContext;
+
+    private final Dependencies mDeps;
+
+    private final ConnectivityManager mCm;
+    private final KeyStore mKeyStore;
+    private final INetworkManagementService mNMS;
+    private final INetd mNetd;
+    private final UserManager mUserManager;
+
+    @VisibleForTesting
+    @GuardedBy("mVpns")
+    protected final SparseArray<Vpn> mVpns = new SparseArray<>();
+
+    // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
+    // a direct call to LockdownVpnTracker.isEnabled().
+    @GuardedBy("mVpns")
+    private boolean mLockdownEnabled;
+    @GuardedBy("mVpns")
+    private LockdownVpnTracker mLockdownTracker;
+
+    /**
+     * Dependencies of VpnManager, for injection in tests.
+     */
+    @VisibleForTesting
+    public static class Dependencies {
+        /** Returns the calling UID of an IPC. */
+        public int getCallingUid() {
+            return Binder.getCallingUid();
+        }
+
+        /** Creates a HandlerThread to be used by this class. */
+        public HandlerThread makeHandlerThread() {
+            return new HandlerThread("VpnManagerService");
+        }
+
+        /** Returns the KeyStore instance to be used by this class. */
+        public KeyStore getKeyStore() {
+            return KeyStore.getInstance();
+        }
+
+        public INetd getNetd() {
+            return NetdService.getInstance();
+        }
+
+        public INetworkManagementService getINetworkManagementService() {
+            return INetworkManagementService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        }
+    }
+
+    public VpnManagerService(Context context, Dependencies deps) {
+        mContext = context;
+        mDeps = deps;
+        mHandlerThread = mDeps.makeHandlerThread();
+        mHandlerThread.start();
+        mHandler = mHandlerThread.getThreadHandler();
+        mKeyStore = mDeps.getKeyStore();
+        mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+        mCm = mContext.getSystemService(ConnectivityManager.class);
+        mNMS = mDeps.getINetworkManagementService();
+        mNetd = mDeps.getNetd();
+        mUserManager = mContext.getSystemService(UserManager.class);
+        registerReceivers();
+        log("VpnManagerService starting up");
+    }
+
+    /** Creates a new VpnManagerService */
+    public static VpnManagerService create(Context context) {
+        return new VpnManagerService(context, new Dependencies());
+    }
+
+    /** Informs the service that the system is ready. */
+    public void systemReady() {
+        // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
+        // for user to unlock device too.
+        updateLockdownVpn();
+    }
+
+    @Override
+    /** Dumps service state. */
+    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
+            @Nullable String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println("VPNs:");
+        pw.increaseIndent();
+        synchronized (mVpns) {
+            for (int i = 0; i < mVpns.size(); i++) {
+                pw.println(mVpns.keyAt(i) + ": " + mVpns.valueAt(i).getPackage());
+            }
+            pw.decreaseIndent();
+        }
+    }
+
+    /**
+     * Prepare for a VPN application.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param oldPackage Package name of the application which currently controls VPN, which will
+     *                   be replaced. If there is no such application, this should should either be
+     *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
+     * @param newPackage Package name of the application which should gain control of VPN, or
+     *                   {@code null} to disable.
+     * @param userId User for whom to prepare the new VPN.
+     *
+     * @hide
+     */
+    @Override
+    public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+            int userId) {
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            Vpn vpn = mVpns.get(userId);
+            if (vpn != null) {
+                return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Set whether the VPN package has the ability to launch VPNs without user intervention. This
+     * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
+     * class. If the caller is not {@code userId}, {@link
+     * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param packageName The package for which authorization state should change.
+     * @param userId User for whom {@code packageName} is installed.
+     * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
+     *     permissions should be granted. When unauthorizing an app, {@link
+     *     VpnManager.TYPE_VPN_NONE} should be used.
+     * @hide
+     */
+    @Override
+    public void setVpnPackageAuthorization(
+            String packageName, int userId, @VpnManager.VpnType int vpnType) {
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn != null) {
+                vpn.setPackageAuthorization(packageName, vpnType);
+            }
+        }
+    }
+
+    /**
+     * Configure a TUN interface and return its file descriptor. Parameters
+     * are encoded and opaque to this class. This method is used by VpnBuilder
+     * and not available in VpnManager. Permissions are checked in
+     * Vpn class.
+     * @hide
+     */
+    @Override
+    public ParcelFileDescriptor establishVpn(VpnConfig config) {
+        int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            return mVpns.get(user).establish(config);
+        }
+    }
+
+    @Override
+    public boolean addVpnAddress(String address, int prefixLength) {
+        int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            return mVpns.get(user).addAddress(address, prefixLength);
+        }
+    }
+
+    @Override
+    public boolean removeVpnAddress(String address, int prefixLength) {
+        int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            return mVpns.get(user).removeAddress(address, prefixLength);
+        }
+    }
+
+    @Override
+    public boolean setUnderlyingNetworksForVpn(Network[] networks) {
+        int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final boolean success;
+        synchronized (mVpns) {
+            success = mVpns.get(user).setUnderlyingNetworks(networks);
+        }
+        return success;
+    }
+
+    /**
+     * Stores the given VPN profile based on the provisioning package name.
+     *
+     * <p>If there is already a VPN profile stored for the provisioning package, this call will
+     * overwrite the profile.
+     *
+     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+     * exclusively by the Settings app, and passed into the platform at startup time.
+     *
+     * @return {@code true} if user consent has already been granted, {@code false} otherwise.
+     * @hide
+     */
+    @Override
+    public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
+        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
+        }
+    }
+
+    /**
+     * Deletes the stored VPN profile for the provisioning package
+     *
+     * <p>If there are no profiles for the given package, this method will silently succeed.
+     *
+     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+     * exclusively by the Settings app, and passed into the platform at startup time.
+     *
+     * @hide
+     */
+    @Override
+    public void deleteVpnProfile(@NonNull String packageName) {
+        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
+        }
+    }
+
+    /**
+     * Starts the VPN based on the stored profile for the given package
+     *
+     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+     * exclusively by the Settings app, and passed into the platform at startup time.
+     *
+     * @throws IllegalArgumentException if no profile was found for the given package name.
+     * @hide
+     */
+    @Override
+    public void startVpnProfile(@NonNull String packageName) {
+        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            mVpns.get(user).startVpnProfile(packageName, mKeyStore);
+        }
+    }
+
+    /**
+     * Stops the Platform VPN if the provided package is running one.
+     *
+     * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+     * exclusively by the Settings app, and passed into the platform at startup time.
+     *
+     * @hide
+     */
+    @Override
+    public void stopVpnProfile(@NonNull String packageName) {
+        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        synchronized (mVpns) {
+            mVpns.get(user).stopVpnProfile(packageName);
+        }
+    }
+
+    /**
+     * Start legacy VPN, controlling native daemons as needed. Creates a
+     * secondary thread to perform connection work, returning quickly.
+     */
+    @Override
+    public void startLegacyVpn(VpnProfile profile) {
+        int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final LinkProperties egress = mCm.getActiveLinkProperties();
+        if (egress == null) {
+            throw new IllegalStateException("Missing active network connection");
+        }
+        synchronized (mVpns) {
+            throwIfLockdownEnabled();
+            mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
+        }
+    }
+
+    /**
+     * Return the information of the ongoing legacy VPN. This method is used
+     * by VpnSettings and not available in ConnectivityManager. Permissions
+     * are checked in Vpn class.
+     */
+    @Override
+    public LegacyVpnInfo getLegacyVpnInfo(int userId) {
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            return mVpns.get(userId).getLegacyVpnInfo();
+        }
+    }
+
+    /**
+     * Returns the information of the ongoing VPN for {@code userId}. This method is used by
+     * VpnDialogs and not available in ConnectivityManager.
+     * Permissions are checked in Vpn class.
+     * @hide
+     */
+    @Override
+    public VpnConfig getVpnConfig(int userId) {
+        enforceCrossUserPermission(userId);
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn != null) {
+                return vpn.getVpnConfig();
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private boolean isLockdownVpnEnabled() {
+        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+    }
+
+    @Override
+    public boolean updateLockdownVpn() {
+        // Allow the system UID for the system server and for Settings.
+        // Also, for unit tests, allow the process that ConnectivityService is running in.
+        if (mDeps.getCallingUid() != Process.SYSTEM_UID
+                && Binder.getCallingPid() != Process.myPid()) {
+            logw("Lockdown VPN only available to system process or AID_SYSTEM");
+            return false;
+        }
+
+        synchronized (mVpns) {
+            // Tear down existing lockdown if profile was removed
+            mLockdownEnabled = isLockdownVpnEnabled();
+            if (!mLockdownEnabled) {
+                setLockdownTracker(null);
+                return true;
+            }
+
+            byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+            if (profileTag == null) {
+                loge("Lockdown VPN configured but cannot be read from keystore");
+                return false;
+            }
+            String profileName = new String(profileTag);
+            final VpnProfile profile = VpnProfile.decode(
+                    profileName, mKeyStore.get(Credentials.VPN + profileName));
+            if (profile == null) {
+                loge("Lockdown VPN configured invalid profile " + profileName);
+                setLockdownTracker(null);
+                return true;
+            }
+            int user = UserHandle.getUserId(mDeps.getCallingUid());
+            Vpn vpn = mVpns.get(user);
+            if (vpn == null) {
+                logw("VPN for user " + user + " not ready yet. Skipping lockdown");
+                return false;
+            }
+            setLockdownTracker(
+                    new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn,  profile));
+        }
+
+        return true;
+    }
+
+    /**
+     * Internally set new {@link LockdownVpnTracker}, shutting down any existing
+     * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
+     */
+    @GuardedBy("mVpns")
+    private void setLockdownTracker(LockdownVpnTracker tracker) {
+        // Shutdown any existing tracker
+        final LockdownVpnTracker existing = mLockdownTracker;
+        // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
+        // necessary onBlockedStatusChanged callbacks.
+        mLockdownTracker = null;
+        if (existing != null) {
+            existing.shutdown();
+        }
+
+        if (tracker != null) {
+            mLockdownTracker = tracker;
+            mLockdownTracker.init();
+        }
+    }
+
+    /**
+     * Throws if there is any currently running, always-on Legacy VPN.
+     *
+     * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
+     * running across the entire system. Tracking for app-based VPNs is done on a per-user,
+     * per-package basis in Vpn.java
+     */
+    @GuardedBy("mVpns")
+    private void throwIfLockdownEnabled() {
+        if (mLockdownEnabled) {
+            throw new IllegalStateException("Unavailable in lockdown mode");
+        }
+    }
+
+    /**
+     * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
+     * some setup and then call {@code establish()} to connect.
+     *
+     * @return {@code true} if the service was started, the service was already connected, or there
+     *         was no always-on VPN to start. {@code false} otherwise.
+     */
+    private boolean startAlwaysOnVpn(int userId) {
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                // Shouldn't happen as all code paths that point here should have checked the Vpn
+                // exists already.
+                Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
+                return false;
+            }
+
+            return vpn.startAlwaysOnVpn(mKeyStore);
+        }
+    }
+
+    @Override
+    public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
+        enforceSettingsPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                logw("User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
+        }
+    }
+
+    @Override
+    public boolean setAlwaysOnVpnPackage(
+            int userId, String packageName, boolean lockdown, List<String> lockdownAllowlist) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            // Can't set always-on VPN if legacy VPN is already in lockdown mode.
+            if (isLockdownVpnEnabled()) {
+                return false;
+            }
+
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                logw("User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist, mKeyStore)) {
+                return false;
+            }
+            if (!startAlwaysOnVpn(userId)) {
+                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String getAlwaysOnVpnPackage(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                logw("User " + userId + " has no Vpn configuration");
+                return null;
+            }
+            return vpn.getAlwaysOnPackage();
+        }
+    }
+
+    @Override
+    public boolean isVpnLockdownEnabled(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                logw("User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            return vpn.getLockdown();
+        }
+    }
+
+    @Override
+    public List<String> getVpnLockdownAllowlist(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                logw("User " + userId + " has no Vpn configuration");
+                return null;
+            }
+            return vpn.getLockdownAllowlist();
+        }
+    }
+
+    @GuardedBy("mVpns")
+    private Vpn getVpnIfOwner() {
+        return getVpnIfOwner(mDeps.getCallingUid());
+    }
+
+    // TODO: stop calling into Vpn.java and get this information from data in this class.
+    @GuardedBy("mVpns")
+    private Vpn getVpnIfOwner(int uid) {
+        final int user = UserHandle.getUserId(uid);
+
+        final Vpn vpn = mVpns.get(user);
+        if (vpn == null) {
+            return null;
+        } else {
+            final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
+            return (info == null || info.ownerUid != uid) ? null : vpn;
+        }
+    }
+
+    private void registerReceivers() {
+        // Set up the listener for user state for creating user VPNs.
+        // Should run on mHandler to avoid any races.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_STARTED);
+        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
+        intentFilter.addAction(Intent.ACTION_USER_ADDED);
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+
+        mUserAllContext.registerReceiver(
+                mIntentReceiver,
+                intentFilter,
+                null /* broadcastPermission */,
+                mHandler);
+        mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+                mUserPresentReceiver,
+                new IntentFilter(Intent.ACTION_USER_PRESENT),
+                null /* broadcastPermission */,
+                mHandler /* scheduler */);
+
+        // Listen to package add and removal events for all users.
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addDataScheme("package");
+        mUserAllContext.registerReceiver(
+                mIntentReceiver,
+                intentFilter,
+                null /* broadcastPermission */,
+                mHandler);
+
+        // Listen to lockdown VPN reset.
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
+        mUserAllContext.registerReceiver(
+                mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+    }
+
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            ensureRunningOnHandlerThread();
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+            final Uri packageData = intent.getData();
+            final String packageName =
+                    packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+            if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
+                onVpnLockdownReset();
+            }
+
+            // UserId should be filled for below intents, check the existence.
+            if (userId == UserHandle.USER_NULL) return;
+
+            if (Intent.ACTION_USER_STARTED.equals(action)) {
+                onUserStarted(userId);
+            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+                onUserStopped(userId);
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                onUserAdded(userId);
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                onUserRemoved(userId);
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                onUserUnlocked(userId);
+            } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+                onPackageReplaced(packageName, uid);
+            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                final boolean isReplacing = intent.getBooleanExtra(
+                        Intent.EXTRA_REPLACING, false);
+                onPackageRemoved(packageName, uid, isReplacing);
+            } else {
+                Log.wtf(TAG, "received unexpected intent: " + action);
+            }
+        }
+    };
+
+    private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            ensureRunningOnHandlerThread();
+            // Try creating lockdown tracker, since user present usually means
+            // unlocked keystore.
+            updateLockdownVpn();
+            // Use the same context that registered receiver before to unregister it. Because use
+            // different context to unregister receiver will cause exception.
+            context.unregisterReceiver(this);
+        }
+    };
+
+    private void onUserStarted(int userId) {
+        synchronized (mVpns) {
+            Vpn userVpn = mVpns.get(userId);
+            if (userVpn != null) {
+                loge("Starting user already has a VPN");
+                return;
+            }
+            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
+            mVpns.put(userId, userVpn);
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+                updateLockdownVpn();
+            }
+        }
+    }
+
+    private void onUserStopped(int userId) {
+        synchronized (mVpns) {
+            Vpn userVpn = mVpns.get(userId);
+            if (userVpn == null) {
+                loge("Stopped user has no VPN");
+                return;
+            }
+            userVpn.onUserStopped();
+            mVpns.delete(userId);
+        }
+    }
+
+    @Override
+    public boolean isCallerCurrentAlwaysOnVpnApp() {
+        synchronized (mVpns) {
+            Vpn vpn = getVpnIfOwner();
+            return vpn != null && vpn.getAlwaysOn();
+        }
+    }
+
+    @Override
+    public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
+        synchronized (mVpns) {
+            Vpn vpn = getVpnIfOwner();
+            return vpn != null && vpn.getLockdown();
+        }
+    }
+
+
+    private void onUserAdded(int userId) {
+        synchronized (mVpns) {
+            final int vpnsSize = mVpns.size();
+            for (int i = 0; i < vpnsSize; i++) {
+                Vpn vpn = mVpns.valueAt(i);
+                vpn.onUserAdded(userId);
+            }
+        }
+    }
+
+    private void onUserRemoved(int userId) {
+        synchronized (mVpns) {
+            final int vpnsSize = mVpns.size();
+            for (int i = 0; i < vpnsSize; i++) {
+                Vpn vpn = mVpns.valueAt(i);
+                vpn.onUserRemoved(userId);
+            }
+        }
+    }
+
+    private void onPackageReplaced(String packageName, int uid) {
+        if (TextUtils.isEmpty(packageName) || uid < 0) {
+            Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
+            return;
+        }
+        final int userId = UserHandle.getUserId(uid);
+        synchronized (mVpns) {
+            final Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                return;
+            }
+            // Legacy always-on VPN won't be affected since the package name is not set.
+            if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
+                log("Restarting always-on VPN package " + packageName + " for user "
+                        + userId);
+                vpn.startAlwaysOnVpn(mKeyStore);
+            }
+        }
+    }
+
+    private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
+        if (TextUtils.isEmpty(packageName) || uid < 0) {
+            Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+            return;
+        }
+
+        final int userId = UserHandle.getUserId(uid);
+        synchronized (mVpns) {
+            final Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                return;
+            }
+            // Legacy always-on VPN won't be affected since the package name is not set.
+            if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
+                log("Removing always-on VPN package " + packageName + " for user "
+                        + userId);
+                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+            }
+        }
+    }
+
+    private void onUserUnlocked(int userId) {
+        synchronized (mVpns) {
+            // User present may be sent because of an unlock, which might mean an unlocked keystore.
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+                updateLockdownVpn();
+            } else {
+                startAlwaysOnVpn(userId);
+            }
+        }
+    }
+
+    private void onVpnLockdownReset() {
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) mLockdownTracker.reset();
+        }
+    }
+
+
+    @Override
+    public void factoryReset() {
+        enforceSettingsPermission();
+
+        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)
+                || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
+            return;
+        }
+
+        // Remove always-on package
+        final int userId = UserHandle.getCallingUserId();
+        synchronized (mVpns) {
+            final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
+            if (alwaysOnPackage != null) {
+                setAlwaysOnVpnPackage(userId, null, false, null);
+                setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
+            }
+
+            // Turn Always-on VPN off
+            if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+                    mLockdownEnabled = false;
+                    setLockdownTracker(null);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+
+            // Turn VPN off
+            VpnConfig vpnConfig = getVpnConfig(userId);
+            if (vpnConfig != null) {
+                if (vpnConfig.legacy) {
+                    prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
+                } else {
+                    // Prevent this app (packagename = vpnConfig.user) from initiating
+                    // VPN connections in the future without user intervention.
+                    setVpnPackageAuthorization(
+                            vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
+
+                    prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
+                }
+            }
+        }
+    }
+
+    private void ensureRunningOnHandlerThread() {
+        if (mHandler.getLooper().getThread() != Thread.currentThread()) {
+            throw new IllegalStateException(
+                    "Not running on VpnManagerService thread: "
+                            + Thread.currentThread().getName());
+        }
+    }
+
+    private void enforceControlAlwaysOnVpnPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+                "VpnManagerService");
+    }
+
+    /**
+     * Require that the caller is either in the same user or has appropriate permission to interact
+     * across users.
+     *
+     * @param userId Target user for whatever operation the current IPC is supposed to perform.
+     */
+    private void enforceCrossUserPermission(int userId) {
+        if (userId == UserHandle.getCallingUserId()) {
+            // Not a cross-user call.
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                "VpnManagerService");
+    }
+
+    private void enforceSettingsPermission() {
+        enforceAnyPermissionOf(mContext,
+                android.Manifest.permission.NETWORK_SETTINGS,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+    }
+
+    private static void log(String s) {
+        Log.d(TAG, s);
+    }
+
+    private static void logw(String s) {
+        Log.w(TAG, s);
+    }
+
+    private static void loge(String s) {
+        Log.e(TAG, s);
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/OWNERS b/services/core/java/com/android/server/accounts/OWNERS
index ea5fd36..8dcc04a 100644
--- a/services/core/java/com/android/server/accounts/OWNERS
+++ b/services/core/java/com/android/server/accounts/OWNERS
@@ -3,7 +3,6 @@
 sandrakwan@google.com
 hackbod@google.com
 svetoslavganov@google.com
-moltmann@google.com
 fkupolov@google.com
 yamasani@google.com
 omakoto@google.com
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 686adbb..900871d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -364,6 +364,7 @@
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
+import com.android.server.os.NativeTombstoneManager;
 import com.android.server.pm.Installer;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.uri.GrantUri;
@@ -7144,67 +7145,68 @@
                         "getContentProviderImpl: after checkContentProviderPermission");
 
                 final long origId = Binder.clearCallingIdentity();
+                try {
+                    checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
 
-                checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
-
-                // In this case the provider instance already exists, so we can
-                // return it right away.
-                conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
-                        stable);
-                if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
-                    if (cpr.proc != null
-                            && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
-                        // If this is a perceptible app accessing the provider,
-                        // make sure to count it as being accessed and thus
-                        // back up on the LRU list.  This is good because
-                        // content providers are often expensive to start.
-                        checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
-                        mProcessList.updateLruProcessLocked(cpr.proc, false, null);
-                        checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
+                    // Return the provider instance right away since it already exists.
+                    conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage,
+                            callingTag, stable);
+                    if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
+                        if (cpr.proc != null
+                                && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+                            // If this is a perceptible app accessing the provider,
+                            // make sure to count it as being accessed and thus
+                            // back up on the LRU list.  This is good because
+                            // content providers are often expensive to start.
+                            checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
+                            mProcessList.updateLruProcessLocked(cpr.proc, false, null);
+                            checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
+                        }
                     }
-                }
 
-                checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
-                final int verifiedAdj = cpr.proc.verifiedAdj;
-                boolean success = updateOomAdjLocked(cpr.proc, true,
-                        OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
-                // XXX things have changed so updateOomAdjLocked doesn't actually tell us
-                // if the process has been successfully adjusted.  So to reduce races with
-                // it, we will check whether the process still exists.  Note that this doesn't
-                // completely get rid of races with LMK killing the process, but should make
-                // them much smaller.
-                if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
-                    success = false;
-                }
-                maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
-                checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
-                if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
-                // NOTE: there is still a race here where a signal could be
-                // pending on the process even though we managed to update its
-                // adj level.  Not sure what to do about this, but at least
-                // the race is now smaller.
-                if (!success) {
-                    // Uh oh...  it looks like the provider's process
-                    // has been killed on us.  We need to wait for a new
-                    // process to be started, and make sure its death
-                    // doesn't kill our process.
-                    Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
-                            + " is crashing; detaching " + r);
-                    boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
-                    if (!lastRef) {
-                        // This wasn't the last ref our process had on
-                        // the provider...  we will be killed during cleaning up, bail.
-                        return null;
+                    checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
+                    final int verifiedAdj = cpr.proc.verifiedAdj;
+                    boolean success = updateOomAdjLocked(cpr.proc, true,
+                            OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
+                    // XXX things have changed so updateOomAdjLocked doesn't actually tell us
+                    // if the process has been successfully adjusted.  So to reduce races with
+                    // it, we will check whether the process still exists.  Note that this doesn't
+                    // completely get rid of races with LMK killing the process, but should make
+                    // them much smaller.
+                    if (success && verifiedAdj != cpr.proc.setAdj
+                            && !isProcessAliveLocked(cpr.proc)) {
+                        success = false;
                     }
-                    // We'll just start a new process to host the content provider
-                    providerRunning = false;
-                    conn = null;
-                    dyingProc = cpr.proc;
-                } else {
-                    cpr.proc.verifiedAdj = cpr.proc.setAdj;
+                    maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
+                    checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
+                    if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
+                    // NOTE: there is still a race here where a signal could be
+                    // pending on the process even though we managed to update its
+                    // adj level.  Not sure what to do about this, but at least
+                    // the race is now smaller.
+                    if (!success) {
+                        // Uh oh...  it looks like the provider's process
+                        // has been killed on us.  We need to wait for a new
+                        // process to be started, and make sure its death
+                        // doesn't kill our process.
+                        Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+                                + " is crashing; detaching " + r);
+                        boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
+                        if (!lastRef) {
+                            // This wasn't the last ref our process had on
+                            // the provider...  we will be killed during cleaning up, bail.
+                            return null;
+                        }
+                        // We'll just start a new process to host the content provider
+                        providerRunning = false;
+                        conn = null;
+                        dyingProc = cpr.proc;
+                    } else {
+                        cpr.proc.verifiedAdj = cpr.proc.setAdj;
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
                 }
-
-                Binder.restoreCallingIdentity(origId);
             }
 
             if (!providerRunning) {
@@ -8211,20 +8213,11 @@
                 false /* mountExtStorageFull */, abiOverride, zygotePolicyFlags);
     }
 
+    // TODO: Move to ProcessList?
     @GuardedBy("this")
     final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
             boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride,
             int zygotePolicyFlags) {
-        return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks,
-                false /* disableTestApiChecks */, mountExtStorageFull, abiOverride,
-                zygotePolicyFlags);
-    }
-
-    // TODO: Move to ProcessList?
-    @GuardedBy("this")
-    final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
-            boolean disableHiddenApiChecks, boolean disableTestApiChecks,
-            boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) {
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -8259,8 +8252,7 @@
             mPersistentStartingProcesses.add(app);
             mProcessList.startProcessLocked(app, new HostingRecord("added application",
                     customProcess != null ? customProcess : app.processName),
-                    zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks,
-                    mountExtStorageFull, abiOverride);
+                    zygotePolicyFlags, disableHiddenApiChecks, mountExtStorageFull, abiOverride);
         }
 
         return app;
@@ -10419,6 +10411,9 @@
         mUserController.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL,
                 "getHistoricalProcessExitReasons", null);
 
+        NativeTombstoneManager tombstoneService = LocalServices.getService(
+                NativeTombstoneManager.class);
+
         final ArrayList<ApplicationExitInfo> results = new ArrayList<ApplicationExitInfo>();
         if (!TextUtils.isEmpty(packageName)) {
             final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
@@ -10426,11 +10421,13 @@
             if (uid != Process.INVALID_UID) {
                 mProcessList.mAppExitInfoTracker.getExitInfo(
                         packageName, uid, pid, maxNum, results);
+                tombstoneService.collectTombstones(results, uid, pid, maxNum);
             }
         } else {
             // If no package name is given, use the caller's uid as the filter uid.
             mProcessList.mAppExitInfoTracker.getExitInfo(
                     packageName, callingUid, pid, maxNum, results);
+            tombstoneService.collectTombstones(results, callingUid, pid, maxNum);
         }
 
         return new ParceledListSlice<ApplicationExitInfo>(results);
@@ -13327,6 +13324,7 @@
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
         long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
         long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+        long[] memtrackTmp = new long[4];
 
         long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
         long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
@@ -13339,6 +13337,8 @@
         long totalRss = 0;
         long cachedPss = 0;
         long cachedSwapPss = 0;
+        long totalMemtrackGraphics = 0;
+        long totalMemtrackGl = 0;
         boolean hasSwapPss = false;
 
         Debug.MemoryInfo mi = null;
@@ -13361,6 +13361,8 @@
                 final int reportType;
                 final long startTime;
                 final long endTime;
+                long memtrackGraphics = 0;
+                long memtrackGl = 0;
                 if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
                     reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
                     startTime = SystemClock.currentThreadTimeMillis();
@@ -13372,7 +13374,7 @@
                 } else {
                     reportType = ProcessStats.ADD_PSS_EXTERNAL;
                     startTime = SystemClock.currentThreadTimeMillis();
-                    long pss = Debug.getPss(pid, tmpLong, null);
+                    long pss = Debug.getPss(pid, tmpLong, memtrackTmp);
                     if (pss == 0) {
                         continue;
                     }
@@ -13380,6 +13382,8 @@
                     endTime = SystemClock.currentThreadTimeMillis();
                     mi.dalvikPrivateDirty = (int) tmpLong[0];
                     mi.dalvikRss = (int) tmpLong[2];
+                    memtrackGraphics = memtrackTmp[1];
+                    memtrackGl = memtrackTmp[2];
                 }
                 if (!opts.isCheckinRequest && opts.dumpDetails) {
                     pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
@@ -13444,6 +13448,8 @@
                     totalPss += myTotalPss;
                     totalSwapPss += myTotalSwapPss;
                     totalRss += myTotalRss;
+                    totalMemtrackGraphics += memtrackGraphics;
+                    totalMemtrackGl += memtrackGl;
                     MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
                             (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
                             myTotalSwapPss, myTotalRss, pid, hasActivities);
@@ -13509,6 +13515,8 @@
                 for (int i=0; i<N; i++) {
                     ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
                     if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+                        long memtrackGraphics = 0;
+                        long memtrackGl = 0;
                         if (mi == null) {
                             mi = new Debug.MemoryInfo();
                         }
@@ -13517,13 +13525,15 @@
                                 continue;
                             }
                         } else {
-                            long pss = Debug.getPss(st.pid, tmpLong, null);
+                            long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
                             if (pss == 0) {
                                 continue;
                             }
                             mi.nativePss = (int) pss;
                             mi.nativePrivateDirty = (int) tmpLong[0];
                             mi.nativeRss = (int) tmpLong[2];
+                            memtrackGraphics = memtrackTmp[1];
+                            memtrackGl = memtrackTmp[2];
                         }
 
                         final long myTotalPss = mi.getTotalPss();
@@ -13533,6 +13543,8 @@
                         totalSwapPss += myTotalSwapPss;
                         totalRss += myTotalRss;
                         nativeProcTotalPss += myTotalPss;
+                        totalMemtrackGraphics += memtrackGraphics;
+                        totalMemtrackGl += memtrackGl;
 
                         MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
                                 st.name, myTotalPss, mi.getSummaryTotalSwapPss(), myTotalRss,
@@ -13729,13 +13741,13 @@
             long kernelUsed = memInfo.getKernelUsedSizeKb();
             final long ionHeap = Debug.getIonHeapsSizeKb();
             final long ionPool = Debug.getIonPoolsSizeKb();
+            final long dmabufMapped = Debug.getDmabufMappedSizeKb();
             if (ionHeap >= 0 && ionPool >= 0) {
-                final long ionMapped = Debug.getIonMappedSizeKb();
-                final long ionUnmapped = ionHeap - ionMapped;
+                final long ionUnmapped = ionHeap - dmabufMapped;
                 pw.print("      ION: ");
                         pw.print(stringifyKBSize(ionHeap + ionPool));
                         pw.print(" (");
-                        pw.print(stringifyKBSize(ionMapped));
+                        pw.print(stringifyKBSize(dmabufMapped));
                         pw.print(" mapped + ");
                         pw.print(stringifyKBSize(ionUnmapped));
                         pw.print(" unmapped + ");
@@ -13744,11 +13756,61 @@
                 // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
                 // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
                 kernelUsed += ionHeap;
+            } else {
+                final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
+                if (totalExportedDmabuf >= 0) {
+                    final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
+                    pw.print("DMA-BUF: ");
+                    pw.print(stringifyKBSize(totalExportedDmabuf));
+                    pw.print(" (");
+                    pw.print(stringifyKBSize(dmabufMapped));
+                    pw.print(" mapped + ");
+                    pw.print(stringifyKBSize(dmabufUnmapped));
+                    pw.println(" unmapped)");
+                    // Account unmapped dmabufs as part of kernel memory allocations
+                    kernelUsed += dmabufUnmapped;
+                    // Replace memtrack HAL reported Graphics category with mapped dmabufs
+                    totalPss -= totalMemtrackGraphics;
+                    totalPss += dmabufMapped;
+                }
+
+                // totalDmabufHeapExported is included in totalExportedDmabuf above and hence do not
+                // need to be added to kernelUsed.
+                final long totalDmabufHeapExported = Debug.getDmabufHeapTotalExportedKb();
+                if (totalDmabufHeapExported >= 0) {
+                    pw.print("DMA-BUF Heaps: ");
+                    pw.println(stringifyKBSize(totalDmabufHeapExported));
+                }
+
+                final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
+                if (totalDmabufHeapPool >= 0) {
+                    pw.print("DMA-BUF Heaps pool: ");
+                    pw.println(stringifyKBSize(totalDmabufHeapPool));
+                }
             }
             final long gpuUsage = Debug.getGpuTotalUsageKb();
             if (gpuUsage >= 0) {
-                pw.print("      GPU: "); pw.println(stringifyKBSize(gpuUsage));
+                final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+                if (gpuDmaBufUsage >= 0) {
+                    final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+                    pw.print("      GPU: ");
+                    pw.print(stringifyKBSize(gpuUsage));
+                    pw.print(" (");
+                    pw.print(stringifyKBSize(gpuDmaBufUsage));
+                    pw.print(" dmabuf + ");
+                    pw.print(stringifyKBSize(gpuPrivateUsage));
+                    pw.println(" private)");
+                    // Replace memtrack HAL reported GL category with private GPU allocations and
+                    // account it as part of kernel memory allocations
+                    totalPss -= totalMemtrackGl;
+                    kernelUsed += gpuPrivateUsage;
+                } else {
+                    pw.print("      GPU: "); pw.println(stringifyKBSize(gpuUsage));
+                }
             }
+
+             // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+             // memInfo.getCachedSizeKb().
             final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
                     - kernelUsed - memInfo.getZramTotalSizeKb();
@@ -14352,7 +14414,7 @@
             infoMap.put(mi.pid, mi);
         }
         updateCpuStatsNow();
-        long[] memtrackTmp = new long[1];
+        long[] memtrackTmp = new long[4];
         long[] swaptrackTmp = new long[2];
         final List<ProcessCpuTracker.Stats> stats;
         // Get a list of Stats that have vsize > 0
@@ -14380,6 +14442,8 @@
         long totalPss = 0;
         long totalSwapPss = 0;
         long totalMemtrack = 0;
+        long totalMemtrackGraphics = 0;
+        long totalMemtrackGl = 0;
         for (int i=0, N=memInfos.size(); i<N; i++) {
             ProcessMemInfo mi = memInfos.get(i);
             if (mi.pss == 0) {
@@ -14390,6 +14454,8 @@
             totalPss += mi.pss;
             totalSwapPss += mi.swapPss;
             totalMemtrack += mi.memtrack;
+            totalMemtrackGraphics += memtrackTmp[1];
+            totalMemtrackGl += memtrackTmp[2];
         }
         Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
             @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
@@ -14548,25 +14614,74 @@
         final long ionHeap = Debug.getIonHeapsSizeKb();
         final long ionPool = Debug.getIonPoolsSizeKb();
         if (ionHeap >= 0 && ionPool >= 0) {
-            final long ionMapped = Debug.getIonMappedSizeKb();
-            final long ionUnmapped = ionHeap - ionMapped;
             memInfoBuilder.append("       ION: ");
             memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
             memInfoBuilder.append("\n");
             // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
             // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
             kernelUsed += ionHeap;
+        } else {
+            final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
+            if (totalExportedDmabuf >= 0) {
+                final long dmabufMapped = Debug.getDmabufMappedSizeKb();
+                final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
+                memInfoBuilder.append("DMA-BUF: ");
+                memInfoBuilder.append(stringifyKBSize(totalExportedDmabuf));
+                memInfoBuilder.append("\n");
+                // Account unmapped dmabufs as part of kernel memory allocations
+                kernelUsed += dmabufUnmapped;
+                // Replace memtrack HAL reported Graphics category with mapped dmabufs
+                totalPss -= totalMemtrackGraphics;
+                totalPss += dmabufMapped;
+            }
+
+            // These are included in the totalExportedDmabuf above and hence do not need to be added
+            // to kernelUsed.
+            final long totalExportedDmabufHeap = Debug.getDmabufHeapTotalExportedKb();
+            if (totalExportedDmabufHeap >= 0) {
+                memInfoBuilder.append("DMA-BUF Heap: ");
+                memInfoBuilder.append(stringifyKBSize(totalExportedDmabufHeap));
+                memInfoBuilder.append("\n");
+            }
+
+            final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
+            if (totalDmabufHeapPool >= 0) {
+                memInfoBuilder.append("DMA-BUF Heaps pool: ");
+                memInfoBuilder.append(stringifyKBSize(totalDmabufHeapPool));
+                memInfoBuilder.append("\n");
+            }
         }
+
         final long gpuUsage = Debug.getGpuTotalUsageKb();
         if (gpuUsage >= 0) {
-            memInfoBuilder.append("       GPU: ");
-            memInfoBuilder.append(stringifyKBSize(gpuUsage));
-            memInfoBuilder.append("\n");
+            final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+            if (gpuDmaBufUsage >= 0) {
+                final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+                memInfoBuilder.append("      GPU: ");
+                memInfoBuilder.append(stringifyKBSize(gpuUsage));
+                memInfoBuilder.append(" (");
+                memInfoBuilder.append(stringifyKBSize(gpuDmaBufUsage));
+                memInfoBuilder.append(" dmabuf + ");
+                memInfoBuilder.append(stringifyKBSize(gpuPrivateUsage));
+                memInfoBuilder.append(" private)\n");
+                // Replace memtrack HAL reported GL category with private GPU allocations and
+                // account it as part of kernel memory allocations
+                totalPss -= totalMemtrackGl;
+                kernelUsed += gpuPrivateUsage;
+            } else {
+                memInfoBuilder.append("       GPU: ");
+                memInfoBuilder.append(stringifyKBSize(gpuUsage));
+                memInfoBuilder.append("\n");
+            }
+
         }
         memInfoBuilder.append("  Used RAM: ");
         memInfoBuilder.append(stringifyKBSize(
                                   totalPss - cachedPss + kernelUsed));
         memInfoBuilder.append("\n");
+
+        // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+        // memInfo.getCachedSizeKb().
         memInfoBuilder.append("  Lost RAM: ");
         memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
                 - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
@@ -16943,11 +17058,12 @@
                     || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
             boolean disableTestApiChecks = disableHiddenApiChecks
                     || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
+
             if (disableHiddenApiChecks || disableTestApiChecks) {
                 enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
                         "disable hidden API checks");
 
-                enableTestApiAccess(ii.packageName);
+                enableTestApiAccess(ai.packageName);
             }
 
             // TODO(b/158750470): remove
@@ -16965,8 +17081,7 @@
             }
 
             ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
-                    disableTestApiChecks, mountExtStorageFull, abiOverride,
-                    ZYGOTE_POLICY_FLAG_EMPTY);
+                    mountExtStorageFull, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY);
             app.setActiveInstrumentation(activeInstr);
             activeInstr.mFinished = false;
             activeInstr.mSourceUid = callingUid;
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 374c215..f2c1f55 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -63,8 +63,10 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.IoThread;
+import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemServiceManager;
+import com.android.server.os.NativeTombstoneManager;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -78,6 +80,7 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
@@ -770,6 +773,10 @@
      * Helper function for shell command
      */
     void clearHistoryProcessExitInfo(String packageName, int userId) {
+        NativeTombstoneManager tombstoneService = LocalServices.getService(
+                NativeTombstoneManager.class);
+        Optional<Integer> appId = Optional.empty();
+
         if (TextUtils.isEmpty(packageName)) {
             synchronized (mLock) {
                 removeByUserIdLocked(userId);
@@ -777,10 +784,13 @@
         } else {
             final int uid = mService.mPackageManagerInt.getPackageUid(packageName,
                     PackageManager.MATCH_ALL, userId);
+            appId = Optional.of(UserHandle.getAppId(uid));
             synchronized (mLock) {
                 removePackageLocked(packageName, uid, true, userId);
             }
         }
+
+        tombstoneService.purge(Optional.of(userId), appId);
         schedulePersistProcessExitInfo(true);
     }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a2eea13..b7ecddc 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -809,7 +809,8 @@
                         r.resultExtras, r.ordered, r.initialSticky, r.userId);
                 // parallel broadcasts are fire-and-forget, not bookended by a call to
                 // finishReceiverLocked(), so we manage their activity-start token here
-                if (r.allowBackgroundActivityStarts && !r.ordered) {
+                if (filter.receiverList.app != null
+                        && r.allowBackgroundActivityStarts && !r.ordered) {
                     postActivityStartTokenRemoval(filter.receiverList.app, r);
                 }
             }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b6e632d..e2c020af 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1769,8 +1769,8 @@
      */
     @GuardedBy("mService")
     boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
-            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
-            boolean mountExtStorageFull, String abiOverride) {
+            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean mountExtStorageFull,
+            String abiOverride) {
         if (app.pendingStart) {
             return true;
         }
@@ -1914,10 +1914,6 @@
                     throw new IllegalStateException("Invalid API policy: " + policy);
                 }
                 runtimeFlags |= policyBits;
-
-                if (disableTestApiChecks) {
-                    runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY;
-                }
             }
 
             String useAppImageCache = SystemProperties.get(
@@ -2360,8 +2356,7 @@
     final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
             int zygotePolicyFlags, String abiOverride) {
         return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
-                false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
-                false /* mountExtStorageFull */, abiOverride);
+                false /* disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride);
     }
 
     @GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 28afcbb..c20a01d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -81,6 +81,7 @@
     static final String[] sDeviceConfigScopes = new String[] {
         DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_CONFIGURATION,
+        DeviceConfig.NAMESPACE_CONNECTIVITY,
         DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
         DeviceConfig.NAMESPACE_MEDIA_NATIVE,
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index fded85c..33bdac2 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -18,16 +18,17 @@
 
 import static android.content.Intent.ACTION_PACKAGE_ADDED;
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.Intent.ACTION_USER_ADDED;
-import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_REMOVED_FOR_ALL_USERS;
 import static android.content.Intent.EXTRA_REPLACING;
-import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
 
+import static com.android.server.apphibernation.AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.app.IActivityManager;
 import android.apphibernation.IAppHibernationService;
 import android.content.BroadcastReceiver;
@@ -36,8 +37,9 @@
 import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
-import android.content.pm.UserInfo;
+import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -46,18 +48,25 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.SystemService;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
 
 /**
  * System service that manages app hibernation state, a state apps can enter that means they are
@@ -66,6 +75,11 @@
  */
 public final class AppHibernationService extends SystemService {
     private static final String TAG = "AppHibernationService";
+    private static final int PACKAGE_MATCH_FLAGS =
+            PackageManager.MATCH_DIRECT_BOOT_AWARE
+                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                    | PackageManager.MATCH_UNINSTALLED_PACKAGES
+                    | PackageManager.MATCH_DISABLED_COMPONENTS;
 
     /**
      * Lock for accessing any in-memory hibernation state
@@ -76,9 +90,16 @@
     private final IActivityManager mIActivityManager;
     private final UserManager mUserManager;
     @GuardedBy("mLock")
-    private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>();
+    private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>();
+    private final SparseArray<HibernationStateDiskStore<UserLevelState>> mUserDiskStores =
+            new SparseArray<>();
     @GuardedBy("mLock")
-    private final Set<String> mGloballyHibernatedPackages = new ArraySet<>();
+    private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>();
+    private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore;
+    private final Injector mInjector;
+
+    @VisibleForTesting
+    boolean mIsServiceEnabled;
 
     /**
      * Initializes the system service.
@@ -90,28 +111,22 @@
      * @param context The system server context.
      */
     public AppHibernationService(@NonNull Context context) {
-        this(context, IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
-                ActivityManager.getService(),
-                context.getSystemService(UserManager.class));
+        this(new InjectorImpl(context));
     }
 
     @VisibleForTesting
-    AppHibernationService(@NonNull Context context, IPackageManager packageManager,
-            IActivityManager activityManager, UserManager userManager) {
-        super(context);
-        mContext = context;
-        mIPackageManager = packageManager;
-        mIActivityManager = activityManager;
-        mUserManager = userManager;
+    AppHibernationService(@NonNull Injector injector) {
+        super(injector.getContext());
+        mContext = injector.getContext();
+        mIPackageManager = injector.getPackageManager();
+        mIActivityManager = injector.getActivityManager();
+        mUserManager = injector.getUserManager();
+        mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
+        mInjector = injector;
 
         final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
 
         IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ACTION_USER_ADDED);
-        intentFilter.addAction(ACTION_USER_REMOVED);
-        userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
-
-        intentFilter = new IntentFilter();
         intentFilter.addAction(ACTION_PACKAGE_ADDED);
         intentFilter.addAction(ACTION_PACKAGE_REMOVED);
         intentFilter.addDataScheme("package");
@@ -126,14 +141,19 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_BOOT_COMPLETED) {
+            List<GlobalLevelState> states =
+                    mGlobalLevelHibernationDiskStore.readHibernationStates();
             synchronized (mLock) {
-                final List<UserInfo> users = mUserManager.getUsers();
-                // TODO: Pull from persistent disk storage. For now, just make from scratch.
-                for (UserInfo user : users) {
-                    addUserPackageStatesL(user.id);
-                }
+                initializeGlobalHibernationStates(states);
             }
         }
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            mIsServiceEnabled = isAppHibernationEnabled();
+            DeviceConfig.addOnPropertiesChangedListener(
+                    NAMESPACE_APP_HIBERNATION,
+                    ActivityThread.currentApplication().getMainExecutor(),
+                    this::onDeviceConfigChanged);
+        }
     }
 
     /**
@@ -144,13 +164,19 @@
      * @return true if package is hibernating for the user
      */
     boolean isHibernatingForUser(String packageName, int userId) {
+        if (!checkHibernationEnabled("isHibernatingForUser")) {
+            return false;
+        }
+
         userId = handleIncomingUser(userId, "isHibernating");
+        if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+            Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
+                    + userId);
+            return false;
+        }
         synchronized (mLock) {
-            final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
-            if (packageStates == null) {
-                throw new IllegalArgumentException("No user associated with user id " + userId);
-            }
-            final UserPackageState pkgState = packageStates.get(packageName);
+            final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
+            final UserLevelState pkgState = packageStates.get(packageName);
             if (pkgState == null) {
                 throw new IllegalArgumentException(
                         String.format("Package %s is not installed for user %s",
@@ -167,8 +193,16 @@
      * @param packageName package to check
      */
     boolean isHibernatingGlobally(String packageName) {
+        if (!checkHibernationEnabled("isHibernatingGlobally")) {
+            return false;
+        }
         synchronized (mLock) {
-            return mGloballyHibernatedPackages.contains(packageName);
+            GlobalLevelState state = mGlobalHibernationStates.get(packageName);
+            if (state == null) {
+                throw new IllegalArgumentException(
+                        String.format("Package %s is not installed", packageName));
+            }
+            return state.hibernated;
         }
     }
 
@@ -180,13 +214,18 @@
      * @param isHibernating new hibernation state
      */
     void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+        if (!checkHibernationEnabled("setHibernatingForUser")) {
+            return;
+        }
         userId = handleIncomingUser(userId, "setHibernating");
+        if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+            Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
+                    + userId);
+            return;
+        }
         synchronized (mLock) {
-            if (!mUserStates.contains(userId)) {
-                throw new IllegalArgumentException("No user associated with user id " + userId);
-            }
-            Map<String, UserPackageState> packageStates = mUserStates.get(userId);
-            UserPackageState pkgState = packageStates.get(packageName);
+            final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
+            final UserLevelState pkgState = packageStates.get(packageName);
             if (pkgState == null) {
                 throw new IllegalArgumentException(
                         String.format("Package %s is not installed for user %s",
@@ -198,10 +237,12 @@
             }
 
             if (isHibernating) {
-                hibernatePackageForUserL(packageName, userId, pkgState);
+                hibernatePackageForUser(packageName, userId, pkgState);
             } else {
-                unhibernatePackageForUserL(packageName, userId, pkgState);
+                unhibernatePackageForUser(packageName, userId, pkgState);
             }
+            List<UserLevelState> states = new ArrayList<>(mUserStates.get(userId).values());
+            mUserDiskStores.get(userId).scheduleWriteHibernationStates(states);
         }
     }
 
@@ -213,25 +254,35 @@
      * @param isHibernating new hibernation state
      */
     void setHibernatingGlobally(String packageName, boolean isHibernating) {
-        if (isHibernating != mGloballyHibernatedPackages.contains(packageName)) {
-            synchronized (mLock) {
+        if (!checkHibernationEnabled("setHibernatingGlobally")) {
+            return;
+        }
+        synchronized (mLock) {
+            GlobalLevelState state = mGlobalHibernationStates.get(packageName);
+            if (state == null) {
+                throw new IllegalArgumentException(
+                        String.format("Package %s is not installed for any user", packageName));
+            }
+            if (state.hibernated != isHibernating) {
                 if (isHibernating) {
-                    hibernatePackageGloballyL(packageName);
+                    hibernatePackageGlobally(packageName, state);
                 } else {
-                    unhibernatePackageGloballyL(packageName);
+                    unhibernatePackageGlobally(packageName, state);
                 }
+                List<GlobalLevelState> states = new ArrayList<>(mGlobalHibernationStates.values());
+                mGlobalLevelHibernationDiskStore.scheduleWriteHibernationStates(states);
             }
         }
     }
 
     /**
      * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
-     * The caller should hold {@link #mLock}
      *
      * @param pkgState package hibernation state
      */
-    private void hibernatePackageForUserL(@NonNull String packageName, int userId,
-            @NonNull UserPackageState pkgState) {
+    @GuardedBy("mLock")
+    private void hibernatePackageForUser(@NonNull String packageName, int userId,
+            @NonNull UserLevelState pkgState) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
         final long caller = Binder.clearCallingIdentity();
         try {
@@ -249,12 +300,13 @@
     }
 
     /**
-     * Remove a package from hibernation for a given user. The caller should hold {@link #mLock}.
+     * Remove a package from hibernation for a given user.
      *
      * @param pkgState package hibernation state
      */
-    private void unhibernatePackageForUserL(@NonNull String packageName, int userId,
-            UserPackageState pkgState) {
+    @GuardedBy("mLock")
+    private void unhibernatePackageForUser(@NonNull String packageName, int userId,
+            UserLevelState pkgState) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
         final long caller = Binder.clearCallingIdentity();
         try {
@@ -271,72 +323,167 @@
 
     /**
      * Put a package into global hibernation, optimizing its storage at a package / APK level.
-     * The caller should hold {@link #mLock}.
      */
-    private void hibernatePackageGloballyL(@NonNull String packageName) {
+    @GuardedBy("mLock")
+    private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
         // TODO(175830194): Delete vdex/odex when DexManager API is built out
-        mGloballyHibernatedPackages.add(packageName);
+        state.hibernated = true;
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     /**
-     * Unhibernate a package from global hibernation. The caller should hold {@link #mLock}.
+     * Unhibernate a package from global hibernation.
      */
-    private void unhibernatePackageGloballyL(@NonNull String packageName) {
+    @GuardedBy("mLock")
+    private void unhibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
-        mGloballyHibernatedPackages.remove(packageName);
+        state.hibernated = false;
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     /**
-     * Populates {@link #mUserStates} with the users installed packages. The caller should hold
-     * {@link #mLock}.
+     * Initializes in-memory store of user-level hibernation states for the given user
      *
      * @param userId user id to add installed packages for
+     * @param diskStates states pulled from disk, if available
      */
-    private void addUserPackageStatesL(int userId) {
-        Map<String, UserPackageState> packages = new ArrayMap<>();
-        List<PackageInfo> packageList;
+    @GuardedBy("mLock")
+    private void initializeUserHibernationStates(int userId,
+            @Nullable List<UserLevelState> diskStates) {
+        List<PackageInfo> packages;
         try {
-            packageList = mIPackageManager.getInstalledPackages(MATCH_ALL, userId).getList();
+            packages = mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId).getList();
         } catch (RemoteException e) {
-            throw new IllegalStateException("Package manager not available.", e);
+            throw new IllegalStateException("Package manager not available", e);
         }
 
-        for (int i = 0, size = packageList.size(); i < size; i++) {
-            packages.put(packageList.get(i).packageName, new UserPackageState());
+        Map<String, UserLevelState> userLevelStates = new ArrayMap<>();
+
+        for (int i = 0, size = packages.size(); i < size; i++) {
+            String packageName = packages.get(i).packageName;
+            UserLevelState state = new UserLevelState();
+            state.packageName = packageName;
+            userLevelStates.put(packageName, state);
         }
-        mUserStates.put(userId, packages);
+
+        if (diskStates != null) {
+            Set<String> installedPackages = new ArraySet<>();
+            for (int i = 0, size = packages.size(); i < size; i++) {
+                installedPackages.add(packages.get(i).packageName);
+            }
+            for (int i = 0, size = diskStates.size(); i < size; i++) {
+                String packageName = diskStates.get(i).packageName;
+                if (!installedPackages.contains(packageName)) {
+                    Slog.w(TAG, String.format(
+                            "No hibernation state associated with package %s user %d. Maybe"
+                                    + "the package was uninstalled? ", packageName, userId));
+                    continue;
+                }
+                userLevelStates.put(packageName, diskStates.get(i));
+            }
+        }
+        mUserStates.put(userId, userLevelStates);
     }
 
-    private void onUserAdded(int userId) {
-        synchronized (mLock) {
-            addUserPackageStatesL(userId);
+    /**
+     * Initialize in-memory store of global level hibernation states.
+     *
+     * @param diskStates global level hibernation states pulled from disk, if available
+     */
+    @GuardedBy("mLock")
+    private void initializeGlobalHibernationStates(@Nullable List<GlobalLevelState> diskStates) {
+        List<PackageInfo> packages;
+        try {
+            packages = mIPackageManager.getInstalledPackages(
+                    PACKAGE_MATCH_FLAGS | MATCH_ANY_USER, 0 /* userId */).getList();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package manager not available", e);
+        }
+
+        for (int i = 0, size = packages.size(); i < size; i++) {
+            String packageName = packages.get(i).packageName;
+            GlobalLevelState state = new GlobalLevelState();
+            state.packageName = packageName;
+            mGlobalHibernationStates.put(packageName, state);
+        }
+        if (diskStates != null) {
+            Set<String> installedPackages = new ArraySet<>();
+            for (int i = 0, size = packages.size(); i < size; i++) {
+                installedPackages.add(packages.get(i).packageName);
+            }
+            for (int i = 0, size = diskStates.size(); i < size; i++) {
+                GlobalLevelState state = diskStates.get(i);
+                if (!installedPackages.contains(state.packageName)) {
+                    Slog.w(TAG, String.format(
+                            "No hibernation state associated with package %s. Maybe the "
+                                    + "package was uninstalled? ", state.packageName));
+                    continue;
+                }
+                mGlobalHibernationStates.put(state.packageName, state);
+            }
         }
     }
 
-    private void onUserRemoved(int userId) {
+    @Override
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        int userId = user.getUserIdentifier();
+        HibernationStateDiskStore<UserLevelState> diskStore =
+                mInjector.getUserLevelDiskStore(userId);
+        mUserDiskStores.put(userId, diskStore);
+        List<UserLevelState> storedStates = diskStore.readHibernationStates();
         synchronized (mLock) {
+            initializeUserHibernationStates(userId, storedStates);
+        }
+    }
+
+    @Override
+    public void onUserStopping(@NonNull TargetUser user) {
+        int userId = user.getUserIdentifier();
+        // TODO: Flush any scheduled writes to disk immediately on user stopping / power off.
+        synchronized (mLock) {
+            mUserDiskStores.remove(userId);
             mUserStates.remove(userId);
         }
     }
 
     private void onPackageAdded(@NonNull String packageName, int userId) {
         synchronized (mLock) {
-            mUserStates.get(userId).put(packageName, new UserPackageState());
+            if (!mUserStates.contains(userId)) {
+                return;
+            }
+            UserLevelState userState = new UserLevelState();
+            userState.packageName = packageName;
+            mUserStates.get(userId).put(packageName, userState);
+            if (!mGlobalHibernationStates.containsKey(packageName)) {
+                GlobalLevelState globalState = new GlobalLevelState();
+                globalState.packageName = packageName;
+                mGlobalHibernationStates.put(packageName, globalState);
+            }
         }
     }
 
     private void onPackageRemoved(@NonNull String packageName, int userId) {
         synchronized (mLock) {
+            if (!mUserStates.contains(userId)) {
+                return;
+            }
             mUserStates.get(userId).remove(packageName);
         }
     }
 
     private void onPackageRemovedForAllUsers(@NonNull String packageName) {
         synchronized (mLock) {
-            mGloballyHibernatedPackages.remove(packageName);
+            mGlobalHibernationStates.remove(packageName);
+        }
+    }
+
+    private void onDeviceConfigChanged(Properties properties) {
+        for (String key : properties.getKeyset()) {
+            if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) {
+                mIsServiceEnabled = isAppHibernationEnabled();
+                break;
+            }
         }
     }
 
@@ -357,6 +504,13 @@
         }
     }
 
+    private boolean checkHibernationEnabled(String methodName) {
+        if (!mIsServiceEnabled) {
+            Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
+        }
+        return mIsServiceEnabled;
+    }
+
     private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
 
     static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
@@ -395,7 +549,7 @@
         }
     }
 
-    // Broadcast receiver for user and package add/removal events
+    // Broadcast receiver for package add/removal events
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -405,12 +559,6 @@
             }
 
             final String action = intent.getAction();
-            if (ACTION_USER_ADDED.equals(action)) {
-                onUserAdded(userId);
-            }
-            if (ACTION_USER_REMOVED.equals(action)) {
-                onUserRemoved(userId);
-            }
             if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) {
                 final String packageName = intent.getData().getSchemeSpecificPart();
                 if (intent.getBooleanExtra(EXTRA_REPLACING, false)) {
@@ -438,15 +586,71 @@
     public static boolean isAppHibernationEnabled() {
         return DeviceConfig.getBoolean(
                 NAMESPACE_APP_HIBERNATION,
-                AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED,
+                KEY_APP_HIBERNATION_ENABLED,
                 false /* defaultValue */);
     }
 
     /**
-     * Data class that contains hibernation state info of a package for a user.
+     * Dependency injector for {@link #AppHibernationService)}.
      */
-    private static final class UserPackageState {
-        public boolean hibernated;
-        // TODO: Track whether hibernation is exempted by the user
+    interface Injector {
+        Context getContext();
+
+        IPackageManager getPackageManager();
+
+        IActivityManager getActivityManager();
+
+        UserManager getUserManager();
+
+        HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();
+
+        HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
+    }
+
+    private static final class InjectorImpl implements Injector {
+        private static final String HIBERNATION_DIR_NAME = "hibernation";
+        private final Context mContext;
+        private final ScheduledExecutorService mScheduledExecutorService;
+        private final UserLevelHibernationProto mUserLevelHibernationProto;
+
+        InjectorImpl(Context context) {
+            mContext = context;
+            mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+            mUserLevelHibernationProto = new UserLevelHibernationProto();
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        public IPackageManager getPackageManager() {
+            return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+        }
+
+        @Override
+        public IActivityManager getActivityManager() {
+            return ActivityManager.getService();
+        }
+
+        @Override
+        public UserManager getUserManager() {
+            return mContext.getSystemService(UserManager.class);
+        }
+
+        @Override
+        public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
+            File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME);
+            return new HibernationStateDiskStore<>(
+                    dir, new GlobalLevelHibernationProto(), mScheduledExecutorService);
+        }
+
+        @Override
+        public HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId) {
+            File dir = new File(Environment.getDataSystemCeDirectory(userId), HIBERNATION_DIR_NAME);
+            return new HibernationStateDiskStore<>(
+                    dir, mUserLevelHibernationProto, mScheduledExecutorService);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
new file mode 100644
index 0000000..79e995b
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.android.server.apphibernation;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads and writes protos for {@link GlobalLevelState} hiberation states.
+ */
+final class GlobalLevelHibernationProto implements ProtoReadWriter<List<GlobalLevelState>> {
+    private static final String TAG = "GlobalLevelHibernationProtoReadWriter";
+
+    @Override
+    public void writeToProto(@NonNull ProtoOutputStream stream,
+            @NonNull List<GlobalLevelState> data) {
+        for (int i = 0, size = data.size(); i < size; i++) {
+            long token = stream.start(GlobalLevelHibernationStatesProto.HIBERNATION_STATE);
+            GlobalLevelState state = data.get(i);
+            stream.write(GlobalLevelHibernationStateProto.PACKAGE_NAME, state.packageName);
+            stream.write(GlobalLevelHibernationStateProto.HIBERNATED, state.hibernated);
+            stream.end(token);
+        }
+    }
+
+    @Override
+    public @Nullable List<GlobalLevelState> readFromProto(@NonNull ProtoInputStream stream)
+            throws IOException {
+        List<GlobalLevelState> list = new ArrayList<>();
+        while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (stream.getFieldNumber()
+                    != (int) GlobalLevelHibernationStatesProto.HIBERNATION_STATE) {
+                continue;
+            }
+            GlobalLevelState state = new GlobalLevelState();
+            long token = stream.start(GlobalLevelHibernationStatesProto.HIBERNATION_STATE);
+            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (stream.getFieldNumber()) {
+                    case (int) GlobalLevelHibernationStateProto.PACKAGE_NAME:
+                        state.packageName =
+                                stream.readString(GlobalLevelHibernationStateProto.PACKAGE_NAME);
+                        break;
+                    case (int) GlobalLevelHibernationStateProto.HIBERNATED:
+                        state.hibernated =
+                                stream.readBoolean(GlobalLevelHibernationStateProto.HIBERNATED);
+                        break;
+                    default:
+                        Slog.w(TAG, "Undefined field in proto: " + stream.getFieldNumber());
+                }
+            }
+            stream.end(token);
+            list.add(state);
+        }
+        return list;
+    }
+}
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
similarity index 67%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to services/core/java/com/android/server/apphibernation/GlobalLevelState.java
index 46bc4ab..4f75675 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package com.android.server.apphibernation;
 
-parcelable ApnThrottleStatus;
+/**
+ * Data class that contains global hibernation state for a package.
+ */
+final class GlobalLevelState {
+    public String packageName;
+    public boolean hibernated;
+}
diff --git a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
new file mode 100644
index 0000000..c83659d
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
@@ -0,0 +1,162 @@
+/*
+ * 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 com.android.server.apphibernation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.text.format.DateUtils;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Disk store utility class for hibernation states.
+ *
+ * @param <T> the type of hibernation state data
+ */
+class HibernationStateDiskStore<T> {
+    private static final String TAG = "HibernationStateDiskStore";
+
+    // Time to wait before actually writing. Saves extra writes if data changes come in batches.
+    private static final long DISK_WRITE_DELAY = 1L * DateUtils.MINUTE_IN_MILLIS;
+    private static final String STATES_FILE_NAME = "states";
+
+    private final File mHibernationFile;
+    private final ScheduledExecutorService mExecutorService;
+    private final ProtoReadWriter<List<T>> mProtoReadWriter;
+    private List<T> mScheduledStatesToWrite = new ArrayList<>();
+    private ScheduledFuture<?> mFuture;
+
+    /**
+     * Initialize a disk store for hibernation states in the given directory.
+     *
+     * @param hibernationDir directory to write/read states file
+     * @param readWriter writer/reader of states proto
+     * @param executorService scheduled executor for writing data
+     */
+    HibernationStateDiskStore(@NonNull File hibernationDir,
+            @NonNull ProtoReadWriter<List<T>> readWriter,
+            @NonNull ScheduledExecutorService executorService) {
+        this(hibernationDir, readWriter, executorService, STATES_FILE_NAME);
+    }
+
+    @VisibleForTesting
+    HibernationStateDiskStore(@NonNull File hibernationDir,
+            @NonNull ProtoReadWriter<List<T>> readWriter,
+            @NonNull ScheduledExecutorService executorService,
+            @NonNull String fileName) {
+        mHibernationFile = new File(hibernationDir, fileName);
+        mExecutorService = executorService;
+        mProtoReadWriter = readWriter;
+    }
+
+    /**
+     * Schedule a full write of all the hibernation states to the file on disk. Does not run
+     * immediately and subsequent writes override previous ones.
+     *
+     * @param hibernationStates list of hibernation states to write to disk
+     */
+    void scheduleWriteHibernationStates(@NonNull List<T> hibernationStates) {
+        synchronized (this) {
+            mScheduledStatesToWrite = hibernationStates;
+            if (mExecutorService.isShutdown()) {
+                Slog.e(TAG, "Scheduled executor service is shut down.");
+                return;
+            }
+
+            // Already have write scheduled
+            if (mFuture != null) {
+                Slog.i(TAG, "Write already scheduled. Skipping schedule.");
+                return;
+            }
+
+            mFuture = mExecutorService.schedule(this::writeHibernationStates, DISK_WRITE_DELAY,
+                    TimeUnit.MILLISECONDS);
+        }
+    }
+
+    /**
+     * Read hibernation states from disk.
+     *
+     * @return the parsed list of hibernation states, null if file does not exist
+     */
+    @Nullable
+    List<T> readHibernationStates() {
+        synchronized (this) {
+            if (!mHibernationFile.exists()) {
+                Slog.i(TAG, "No hibernation file on disk for file " + mHibernationFile.getPath());
+                return null;
+            }
+            AtomicFile atomicFile = new AtomicFile(mHibernationFile);
+
+            try {
+                FileInputStream inputStream = atomicFile.openRead();
+                ProtoInputStream protoInputStream = new ProtoInputStream(inputStream);
+                return mProtoReadWriter.readFromProto(protoInputStream);
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to read states protobuf.", e);
+                return null;
+            }
+        }
+    }
+
+    @WorkerThread
+    private void writeHibernationStates() {
+        synchronized (this) {
+            writeStateProto(mScheduledStatesToWrite);
+            mScheduledStatesToWrite.clear();
+            mFuture = null;
+        }
+    }
+
+    @WorkerThread
+    private void writeStateProto(List<T> states) {
+        AtomicFile atomicFile = new AtomicFile(mHibernationFile);
+
+        FileOutputStream fileOutputStream;
+        try {
+            fileOutputStream = atomicFile.startWrite();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to start write to states protobuf.", e);
+            return;
+        }
+
+        try {
+            ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
+            mProtoReadWriter.writeToProto(protoOutputStream, states);
+            protoOutputStream.flush();
+            atomicFile.finishWrite(fileOutputStream);
+        } catch (Exception e) {
+            Slog.e(TAG, "Failed to finish write to states protobuf.", e);
+            atomicFile.failWrite(fileOutputStream);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/apphibernation/ProtoReadWriter.java b/services/core/java/com/android/server/apphibernation/ProtoReadWriter.java
new file mode 100644
index 0000000..0cbc09a
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/ProtoReadWriter.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.android.server.apphibernation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.IOException;
+
+/**
+ * Proto utility that reads and writes proto for some data.
+ *
+ * @param <T> data that can be written and read from a proto
+ */
+interface ProtoReadWriter<T> {
+
+    /**
+     * Write data to a proto stream
+     */
+    void writeToProto(@NonNull ProtoOutputStream stream, @NonNull T data);
+
+    /**
+     * Parse data from the proto stream and return
+     */
+    @Nullable T readFromProto(@NonNull ProtoInputStream stream) throws IOException;
+}
diff --git a/services/core/java/com/android/server/apphibernation/UserLevelHibernationProto.java b/services/core/java/com/android/server/apphibernation/UserLevelHibernationProto.java
new file mode 100644
index 0000000..a24c4c5
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/UserLevelHibernationProto.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.android.server.apphibernation;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads and writes protos for {@link UserLevelState} hiberation states.
+ */
+final class UserLevelHibernationProto implements ProtoReadWriter<List<UserLevelState>> {
+    private static final String TAG = "UserLevelHibernationProtoReadWriter";
+
+    @Override
+    public void writeToProto(@NonNull ProtoOutputStream stream,
+            @NonNull List<UserLevelState> data) {
+        for (int i = 0, size = data.size(); i < size; i++) {
+            long token = stream.start(UserLevelHibernationStatesProto.HIBERNATION_STATE);
+            UserLevelState state = data.get(i);
+            stream.write(UserLevelHibernationStateProto.PACKAGE_NAME, state.packageName);
+            stream.write(UserLevelHibernationStateProto.HIBERNATED, state.hibernated);
+            stream.end(token);
+        }
+    }
+
+    @Override
+    public @Nullable List<UserLevelState> readFromProto(@NonNull ProtoInputStream stream)
+            throws IOException {
+        List<UserLevelState> list = new ArrayList<>();
+        while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (stream.getFieldNumber()
+                    != (int) UserLevelHibernationStatesProto.HIBERNATION_STATE) {
+                continue;
+            }
+            UserLevelState state = new UserLevelState();
+            long token = stream.start(UserLevelHibernationStatesProto.HIBERNATION_STATE);
+            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (stream.getFieldNumber()) {
+                    case (int) UserLevelHibernationStateProto.PACKAGE_NAME:
+                        state.packageName =
+                                stream.readString(UserLevelHibernationStateProto.PACKAGE_NAME);
+                        break;
+                    case (int) UserLevelHibernationStateProto.HIBERNATED:
+                        state.hibernated =
+                                stream.readBoolean(UserLevelHibernationStateProto.HIBERNATED);
+                        break;
+                    default:
+                        Slog.w(TAG, "Undefined field in proto: " + stream.getFieldNumber());
+                }
+            }
+            stream.end(token);
+            list.add(state);
+        }
+        return list;
+    }
+}
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/services/core/java/com/android/server/apphibernation/UserLevelState.java
similarity index 66%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to services/core/java/com/android/server/apphibernation/UserLevelState.java
index 46bc4ab..c66dad8 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package com.android.server.apphibernation;
 
-parcelable ApnThrottleStatus;
+/**
+ * Data class that contains hibernation state info of a package for a user.
+ */
+final class UserLevelState {
+    public String packageName;
+    public boolean hibernated;
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4c69704..5a8396f 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8129,6 +8129,7 @@
         public void postDisplaySafeVolumeWarning(int flags) {
             if (mController == null)
                 return;
+            flags = flags | AudioManager.FLAG_SHOW_UI;
             try {
                 mController.displaySafeVolumeWarning(flags);
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index e3757df..df83df9 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -16,15 +16,24 @@
 
 package com.android.server.compat;
 
+import static android.app.compat.PackageOverride.VALUE_DISABLED;
+import static android.app.compat.PackageOverride.VALUE_ENABLED;
+import static android.app.compat.PackageOverride.VALUE_UNDEFINED;
+
 import android.annotation.Nullable;
+import android.app.compat.PackageOverride;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 
 import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.OverrideAllowedState;
 import com.android.server.compat.config.Change;
 import com.android.server.compat.overrides.ChangeOverrides;
 import com.android.server.compat.overrides.OverrideValue;
+import com.android.server.compat.overrides.RawOverrideValue;
 
 import java.util.HashMap;
 import java.util.List;
@@ -36,7 +45,7 @@
  * <p>A compatibility change has a default setting, determined by the {@code enableAfterTargetSdk}
  * and {@code disabled} constructor parameters. If a change is {@code disabled}, this overrides any
  * target SDK criteria set. These settings can be overridden for a specific package using
- * {@link #addPackageOverride(String, boolean)}.
+ * {@link #addPackageOverrideInternal(String, boolean)}.
  *
  * <p>Note, this class is not thread safe so callers must ensure thread safety.
  */
@@ -63,8 +72,8 @@
 
     ChangeListener mListener = null;
 
-    private Map<String, Boolean> mPackageOverrides;
-    private Map<String, Boolean> mDeferredOverrides;
+    private Map<String, Boolean> mEvaluatedOverrides;
+    private Map<String, PackageOverride> mRawOverrides;
 
     public CompatChange(long changeId) {
         this(changeId, null, -1, -1, false, false, null, false);
@@ -113,18 +122,26 @@
      * @param pname Package name to enable the change for.
      * @param enabled Whether or not to enable the change.
      */
-    void addPackageOverride(String pname, boolean enabled) {
+    private void addPackageOverrideInternal(String pname, boolean enabled) {
         if (getLoggingOnly()) {
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mPackageOverrides == null) {
-            mPackageOverrides = new HashMap<>();
+        if (mEvaluatedOverrides == null) {
+            mEvaluatedOverrides = new HashMap<>();
         }
-        mPackageOverrides.put(pname, enabled);
+        mEvaluatedOverrides.put(pname, enabled);
         notifyListener(pname);
     }
 
+    private void removePackageOverrideInternal(String pname) {
+        if (mEvaluatedOverrides != null) {
+            if (mEvaluatedOverrides.remove(pname) != null) {
+                notifyListener(pname);
+            }
+        }
+    }
+
     /**
      * Tentatively set the state of this change for a given package name.
      * The override will only take effect after that package is installed, if applicable.
@@ -132,17 +149,19 @@
      * <p>Note, this method is not thread safe so callers must ensure thread safety.
      *
      * @param packageName Package name to tentatively enable the change for.
-     * @param enabled Whether or not to enable the change.
+     * @param override The package override to be set
      */
-    void addPackageDeferredOverride(String packageName, boolean enabled) {
+    void addPackageOverride(String packageName, PackageOverride override,
+            OverrideAllowedState allowedState, Context context) {
         if (getLoggingOnly()) {
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mDeferredOverrides == null) {
-            mDeferredOverrides = new HashMap<>();
+        if (mRawOverrides == null) {
+            mRawOverrides = new HashMap<>();
         }
-        mDeferredOverrides.put(packageName, enabled);
+        mRawOverrides.put(packageName, override);
+        recheckOverride(packageName, allowedState, context);
     }
 
     /**
@@ -157,24 +176,44 @@
      * @return {@code true} if the recheck yielded a result that requires invalidating caches
      *         (a deferred override was consolidated or a regular override was removed).
      */
-    boolean recheckOverride(String packageName, boolean allowed) {
-        // A deferred override now is allowed by the policy, so promote it to a regular override.
-        if (hasDeferredOverride(packageName) && allowed) {
-            boolean overrideValue = mDeferredOverrides.remove(packageName);
-            addPackageOverride(packageName, overrideValue);
-            return true;
+    boolean recheckOverride(String packageName, OverrideAllowedState allowedState,
+            Context context) {
+        boolean allowed = (allowedState.state == OverrideAllowedState.ALLOWED);
+
+        Long version = null;
+        try {
+            ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(
+                    packageName, 0);
+            version = applicationInfo.longVersionCode;
+        } catch (PackageManager.NameNotFoundException e) {
+            // Do nothing
         }
-        // A previously set override is no longer allowed by the policy, so make it deferred.
-        if (hasOverride(packageName) && !allowed) {
-            boolean overrideValue = mPackageOverrides.remove(packageName);
-            addPackageDeferredOverride(packageName, overrideValue);
-            // Notify because the override was removed.
-            notifyListener(packageName);
-            return true;
+
+        // If the app is not installed or no longer has raw overrides, evaluate to false
+        if (version == null || !hasRawOverride(packageName) || !allowed) {
+            removePackageOverrideInternal(packageName);
+            return false;
         }
-        return false;
+
+        // Evaluate the override based on its version
+        int overrideValue = mRawOverrides.get(packageName).evaluate(version);
+        switch (overrideValue) {
+            case VALUE_UNDEFINED:
+                removePackageOverrideInternal(packageName);
+                break;
+            case VALUE_ENABLED:
+                addPackageOverrideInternal(packageName, true);
+                break;
+            case VALUE_DISABLED:
+                addPackageOverrideInternal(packageName, false);
+                break;
+        }
+        return true;
     }
 
+    boolean hasPackageOverride(String pname) {
+        return mRawOverrides != null && mRawOverrides.containsKey(pname);
+    }
     /**
      * Remove any package override for the given package name, restoring the default behaviour.
      *
@@ -182,15 +221,13 @@
      *
      * @param pname Package name to reset to defaults for.
      */
-    void removePackageOverride(String pname) {
-        if (mPackageOverrides != null) {
-            if (mPackageOverrides.remove(pname) != null) {
-                notifyListener(pname);
-            }
+    boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
+            Context context) {
+        if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
+            recheckOverride(pname, allowedState, context);
+            return true;
         }
-        if (mDeferredOverrides != null) {
-            mDeferredOverrides.remove(pname);
-        }
+        return false;
     }
 
     /**
@@ -204,8 +241,8 @@
         if (app == null) {
             return defaultValue();
         }
-        if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
-            return mPackageOverrides.get(app.packageName);
+        if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
+            return mEvaluatedOverrides.get(app.packageName);
         }
         if (getDisabled()) {
             return false;
@@ -223,8 +260,16 @@
      * @return {@code true} if the change should be enabled for the package.
      */
     boolean willBeEnabled(String packageName) {
-        if (hasDeferredOverride(packageName)) {
-            return mDeferredOverrides.get(packageName);
+        if (hasRawOverride(packageName)) {
+            int eval = mRawOverrides.get(packageName).evaluateForAllVersions();
+            switch (eval) {
+                case VALUE_ENABLED:
+                    return true;
+                case VALUE_DISABLED:
+                    return false;
+                case VALUE_UNDEFINED:
+                    return defaultValue();
+            }
         }
         return defaultValue();
     }
@@ -243,8 +288,8 @@
      * @param packageName name of the package
      * @return true if there is such override
      */
-    boolean hasOverride(String packageName) {
-        return mPackageOverrides != null && mPackageOverrides.containsKey(packageName);
+    private boolean hasOverride(String packageName) {
+        return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
     }
 
     /**
@@ -252,65 +297,77 @@
      * @param packageName name of the package
      * @return true if there is such a deferred override
      */
-    boolean hasDeferredOverride(String packageName) {
-        return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
-    }
-
-    /**
-     * Checks whether a change has any package overrides.
-     * @return true if the change has at least one deferred override
-     */
-    boolean hasAnyPackageOverride() {
-        return mDeferredOverrides != null && !mDeferredOverrides.isEmpty();
-    }
-
-    /**
-     * Checks whether a change has any deferred overrides.
-     * @return true if the change has at least one deferred override
-     */
-    boolean hasAnyDeferredOverride() {
-        return mPackageOverrides != null && !mPackageOverrides.isEmpty();
+    private boolean hasRawOverride(String packageName) {
+        return mRawOverrides != null && mRawOverrides.containsKey(packageName);
     }
 
     void loadOverrides(ChangeOverrides changeOverrides) {
-        if (mDeferredOverrides == null) {
-            mDeferredOverrides = new HashMap<>();
+        if (mRawOverrides == null) {
+            mRawOverrides = new HashMap<>();
         }
-        mDeferredOverrides.clear();
-        for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
-            mDeferredOverrides.put(override.getPackageName(), override.getEnabled());
+        mRawOverrides.clear();
+
+        if (mEvaluatedOverrides == null) {
+            mEvaluatedOverrides = new HashMap<>();
+        }
+        mEvaluatedOverrides.clear();
+
+        // Load deferred overrides for backwards compatibility
+        if (changeOverrides.getDeferred() != null) {
+            for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
+                mRawOverrides.put(override.getPackageName(),
+                        new PackageOverride.Builder().setEnabled(
+                                override.getEnabled()).build());
+            }
         }
 
-        if (mPackageOverrides == null) {
-            mPackageOverrides = new HashMap<>();
+        // Load validated overrides. For backwards compatibility, we also add them to raw overrides.
+        if (changeOverrides.getValidated() != null) {
+            for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
+                mEvaluatedOverrides.put(override.getPackageName(), override.getEnabled());
+                mRawOverrides.put(override.getPackageName(),
+                        new PackageOverride.Builder().setEnabled(
+                                override.getEnabled()).build());
+            }
         }
-        mPackageOverrides.clear();
-        for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
-            mPackageOverrides.put(override.getPackageName(), override.getEnabled());
+
+        // Load raw overrides
+        if (changeOverrides.getRaw() != null) {
+            for (RawOverrideValue override : changeOverrides.getRaw().getRawOverrideValue()) {
+                PackageOverride packageOverride = new PackageOverride.Builder()
+                        .setMinVersionCode(override.getMinVersionCode())
+                        .setMaxVersionCode(override.getMaxVersionCode())
+                        .setEnabled(override.getEnabled())
+                        .build();
+                mRawOverrides.put(override.getPackageName(), packageOverride);
+            }
         }
     }
 
     ChangeOverrides saveOverrides() {
-        if (!hasAnyDeferredOverride() && !hasAnyPackageOverride()) {
+        if (mRawOverrides == null || mRawOverrides.isEmpty()) {
             return null;
         }
         ChangeOverrides changeOverrides = new ChangeOverrides();
         changeOverrides.setChangeId(getId());
-        ChangeOverrides.Deferred deferredOverrides = new ChangeOverrides.Deferred();
-        List<OverrideValue> deferredList = deferredOverrides.getOverrideValue();
-        if (mDeferredOverrides != null) {
-            for (Map.Entry<String, Boolean> entry : mDeferredOverrides.entrySet()) {
-                OverrideValue override = new OverrideValue();
+        ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
+        List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
+        if (mRawOverrides != null) {
+            for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
+                RawOverrideValue override = new RawOverrideValue();
                 override.setPackageName(entry.getKey());
-                override.setEnabled(entry.getValue());
-                deferredList.add(override);
+                override.setMinVersionCode(entry.getValue().getMinVersionCode());
+                override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
+                override.setEnabled(entry.getValue().getEnabled());
+                rawList.add(override);
             }
         }
-        changeOverrides.setDeferred(deferredOverrides);
+        changeOverrides.setRaw(rawOverrides);
+
         ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
         List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
-        if (mPackageOverrides != null) {
-            for (Map.Entry<String, Boolean> entry : mPackageOverrides.entrySet()) {
+        if (mEvaluatedOverrides != null) {
+            for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
                 OverrideValue override = new OverrideValue();
                 override.setPackageName(entry.getKey());
                 override.setEnabled(entry.getValue());
@@ -337,11 +394,11 @@
         if (getLoggingOnly()) {
             sb.append("; loggingOnly");
         }
-        if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
-            sb.append("; packageOverrides=").append(mPackageOverrides);
+        if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
+            sb.append("; packageOverrides=").append(mEvaluatedOverrides);
         }
-        if (mDeferredOverrides != null && mDeferredOverrides.size() > 0) {
-            sb.append("; deferredOverrides=").append(mDeferredOverrides);
+        if (mRawOverrides != null && mRawOverrides.size() > 0) {
+            sb.append("; rawOverrides=").append(mRawOverrides);
         }
         if (getOverridable()) {
             sb.append("; overridable");
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 6b77b9d..422991e 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,6 +17,7 @@
 package com.android.server.compat;
 
 import android.app.compat.ChangeIdStateCache;
+import android.app.compat.PackageOverride;
 import android.compat.Compatibility.ChangeConfig;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -31,6 +32,7 @@
 import com.android.internal.compat.AndroidBuildClassifier;
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.CompatibilityOverrideConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.OverrideAllowedState;
 import com.android.server.compat.config.Change;
@@ -70,11 +72,13 @@
     private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
 
     private final OverrideValidatorImpl mOverrideValidator;
+    private Context mContext;
     private File mOverridesFile;
 
     @VisibleForTesting
     CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
         mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
+        mContext = context;
     }
 
     static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
@@ -210,17 +214,33 @@
      * @throws IllegalStateException if overriding is not allowed
      */
     boolean addOverride(long changeId, String packageName, boolean enabled) {
-        boolean alreadyKnown = addOverrideUnsafe(changeId, packageName, enabled);
+        boolean alreadyKnown = addOverrideUnsafe(changeId, packageName,
+                new PackageOverride.Builder().setEnabled(enabled).build());
         saveOverrides();
         invalidateCache();
         return alreadyKnown;
     }
 
     /**
-     * Unsafe version of {@link #addOverride(long, String, boolean)}.
-     * It does not invalidate the cache nor save the overrides.
+     * Overrides the enabled state for a given change and app.
+     *
+     * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+     *
+     * @param overrides   list of overrides to default changes config.
+     * @param packageName app for which the overrides will be applied.
      */
-    private boolean addOverrideUnsafe(long changeId, String packageName, boolean enabled) {
+    void addOverrides(CompatibilityOverrideConfig overrides, String packageName) {
+        synchronized (mChanges) {
+            for (Long changeId : overrides.overrides.keySet()) {
+                addOverrideUnsafe(changeId, packageName, overrides.overrides.get(changeId));
+            }
+            saveOverrides();
+            invalidateCache();
+        }
+    }
+
+    private boolean addOverrideUnsafe(long changeId, String packageName,
+            PackageOverride overrides) {
         boolean alreadyKnown = true;
         OverrideAllowedState allowedState =
                 mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -232,17 +252,8 @@
                 c = new CompatChange(changeId);
                 addChange(c);
             }
-            switch (allowedState.state) {
-                case OverrideAllowedState.ALLOWED:
-                    c.addPackageOverride(packageName, enabled);
-                    break;
-                case OverrideAllowedState.DEFERRED_VERIFICATION:
-                    c.addPackageDeferredOverride(packageName, enabled);
-                    break;
-                default:
-                    throw new IllegalStateException("Should only be able to override changes that "
-                            + "are allowed or can be deferred.");
-            }
+            c.addPackageOverride(packageName, overrides, allowedState, mContext);
+            invalidateCache();
         }
         return alreadyKnown;
     }
@@ -311,47 +322,20 @@
      * It does not invalidate the cache nor save the overrides.
      */
     private boolean removeOverrideUnsafe(long changeId, String packageName) {
-        boolean overrideExists = false;
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
             if (c != null) {
-                // Always allow removing a deferred override.
-                if (c.hasDeferredOverride(packageName)) {
-                    c.removePackageOverride(packageName);
-                    overrideExists = true;
-                } else if (c.hasOverride(packageName)) {
-                    // Regular overrides need to pass the policy.
-                    overrideExists = true;
-                    OverrideAllowedState allowedState =
-                            mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+                OverrideAllowedState allowedState =
+                        mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+                if (c.hasPackageOverride(packageName)) {
                     allowedState.enforce(changeId, packageName);
-                    c.removePackageOverride(packageName);
+                    c.removePackageOverride(packageName, allowedState, mContext);
+                    invalidateCache();
+                    return true;
                 }
             }
         }
-        return overrideExists;
-    }
-
-    /**
-     * Overrides the enabled state for a given change and app.
-     *
-     * <p>Note: package overrides are not persistent and will be lost on system or runtime restart.
-     *
-     * @param overrides   list of overrides to default changes config
-     * @param packageName app for which the overrides will be applied
-     */
-    void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
-        synchronized (mChanges) {
-            for (Long changeId : overrides.enabledChanges()) {
-                addOverrideUnsafe(changeId, packageName, true);
-            }
-            for (Long changeId : overrides.disabledChanges()) {
-                addOverrideUnsafe(changeId, packageName, false);
-
-            }
-            saveOverrides();
-            invalidateCache();
-        }
+        return false;
     }
 
     /**
@@ -402,7 +386,8 @@
     int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
         long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
         for (long changeId : changes) {
-            addOverrideUnsafe(changeId, packageName, true);
+            addOverrideUnsafe(changeId, packageName,
+                    new PackageOverride.Builder().setEnabled(true).build());
         }
         saveOverrides();
         invalidateCache();
@@ -418,7 +403,8 @@
     int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
         long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
         for (long changeId : changes) {
-            addOverrideUnsafe(changeId, packageName, false);
+            addOverrideUnsafe(changeId, packageName,
+                    new PackageOverride.Builder().setEnabled(false).build());
         }
         saveOverrides();
         invalidateCache();
@@ -615,8 +601,7 @@
                 CompatChange c = mChanges.valueAt(idx);
                 OverrideAllowedState allowedState =
                         mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
-                boolean allowedOverride = (allowedState.state == OverrideAllowedState.ALLOWED);
-                shouldInvalidateCache |= c.recheckOverride(packageName, allowedOverride);
+                shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
             }
             if (shouldInvalidateCache) {
                 invalidateCache();
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6b2a1c9..edfc8b8 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -25,6 +25,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.app.compat.PackageOverride;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +44,7 @@
 import com.android.internal.compat.ChangeReporter;
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.CompatibilityOverrideConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.util.DumpUtils;
@@ -51,6 +53,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * System server internal API for gating and reporting compatibility changes.
@@ -161,6 +165,22 @@
     @Override
     public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
         checkCompatChangeOverridePermission();
+        Map<Long, PackageOverride> overridesMap = new HashMap<>();
+        for (long change : overrides.enabledChanges()) {
+            overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
+        }
+        for (long change : overrides.disabledChanges()) {
+            overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
+                    .build());
+        }
+        mCompatConfig.addOverrides(new CompatibilityOverrideConfig(overridesMap), packageName);
+        killPackage(packageName);
+    }
+
+    @Override
+    public void setOverridesFromInstaller(CompatibilityOverrideConfig overrides,
+            String packageName) {
+        checkCompatChangeOverridePermission();
         mCompatConfig.addOverrides(overrides, packageName);
         killPackage(packageName);
     }
@@ -168,7 +188,15 @@
     @Override
     public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
         checkCompatChangeOverridePermission();
-        mCompatConfig.addOverrides(overrides, packageName);
+        Map<Long, PackageOverride> overridesMap = new HashMap<>();
+        for (long change : overrides.enabledChanges()) {
+            overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
+        }
+        for (long change : overrides.disabledChanges()) {
+            overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
+                    .build());
+        }
+        mCompatConfig.addOverrides(new CompatibilityOverrideConfig(overridesMap), packageName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index c70bb08..43d9ade 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.IDnsResolver;
+import android.net.InetAddresses;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.ResolverOptionsParcel;
@@ -190,7 +191,7 @@
             for (String ipAddress : ipAddresses) {
                 try {
                     latestDnses.add(new Pair(hostname,
-                            InetAddress.parseNumericAddress(ipAddress)));
+                            InetAddresses.parseNumericAddress(ipAddress)));
                 } catch (IllegalArgumentException e) {}
             }
             // Remove <hostname, ipAddress> pairs that should not be tracked.
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 397af7b..61b11a5 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -16,7 +16,6 @@
 
 package com.android.server.connectivity;
 
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -25,15 +24,14 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
 
-import android.net.ConnectivityManager;
 import android.net.ConnectivityMetricsEvent;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.ApfStats;
+import android.net.metrics.ConnectStats;
 import android.net.metrics.DefaultNetworkEvent;
 import android.net.metrics.DhcpClientEvent;
 import android.net.metrics.DhcpErrorEvent;
 import android.net.metrics.DnsEvent;
-import android.net.metrics.ConnectStats;
 import android.net.metrics.IpManagerEvent;
 import android.net.metrics.IpReachabilityEvent;
 import android.net.metrics.NetworkEvent;
@@ -41,12 +39,13 @@
 import android.net.metrics.ValidationProbeEvent;
 import android.net.metrics.WakeupStats;
 import android.os.Parcelable;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
+
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -361,29 +360,22 @@
                 return IpConnectivityLogClass.UNKNOWN;
             case 1:
                 int t = Long.numberOfTrailingZeros(transports);
-                return transportToLinkLayer(t);
+                return TRANSPORT_LINKLAYER_MAP.get(t, IpConnectivityLogClass.UNKNOWN);
             default:
                 return IpConnectivityLogClass.MULTIPLE;
         }
     }
 
-    private static int transportToLinkLayer(int transport) {
-        if (0 <= transport && transport < TRANSPORT_LINKLAYER_MAP.length) {
-            return TRANSPORT_LINKLAYER_MAP[transport];
-        }
-        return IpConnectivityLogClass.UNKNOWN;
-    }
-
-    private static final int[] TRANSPORT_LINKLAYER_MAP = new int[MAX_TRANSPORT + 1];
+    private static final SparseIntArray TRANSPORT_LINKLAYER_MAP = new SparseIntArray();
     static {
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_CELLULAR]   = IpConnectivityLogClass.CELLULAR;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI]       = IpConnectivityLogClass.WIFI;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_BLUETOOTH]  = IpConnectivityLogClass.BLUETOOTH;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_ETHERNET]   = IpConnectivityLogClass.ETHERNET;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_VPN]        = IpConnectivityLogClass.UNKNOWN;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI_AWARE] = IpConnectivityLogClass.WIFI_NAN;
-        TRANSPORT_LINKLAYER_MAP[TRANSPORT_LOWPAN]     = IpConnectivityLogClass.LOWPAN;
-    };
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_CELLULAR, IpConnectivityLogClass.CELLULAR);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_WIFI, IpConnectivityLogClass.WIFI);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_BLUETOOTH, IpConnectivityLogClass.BLUETOOTH);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_ETHERNET, IpConnectivityLogClass.ETHERNET);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_VPN, IpConnectivityLogClass.UNKNOWN);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_WIFI_AWARE, IpConnectivityLogClass.WIFI_NAN);
+        TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_LOWPAN, IpConnectivityLogClass.LOWPAN);
+    }
 
     private static int ifnameToLinkLayer(String ifname) {
         // Do not try to catch all interface names with regexes, instead only catch patterns that
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 952193b..641287f 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity;
 
+import static com.android.net.module.util.CollectionUtils.contains;
+
 import android.annotation.NonNull;
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
@@ -33,10 +35,9 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.NetworkStackConstants;
 import com.android.server.net.BaseNetworkObserver;
 
-import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.util.Objects;
 
@@ -117,8 +118,8 @@
     @VisibleForTesting
     protected static boolean requiresClat(NetworkAgentInfo nai) {
         // TODO: migrate to NetworkCapabilities.TRANSPORT_*.
-        final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
-        final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
+        final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType());
+        final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState());
 
         // Only run clat on networks that have a global IPv6 address and don't have a native IPv4
         // address.
@@ -433,7 +434,7 @@
         // clat IPv4 address itself (for those apps, it doesn't matter what
         // the IP of the gateway is, only that there is one).
         RouteInfo ipv4Default = new RouteInfo(
-                new LinkAddress(Inet4Address.ANY, 0),
+                new LinkAddress(NetworkStackConstants.IPV4_ADDR_ANY, 0),
                 clatAddress.getAddress(), mIface);
         stacked.addRoute(ipv4Default);
         stacked.addLinkAddress(clatAddress);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 1a4f20c7..4cf5274 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -122,6 +122,13 @@
 //
 // When ConnectivityService disconnects a network:
 // -----------------------------------------------
+// If a network is just connected, ConnectivityService will think it will be used soon, but might
+// not be used. Thus, a 5s timer will be held to prevent the network being torn down immediately.
+// This "nascent" state is implemented by the "lingering" logic below without relating to any
+// request, and is used in some cases where network requests race with network establishment. The
+// nascent state ends when the 5-second timer fires, or as soon as the network satisfies a
+// request, whichever is earlier. In this state, the network is considered in the background.
+//
 // If a network has no chance of satisfying any requests (even if it were to become validated
 // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
 //
@@ -210,23 +217,23 @@
     // network is taken down.  This usually only happens to the default network. Lingering ends with
     // either the linger timeout expiring and the network being taken down, or the network
     // satisfying a request again.
-    public static class LingerTimer implements Comparable<LingerTimer> {
+    public static class InactivityTimer implements Comparable<InactivityTimer> {
         public final int requestId;
         public final long expiryMs;
 
-        public LingerTimer(int requestId, long expiryMs) {
+        public InactivityTimer(int requestId, long expiryMs) {
             this.requestId = requestId;
             this.expiryMs = expiryMs;
         }
         public boolean equals(Object o) {
-            if (!(o instanceof LingerTimer)) return false;
-            LingerTimer other = (LingerTimer) o;
+            if (!(o instanceof InactivityTimer)) return false;
+            InactivityTimer other = (InactivityTimer) o;
             return (requestId == other.requestId) && (expiryMs == other.expiryMs);
         }
         public int hashCode() {
             return Objects.hash(requestId, expiryMs);
         }
-        public int compareTo(LingerTimer other) {
+        public int compareTo(InactivityTimer other) {
             return (expiryMs != other.expiryMs) ?
                     Long.compare(expiryMs, other.expiryMs) :
                     Integer.compare(requestId, other.requestId);
@@ -269,30 +276,32 @@
      */
     public static final int ARG_AGENT_SUCCESS = 1;
 
-    // All linger timers for this network, sorted by expiry time. A linger timer is added whenever
+    // All inactivity timers for this network, sorted by expiry time. A timer is added whenever
     // a request is moved to a network with a better score, regardless of whether the network is or
-    // was lingering or not.
+    // was lingering or not. An inactivity timer is also added when a network connects
+    // without immediately satisfying any requests.
     // TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g.,
     // SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire.
-    private final SortedSet<LingerTimer> mLingerTimers = new TreeSet<>();
+    private final SortedSet<InactivityTimer> mInactivityTimers = new TreeSet<>();
 
-    // For fast lookups. Indexes into mLingerTimers by request ID.
-    private final SparseArray<LingerTimer> mLingerTimerForRequest = new SparseArray<>();
+    // For fast lookups. Indexes into mInactivityTimers by request ID.
+    private final SparseArray<InactivityTimer> mInactivityTimerForRequest = new SparseArray<>();
 
-    // Linger expiry timer. Armed whenever mLingerTimers is non-empty, regardless of whether the
-    // network is lingering or not. Always set to the expiry of the LingerTimer that expires last.
-    // When the timer fires, all linger state is cleared, and if the network has no requests, it is
-    // torn down.
-    private WakeupMessage mLingerMessage;
+    // Inactivity expiry timer. Armed whenever mInactivityTimers is non-empty, regardless of
+    // whether the network is inactive or not. Always set to the expiry of the mInactivityTimers
+    // that expires last. When the timer fires, all inactivity state is cleared, and if the network
+    // has no requests, it is torn down.
+    private WakeupMessage mInactivityMessage;
 
-    // Linger expiry. Holds the expiry time of the linger timer, or 0 if the timer is not armed.
-    private long mLingerExpiryMs;
+    // Inactivity expiry. Holds the expiry time of the inactivity timer, or 0 if the timer is not
+    // armed.
+    private long mInactivityExpiryMs;
 
-    // Whether the network is lingering or not. Must be maintained separately from the above because
+    // Whether the network is inactive or not. Must be maintained separately from the above because
     // it depends on the state of other networks and requests, which only ConnectivityService knows.
     // (Example: we don't linger a network if it would become the best for a NetworkRequest if it
     // validated).
-    private boolean mLingering;
+    private boolean mInactive;
 
     // This represents the quality of the network with no clear scale.
     private int mScore;
@@ -708,8 +717,9 @@
                 mNumBackgroundNetworkRequests += delta;
                 break;
 
-            case TRACK_DEFAULT:
             case LISTEN:
+            case TRACK_DEFAULT:
+            case TRACK_SYSTEM_DEFAULT:
                 break;
 
             case NONE:
@@ -889,26 +899,31 @@
                     ? networkAgentConfig.subscriberId : null;
             return new NetworkState(new NetworkInfo(networkInfo),
                     new LinkProperties(linkProperties),
-                    new NetworkCapabilities(networkCapabilities), network, subscriberId, null);
+                    new NetworkCapabilities(networkCapabilities), network, subscriberId);
         }
     }
 
     /**
      * Sets the specified requestId to linger on this network for the specified time. Called by
-     * ConnectivityService when the request is moved to another network with a higher score.
+     * ConnectivityService when the request is moved to another network with a higher score, or
+     * when a network is newly created.
+     *
+     * @param requestId The requestId of the request that no longer need to be served by this
+     *                  network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
+     *                  {@code LingerTimer} for a newly created network.
      */
     public void lingerRequest(int requestId, long now, long duration) {
-        if (mLingerTimerForRequest.get(requestId) != null) {
+        if (mInactivityTimerForRequest.get(requestId) != null) {
             // Cannot happen. Once a request is lingering on a particular network, we cannot
             // re-linger it unless that network becomes the best for that request again, in which
             // case we should have unlingered it.
             Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered");
         }
         final long expiryMs = now + duration;
-        LingerTimer timer = new LingerTimer(requestId, expiryMs);
-        if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString());
-        mLingerTimers.add(timer);
-        mLingerTimerForRequest.put(requestId, timer);
+        InactivityTimer timer = new InactivityTimer(requestId, expiryMs);
+        if (VDBG) Log.d(TAG, "Adding InactivityTimer " + timer + " to " + toShortString());
+        mInactivityTimers.add(timer);
+        mInactivityTimerForRequest.put(requestId, timer);
     }
 
     /**
@@ -916,23 +931,25 @@
      * Returns true if the given requestId was lingering on this network, false otherwise.
      */
     public boolean unlingerRequest(int requestId) {
-        LingerTimer timer = mLingerTimerForRequest.get(requestId);
+        InactivityTimer timer = mInactivityTimerForRequest.get(requestId);
         if (timer != null) {
-            if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString());
-            mLingerTimers.remove(timer);
-            mLingerTimerForRequest.remove(requestId);
+            if (VDBG) {
+                Log.d(TAG, "Removing InactivityTimer " + timer + " from " + toShortString());
+            }
+            mInactivityTimers.remove(timer);
+            mInactivityTimerForRequest.remove(requestId);
             return true;
         }
         return false;
     }
 
-    public long getLingerExpiry() {
-        return mLingerExpiryMs;
+    public long getInactivityExpiry() {
+        return mInactivityExpiryMs;
     }
 
-    public void updateLingerTimer() {
-        long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs;
-        if (newExpiry == mLingerExpiryMs) return;
+    public void updateInactivityTimer() {
+        long newExpiry = mInactivityTimers.isEmpty() ? 0 : mInactivityTimers.last().expiryMs;
+        if (newExpiry == mInactivityExpiryMs) return;
 
         // Even if we're going to reschedule the timer, cancel it first. This is because the
         // semantics of WakeupMessage guarantee that if cancel is called then the alarm will
@@ -940,49 +957,65 @@
         // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
         // has already been dispatched, rescheduling to some time in the future won't stop it
         // from calling its callback immediately.
-        if (mLingerMessage != null) {
-            mLingerMessage.cancel();
-            mLingerMessage = null;
+        if (mInactivityMessage != null) {
+            mInactivityMessage.cancel();
+            mInactivityMessage = null;
         }
 
         if (newExpiry > 0) {
-            mLingerMessage = new WakeupMessage(
+            mInactivityMessage = new WakeupMessage(
                     mContext, mHandler,
                     "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
                     EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
                     0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
                     this /* obj (NetworkAgentInfo) */);
-            mLingerMessage.schedule(newExpiry);
+            mInactivityMessage.schedule(newExpiry);
         }
 
-        mLingerExpiryMs = newExpiry;
+        mInactivityExpiryMs = newExpiry;
     }
 
-    public void linger() {
-        mLingering = true;
+    public void setInactive() {
+        mInactive = true;
     }
 
-    public void unlinger() {
-        mLingering = false;
+    public void unsetInactive() {
+        mInactive = false;
+    }
+
+    public boolean isInactive() {
+        return mInactive;
     }
 
     public boolean isLingering() {
-        return mLingering;
+        return mInactive && !isNascent();
     }
 
-    public void clearLingerState() {
-        if (mLingerMessage != null) {
-            mLingerMessage.cancel();
-            mLingerMessage = null;
+    /**
+     * Return whether the network is just connected and about to be torn down because of not
+     * satisfying any request.
+     */
+    public boolean isNascent() {
+        return mInactive && mInactivityTimers.size() == 1
+                && mInactivityTimers.first().requestId == NetworkRequest.REQUEST_ID_NONE;
+    }
+
+    public void clearInactivityState() {
+        if (mInactivityMessage != null) {
+            mInactivityMessage.cancel();
+            mInactivityMessage = null;
         }
-        mLingerTimers.clear();
-        mLingerTimerForRequest.clear();
-        updateLingerTimer();  // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage.
-        mLingering = false;
+        mInactivityTimers.clear();
+        mInactivityTimerForRequest.clear();
+        // Sets mInactivityExpiryMs, cancels and nulls out mInactivityMessage.
+        updateInactivityTimer();
+        mInactive = false;
     }
 
-    public void dumpLingerTimers(PrintWriter pw) {
-        for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
+    public void dumpInactivityTimers(PrintWriter pw) {
+        for (InactivityTimer timer : mInactivityTimers) {
+            pw.println(timer);
+        }
     }
 
     /**
@@ -1016,7 +1049,7 @@
                 + "network{" + network + "}  handle{" + network.getNetworkHandle() + "}  ni{"
                 + networkInfo.toShortString() + "} "
                 + "  Score{" + getCurrentScore() + "} "
-                + (isLingering() ? " lingering" : "")
+                + (isNascent() ? " nascent" : (isLingering() ? " lingering" : ""))
                 + (everValidated ? " everValidated" : "")
                 + (lastValidated ? " lastValidated" : "")
                 + (partialConnectivity ? " partialConnectivity" : "")
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 3d71b0a..508739f 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -79,7 +79,6 @@
     // server.
     public static final String NOTIFICATION_CHANNEL_NETWORK_STATUS = "NETWORK_STATUS";
     public static final String NOTIFICATION_CHANNEL_NETWORK_ALERTS = "NETWORK_ALERTS";
-    public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
 
     // The context is for the current user (system server)
     private final Context mContext;
@@ -161,13 +160,20 @@
         if (nai != null) {
             transportType = approximateTransportType(nai);
             final String extraInfo = nai.networkInfo.getExtraInfo();
-            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSsid() : extraInfo;
+            if (nai.linkProperties != null && nai.linkProperties.getCaptivePortalData() != null
+                    && !TextUtils.isEmpty(nai.linkProperties.getCaptivePortalData()
+                    .getVenueFriendlyName())) {
+                name = nai.linkProperties.getCaptivePortalData().getVenueFriendlyName();
+            } else {
+                name = TextUtils.isEmpty(extraInfo)
+                        ? WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()) : extraInfo;
+            }
             // Only notify for Internet-capable networks.
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
         } else {
             // Legacy notifications.
             transportType = TRANSPORT_CELLULAR;
-            name = null;
+            name = "";
         }
 
         // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -193,35 +199,30 @@
         final CharSequence details;
         int icon = getIcon(transportType);
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
-            title = r.getString(R.string.wifi_no_internet,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+            title = r.getString(R.string.wifi_no_internet, name);
             details = r.getString(R.string.wifi_no_internet_detailed);
         } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
             if (transportType == TRANSPORT_CELLULAR) {
                 title = r.getString(R.string.mobile_no_internet);
             } else if (transportType == TRANSPORT_WIFI) {
-                title = r.getString(R.string.wifi_no_internet,
-                        WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+                title = r.getString(R.string.wifi_no_internet, name);
             } else {
                 title = r.getString(R.string.other_networks_no_internet);
             }
             details = r.getString(R.string.private_dns_broken_detailed);
         } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
                 && transportType == TRANSPORT_WIFI) {
-            title = r.getString(R.string.network_partial_connectivity,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+            title = r.getString(R.string.network_partial_connectivity, name);
             details = r.getString(R.string.network_partial_connectivity_detailed);
         } else if (notifyType == NotificationType.LOST_INTERNET &&
                 transportType == TRANSPORT_WIFI) {
-            title = r.getString(R.string.wifi_no_internet,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+            title = r.getString(R.string.wifi_no_internet, name);
             details = r.getString(R.string.wifi_no_internet_detailed);
         } else if (notifyType == NotificationType.SIGN_IN) {
             switch (transportType) {
                 case TRANSPORT_WIFI:
                     title = r.getString(R.string.wifi_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed,
-                            WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+                    details = r.getString(R.string.network_available_sign_in_detailed, name);
                     break;
                 case TRANSPORT_CELLULAR:
                     title = r.getString(R.string.network_available_sign_in, 0);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d507b5f..9411e33 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -28,6 +28,8 @@
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
 
+import static com.android.net.module.util.CollectionUtils.toIntArray;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -40,23 +42,21 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.SystemConfigManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.system.OsConstants;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.CollectionUtils;
 import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -80,12 +80,12 @@
 
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
+    private final SystemConfigManager mSystemConfigManager;
     private final INetd mNetd;
     private final Dependencies mDeps;
 
-    // Values are User IDs.
     @GuardedBy("this")
-    private final Set<Integer> mUsers = new HashSet<>();
+    private final Set<UserHandle> mUsers = new HashSet<>();
 
     // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
     @GuardedBy("this")
@@ -124,6 +124,7 @@
             @NonNull final Dependencies deps) {
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
         mNetd = netd;
         mDeps = deps;
     }
@@ -173,25 +174,20 @@
             netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
         }
 
-        final List<UserHandle> users = mUserManager.getUserHandles(true /* excludeDying */);
-        for (UserHandle user : users) {
-            mUsers.add(user.getIdentifier());
-        }
+        mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
 
-        final SparseArray<ArraySet<String>> systemPermission =
-                SystemConfig.getInstance().getSystemPermissions();
-        for (int i = 0; i < systemPermission.size(); i++) {
-            ArraySet<String> perms = systemPermission.valueAt(i);
-            int uid = systemPermission.keyAt(i);
-            int netdPermission = 0;
-            // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
-            if (perms != null) {
-                netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
-                        ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
-                netdPermission |= perms.contains(INTERNET)
-                        ? INetd.PERMISSION_INTERNET : 0;
+        final SparseArray<String> netdPermToSystemPerm = new SparseArray<>();
+        netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET);
+        netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS);
+        for (int i = 0; i < netdPermToSystemPerm.size(); i++) {
+            final int netdPermission = netdPermToSystemPerm.keyAt(i);
+            final String systemPermission = netdPermToSystemPerm.valueAt(i);
+            final int[] hasPermissionUids =
+                    mSystemConfigManager.getSystemPermissionUids(systemPermission);
+            for (int j = 0; j < hasPermissionUids.length; j++) {
+                final int uid = hasPermissionUids[j];
+                netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
             }
-            netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
         }
         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
         update(mUsers, mApps, true);
@@ -208,7 +204,7 @@
         if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
             return false;
         }
-        final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
+        final int index = CollectionUtils.indexOf(app.requestedPermissions, permission);
         if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
         return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
     }
@@ -250,21 +246,14 @@
         return mApps.containsKey(uid);
     }
 
-    private int[] toIntArray(Collection<Integer> list) {
-        int[] array = new int[list.size()];
-        int i = 0;
-        for (Integer item : list) {
-            array[i++] = item;
-        }
-        return array;
-    }
-
-    private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
+    private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
         List<Integer> network = new ArrayList<>();
         List<Integer> system = new ArrayList<>();
         for (Entry<Integer, Boolean> app : apps.entrySet()) {
             List<Integer> list = app.getValue() ? system : network;
-            for (int user : users) {
+            for (UserHandle user : users) {
+                if (user == null) continue;
+
                 list.add(UserHandle.getUid(user, app.getKey()));
             }
         }
@@ -288,14 +277,10 @@
      *
      * @hide
      */
-    public synchronized void onUserAdded(int user) {
-        if (user < 0) {
-            loge("Invalid user in onUserAdded: " + user);
-            return;
-        }
+    public synchronized void onUserAdded(@NonNull UserHandle user) {
         mUsers.add(user);
 
-        Set<Integer> users = new HashSet<>();
+        Set<UserHandle> users = new HashSet<>();
         users.add(user);
         update(users, mApps, true);
     }
@@ -307,14 +292,10 @@
      *
      * @hide
      */
-    public synchronized void onUserRemoved(int user) {
-        if (user < 0) {
-            loge("Invalid user in onUserRemoved: " + user);
-            return;
-        }
+    public synchronized void onUserRemoved(@NonNull UserHandle user) {
         mUsers.remove(user);
 
-        Set<Integer> users = new HashSet<>();
+        Set<UserHandle> users = new HashSet<>();
         users.add(user);
         update(users, mApps, false);
     }
@@ -550,7 +531,10 @@
         for (UidRange range : ranges) {
             for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
                 for (int appId : appIds) {
-                    final int uid = UserHandle.getUid(userId, appId);
+                    final UserHandle handle = UserHandle.of(userId);
+                    if (handle == null) continue;
+
+                    final int uid = UserHandle.getUid(handle, appId);
                     if (range.contains(uid)) {
                         result.add(uid);
                     }
@@ -669,23 +653,23 @@
             if (allPermissionAppIds.size() != 0) {
                 mNetd.trafficSetNetPermForUids(
                         INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
-                        ArrayUtils.convertToIntArray(allPermissionAppIds));
+                        toIntArray(allPermissionAppIds));
             }
             if (internetPermissionAppIds.size() != 0) {
                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
-                        ArrayUtils.convertToIntArray(internetPermissionAppIds));
+                        toIntArray(internetPermissionAppIds));
             }
             if (updateStatsPermissionAppIds.size() != 0) {
                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
-                        ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+                        toIntArray(updateStatsPermissionAppIds));
             }
             if (noPermissionAppIds.size() != 0) {
                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
-                        ArrayUtils.convertToIntArray(noPermissionAppIds));
+                        toIntArray(noPermissionAppIds));
             }
             if (uninstalledAppIds.size() != 0) {
                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
-                        ArrayUtils.convertToIntArray(uninstalledAppIds));
+                        toIntArray(uninstalledAppIds));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 87b4c16..7ef315c 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,7 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.util.CollectionUtils;
 import com.android.server.ConnectivityService;
@@ -260,18 +260,18 @@
     }
 
     private static void log(final String msg) {
-        Slog.d(TAG, msg);
+        Log.d(TAG, msg);
     }
 
     private static void logw(final String msg) {
-        Slog.w(TAG, msg);
+        Log.w(TAG, msg);
     }
 
     private static void loge(final String msg) {
-        Slog.e(TAG, msg);
+        Log.e(TAG, msg);
     }
 
     private static void logwtf(final String msg) {
-        Slog.wtf(TAG, msg);
+        Log.wtf(TAG, msg);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index b5f20d7..c480594 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -41,7 +41,6 @@
 import android.os.MessageQueue;
 import android.os.Messenger;
 import android.system.ErrnoException;
-import android.system.Int32Ref;
 import android.system.Os;
 import android.util.Log;
 import android.util.SparseArray;
@@ -306,9 +305,8 @@
 
     private static boolean isReceiveQueueEmpty(FileDescriptor fd)
             throws ErrnoException {
-        Int32Ref result = new Int32Ref(-1);
-        Os.ioctlInt(fd, SIOCINQ, result);
-        if (result.value != 0) {
+        final int result = Os.ioctlInt(fd, SIOCINQ);
+        if (result != 0) {
             Log.e(TAG, "Read queue has data");
             return false;
         }
@@ -317,9 +315,8 @@
 
     private static boolean isSendQueueEmpty(FileDescriptor fd)
             throws ErrnoException {
-        Int32Ref result = new Int32Ref(-1);
-        Os.ioctlInt(fd, SIOCOUTQ, result);
-        if (result.value != 0) {
+        final int result = Os.ioctlInt(fd, SIOCOUTQ);
+        if (result != 0) {
             Log.e(TAG, "Write queue has data");
             return false;
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index d956ba3..01ac81fb 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -21,10 +21,10 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -51,6 +51,7 @@
 import android.net.INetd;
 import android.net.INetworkManagementEventObserver;
 import android.net.Ikev2VpnProfile;
+import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
 import android.net.IpSecManager.IpSecTunnelInterface;
@@ -73,6 +74,7 @@
 import android.net.UnderlyingNetworkInfo;
 import android.net.VpnManager;
 import android.net.VpnService;
+import android.net.VpnTransportInfo;
 import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.ChildSessionConfiguration;
 import android.net.ipsec.ike.ChildSessionParams;
@@ -111,6 +113,8 @@
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
+import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.NetworkStackConstants;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
@@ -169,6 +173,12 @@
      */
     @VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB
 
+    /**
+     * Network score that VPNs will announce to ConnectivityService.
+     * TODO: remove when the network scoring refactor lands.
+     */
+    private static final int VPN_DEFAULT_SCORE = 101;
+
     // TODO: create separate trackers for each unique VPN to support
     // automated reconnection
 
@@ -203,6 +213,7 @@
     protected final NetworkCapabilities mNetworkCapabilities;
     private final SystemServices mSystemServices;
     private final Ikev2SessionCreator mIkev2SessionCreator;
+    private final UserManager mUserManager;
 
     /**
      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
@@ -277,6 +288,10 @@
             return LocalServices.getService(DeviceIdleInternal.class);
         }
 
+        public PendingIntent getIntentForStatusPanel(Context context) {
+            return VpnConfig.getIntentForStatusPanel(context);
+        }
+
         public void sendArgumentsToDaemon(
                 final String daemon, final LocalSocket socket, final String[] arguments,
                 final RetryScheduler retryScheduler) throws IOException, InterruptedException {
@@ -327,7 +342,7 @@
         public InetAddress resolve(final String endpoint)
                 throws ExecutionException, InterruptedException {
             try {
-                return InetAddress.parseNumericAddress(endpoint);
+                return InetAddresses.parseNumericAddress(endpoint);
             } catch (IllegalArgumentException e) {
                 // Endpoint is not numeric : fall through and resolve
             }
@@ -405,6 +420,7 @@
         mLooper = looper;
         mSystemServices = systemServices;
         mIkev2SessionCreator = ikev2SessionCreator;
+        mUserManager = mContext.getSystemService(UserManager.class);
 
         mPackage = VpnConfig.LEGACY_VPN;
         mOwnerUID = getAppUid(mPackage, mUserId);
@@ -427,6 +443,7 @@
         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
         mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
 
         loadAlwaysOnPackage(keyStore);
     }
@@ -486,6 +503,11 @@
         updateAlwaysOnNotification(detailedState);
     }
 
+    private void resetNetworkCapabilities() {
+        mNetworkCapabilities.setUids(null);
+        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+    }
+
     /**
      * Chooses whether to force all connections to go though VPN.
      *
@@ -510,6 +532,11 @@
         }
     }
 
+    /** Returns the package name that is currently prepared. */
+    public String getPackage() {
+        return mPackage;
+    }
+
     /**
      * Check whether to prevent all traffic outside of a VPN even when the VPN is not connected.
      *
@@ -920,7 +947,7 @@
                 agentDisconnect();
                 jniReset(mInterface);
                 mInterface = null;
-                mNetworkCapabilities.setUids(null);
+                resetNetworkCapabilities();
             }
 
             // Revoke the connection or stop the VpnRunner.
@@ -991,6 +1018,8 @@
                 case VpnManager.TYPE_VPN_SERVICE:
                     toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
                     break;
+                case VpnManager.TYPE_VPN_LEGACY:
+                    return false;
                 default:
                     Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
                     return false;
@@ -1021,6 +1050,8 @@
                 return isVpnServicePreConsented(context, packageName);
             case VpnManager.TYPE_VPN_PLATFORM:
                 return isVpnProfilePreConsented(context, packageName);
+            case VpnManager.TYPE_VPN_LEGACY:
+                return VpnConfig.LEGACY_VPN.equals(packageName);
             default:
                 return false;
         }
@@ -1119,7 +1150,7 @@
 
         if (mConfig.dnsServers != null) {
             for (String dnsServer : mConfig.dnsServers) {
-                InetAddress address = InetAddress.parseNumericAddress(dnsServer);
+                InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
                 lp.addDnsServer(address);
                 allowIPv4 |= address instanceof Inet4Address;
                 allowIPv6 |= address instanceof Inet6Address;
@@ -1129,10 +1160,12 @@
         lp.setHttpProxy(mConfig.proxyInfo);
 
         if (!allowIPv4) {
-            lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
+            lp.addRoute(new RouteInfo(new IpPrefix(
+                    NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE));
         }
         if (!allowIPv6) {
-            lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+            lp.addRoute(new RouteInfo(new IpPrefix(
+                    NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE));
         }
 
         // Concatenate search domains into a string.
@@ -1201,6 +1234,8 @@
         mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
 
+        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+
         // Only apps targeting Q and above can explicitly declare themselves as metered.
         // These VPNs are assumed metered unless they state otherwise.
         if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
@@ -1210,8 +1245,7 @@
         }
 
         mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
-                mNetworkCapabilities, lp,
-                ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+                mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
             @Override
             public void unwanted() {
                 // We are user controlled, not driven by NetworkRequest.
@@ -1431,7 +1465,7 @@
             final long token = Binder.clearCallingIdentity();
             List<UserInfo> users;
             try {
-                users = UserManager.get(mContext).getAliveUsers();
+                users = mUserManager.getAliveUsers();
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1476,7 +1510,7 @@
             if (start != -1) ranges.add(new UidRange(start, stop));
         } else if (disallowedApplications != null) {
             // Add all ranges for user skipping UIDs for disallowedApplications.
-            final UidRange userRange = UidRange.createForUser(userId);
+            final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
             int start = userRange.start;
             for (int uid : getAppsUids(disallowedApplications, userId)) {
                 if (uid == start) {
@@ -1489,7 +1523,7 @@
             if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
         } else {
             // Add all UIDs for the user.
-            ranges.add(UidRange.createForUser(userId));
+            ranges.add(UidRange.createForUser(UserHandle.of(userId)));
         }
     }
 
@@ -1498,7 +1532,7 @@
     private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
         // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
         // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
-        final UidRange userRange = UidRange.createForUser(userId);
+        final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
         final List<UidRange> ranges = new ArrayList<>();
         for (UidRange range : existingRanges) {
             if (userRange.containsRange(range)) {
@@ -1515,7 +1549,7 @@
      */
     public void onUserAdded(int userId) {
         // If the user is restricted tie them to the parent user's VPN
-        UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+        UserInfo user = mUserManager.getUserInfo(userId);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
                 final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
@@ -1543,7 +1577,7 @@
      */
     public void onUserRemoved(int userId) {
         // clean up if restricted
-        UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+        UserInfo user = mUserManager.getUserInfo(userId);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
                 final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
@@ -1725,7 +1759,7 @@
 
     private void cleanupVpnStateLocked() {
         mStatusIntent = null;
-        mNetworkCapabilities.setUids(null);
+        resetNetworkCapabilities();
         mConfig = null;
         mInterface = null;
 
@@ -1768,7 +1802,7 @@
     private void prepareStatusIntent() {
         final long token = Binder.clearCallingIdentity();
         try {
-            mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
+            mStatusIntent = mDeps.getIntentForStatusPanel(mContext);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -1836,22 +1870,18 @@
     }
 
     /**
-     * Gets the currently running App-based VPN type
+     * Gets the currently running VPN type
      *
-     * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running an
-     *     app-based VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
+     * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running a
+     *     VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
      *     Settings-based, the Platform VPNs can be initiated by both apps and Settings.
      */
-    public synchronized int getActiveAppVpnType() {
-        if (VpnConfig.LEGACY_VPN.equals(mPackage)) {
-            return VpnManager.TYPE_VPN_NONE;
-        }
-
-        if (mVpnRunner != null && mVpnRunner instanceof IkeV2VpnRunner) {
-            return VpnManager.TYPE_VPN_PLATFORM;
-        } else {
-            return VpnManager.TYPE_VPN_SERVICE;
-        }
+    public synchronized int getActiveVpnType() {
+        if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE;
+        if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE;
+        return mVpnRunner instanceof IkeV2VpnRunner
+                ? VpnManager.TYPE_VPN_PLATFORM
+                : VpnManager.TYPE_VPN_LEGACY;
     }
 
     private void updateAlwaysOnNotification(DetailedState networkState) {
@@ -1968,8 +1998,7 @@
 
     private void enforceNotRestrictedUser() {
         Binder.withCleanCallingIdentity(() -> {
-            final UserManager mgr = UserManager.get(mContext);
-            final UserInfo user = mgr.getUserInfo(mUserId);
+            final UserInfo user = mUserManager.getUserInfo(mUserId);
 
             if (user.isRestricted()) {
                 throw new SecurityException("Restricted users cannot configure VPNs");
@@ -2004,9 +2033,8 @@
      */
     public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
             @Nullable Network underlying, @NonNull LinkProperties egress) {
-        UserManager mgr = UserManager.get(mContext);
-        UserInfo user = mgr.getUserInfo(mUserId);
-        if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
+        UserInfo user = mUserManager.getUserInfo(mUserId);
+        if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
                     new UserHandle(mUserId))) {
             throw new SecurityException("Restricted users cannot establish VPNs");
         }
@@ -2501,7 +2529,7 @@
                                     address /* unused */,
                                     address /* unused */,
                                     network);
-                    mNms.setInterfaceUp(mTunnelIface.getInterfaceName());
+                    NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
 
                     mSession = mIkev2SessionCreator.createIkeSession(
                             mContext,
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 5d1c4e6..16d4f94 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -555,7 +555,7 @@
     private void bootCompleted() {
         // on boot, if device is interactive, set HDMI CEC state as powered on as well
         if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
-            onWakeUp();
+            mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
         }
     }
 
diff --git a/services/core/java/com/android/server/input/OWNERS b/services/core/java/com/android/server/input/OWNERS
index 0313a40..82c6ee1 100644
--- a/services/core/java/com/android/server/input/OWNERS
+++ b/services/core/java/com/android/server/input/OWNERS
@@ -1,2 +1,3 @@
+lzye@google.com
 michaelwr@google.com
 svv@google.com
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index c005af4..f1750cd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -89,6 +89,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
+import android.security.AndroidKeyStoreMaintenance;
 import android.security.Authorization;
 import android.security.KeyStore;
 import android.security.keystore.AndroidKeyStoreProvider;
@@ -225,7 +226,6 @@
     private final SyntheticPasswordManager mSpManager;
 
     private final KeyStore mKeyStore;
-
     private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
     private ManagedProfilePasswordCache mManagedProfilePasswordCache;
 
@@ -280,6 +280,7 @@
             super.onBootPhase(phase);
             if (phase == PHASE_ACTIVITY_MANAGER_READY) {
                 mLockSettingsService.migrateOldDataAfterSystemReady();
+                mLockSettingsService.loadEscrowData();
             }
         }
 
@@ -802,6 +803,7 @@
             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
                 // Notify keystore that a new user was added.
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                AndroidKeyStoreMaintenance.onUserAdded(userHandle);
                 final KeyStore ks = KeyStore.getInstance();
                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -832,11 +834,15 @@
         mSpManager.initWeaverService();
         getAuthSecretHal();
         mDeviceProvisionedObserver.onSystemReady();
-        mRebootEscrowManager.loadRebootEscrowDataIfAvailable();
+
         // TODO: maybe skip this for split system user mode.
         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
     }
 
+    private void loadEscrowData() {
+        mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
+    }
+
     private void getAuthSecretHal() {
         try {
             mAuthSecretService = IAuthSecret.getService(/* retry */ true);
@@ -1265,6 +1271,7 @@
     }
 
     private void setKeystorePassword(byte[] password, int userHandle) {
+        AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
         final KeyStore ks = KeyStore.getInstance();
         // TODO(b/120484642): Update keystore to accept byte[] passwords
         String passwordString = password == null ? null : new String(password);
@@ -1273,7 +1280,7 @@
 
     private void unlockKeystore(byte[] password, int userHandle) {
         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
-        new Authorization().onLockScreenEvent(false, userHandle, password);
+        Authorization.onLockScreenEvent(false, userHandle, password);
         // TODO(b/120484642): Update keystore to accept byte[] passwords
         String passwordString = password == null ? null : new String(password);
         final KeyStore ks = KeyStore.getInstance();
@@ -2296,6 +2303,7 @@
         mSpManager.removeUser(userId);
         mStrongAuth.removeUser(userId);
 
+        AndroidKeyStoreMaintenance.onUserRemoved(userId);
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserRemoved(userId);
         mManagedProfilePasswordCache.removePassword(userId);
@@ -2381,10 +2389,17 @@
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
         enforceShell();
+        final int origPid = Binder.getCallingPid();
+        final int origUid = Binder.getCallingUid();
+
+        // The original identity is an opaque integer.
         final long origId = Binder.clearCallingIdentity();
+        Slog.e(TAG, "Caller pid " + origPid + " Caller uid " + origUid);
         try {
-            (new LockSettingsShellCommand(new LockPatternUtils(mContext))).exec(
-                    this, in, out, err, args, callback, resultReceiver);
+            final LockSettingsShellCommand command =
+                    new LockSettingsShellCommand(new LockPatternUtils(mContext), mContext, origPid,
+                            origUid);
+            command.exec(this, in, out, err, args, callback, resultReceiver);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 7b767b8..8d38bfe 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -23,8 +23,11 @@
 
 import android.app.ActivityManager;
 import android.app.admin.PasswordMetrics;
+import android.content.Context;
 import android.os.ShellCommand;
+import android.os.SystemProperties;
 import android.text.TextUtils;
+import android.util.Slog;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
@@ -45,15 +48,25 @@
     private static final String COMMAND_VERIFY = "verify";
     private static final String COMMAND_GET_DISABLED = "get-disabled";
     private static final String COMMAND_REMOVE_CACHE = "remove-cache";
+    private static final String COMMAND_SET_ROR_PROVIDER_PACKAGE =
+            "set-resume-on-reboot-provider-package";
     private static final String COMMAND_HELP = "help";
 
     private int mCurrentUserId;
     private final LockPatternUtils mLockPatternUtils;
+    private final Context mContext;
+    private final int mCallingPid;
+    private final int mCallingUid;
+
     private String mOld = "";
     private String mNew = "";
 
-    LockSettingsShellCommand(LockPatternUtils lockPatternUtils) {
+    LockSettingsShellCommand(LockPatternUtils lockPatternUtils, Context context, int callingPid,
+            int callingUid) {
         mLockPatternUtils = lockPatternUtils;
+        mCallingPid = callingPid;
+        mCallingUid = callingUid;
+        mContext = context;
     }
 
     @Override
@@ -70,6 +83,7 @@
                     case COMMAND_HELP:
                     case COMMAND_GET_DISABLED:
                     case COMMAND_SET_DISABLED:
+                    case COMMAND_SET_ROR_PROVIDER_PACKAGE:
                         break;
                     default:
                         getErrPrintWriter().println(
@@ -82,6 +96,9 @@
                 case COMMAND_REMOVE_CACHE:
                     runRemoveCache();
                     return 0;
+                case COMMAND_SET_ROR_PROVIDER_PACKAGE:
+                    runSetResumeOnRebootProviderPackage();
+                    return 0;
                 case COMMAND_HELP:
                     onHelp();
                     return 0;
@@ -173,6 +190,10 @@
             pw.println("  remove-cache [--user USER_ID]");
             pw.println("    Removes cached unified challenge for the managed profile.");
             pw.println("");
+            pw.println("  set-resume-on-reboot-provider-package <package_name>");
+            pw.println("    Sets the package name for server based resume on reboot service "
+                    + "provider.");
+            pw.println("");
         }
     }
 
@@ -258,6 +279,17 @@
         return true;
     }
 
+    private boolean runSetResumeOnRebootProviderPackage() {
+        final String packageName = mNew;
+        String name = ResumeOnRebootServiceProvider.PROP_ROR_PROVIDER_PACKAGE;
+        Slog.i(TAG, "Setting " +  name + " to " + packageName);
+
+        mContext.enforcePermission(android.Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE,
+                mCallingPid, mCallingUid, TAG);
+        SystemProperties.set(name, packageName);
+        return true;
+    }
+
     private boolean runClear() {
         LockscreenCredential none = LockscreenCredential.createNone();
         if (!isNewCredentialSufficient(none)) {
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowData.java b/services/core/java/com/android/server/locksettings/RebootEscrowData.java
index 38eeb88..af0774c 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowData.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowData.java
@@ -35,6 +35,12 @@
      */
     private static final int CURRENT_VERSION = 2;
 
+    /**
+    * This is the legacy version of the escrow data format for R builds. The escrow data is only
+    * encrypted by the escrow key, without additional wrap of another key from keystore.
+    */
+    private static final int LEGACY_SINGLE_ENCRYPTED_VERSION = 1;
+
     private RebootEscrowData(byte spVersion, byte[] syntheticPassword, byte[] blob,
             RebootEscrowKey key) {
         mSpVersion = spVersion;
@@ -64,6 +70,19 @@
         return mKey;
     }
 
+    private static byte[] decryptBlobCurrentVersion(SecretKey kk, RebootEscrowKey ks,
+            DataInputStream dis) throws IOException {
+        if (kk == null) {
+            throw new IOException("Failed to find wrapper key in keystore, cannot decrypt the"
+                    + " escrow data");
+        }
+
+        // Decrypt the blob with the key from keystore first, then decrypt again with the reboot
+        // escrow key.
+        byte[] ksEncryptedBlob = AesEncryptionUtil.decrypt(kk, dis);
+        return AesEncryptionUtil.decrypt(ks.getKey(), ksEncryptedBlob);
+    }
+
     static RebootEscrowData fromEncryptedData(RebootEscrowKey ks, byte[] blob, SecretKey kk)
             throws IOException {
         Objects.requireNonNull(ks);
@@ -71,17 +90,20 @@
 
         DataInputStream dis = new DataInputStream(new ByteArrayInputStream(blob));
         int version = dis.readInt();
-        if (version != CURRENT_VERSION) {
-            throw new IOException("Unsupported version " + version);
-        }
         byte spVersion = dis.readByte();
-
-        // Decrypt the blob with the key from keystore first, then decrypt again with the reboot
-        // escrow key.
-        byte[] ksEncryptedBlob = AesEncryptionUtil.decrypt(kk, dis);
-        final byte[] syntheticPassword = AesEncryptionUtil.decrypt(ks.getKey(), ksEncryptedBlob);
-
-        return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+        switch (version) {
+            case CURRENT_VERSION: {
+                byte[] syntheticPassword = decryptBlobCurrentVersion(kk, ks, dis);
+                return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+            }
+            case LEGACY_SINGLE_ENCRYPTED_VERSION: {
+                // Decrypt the blob with the escrow key directly.
+                byte[] syntheticPassword = AesEncryptionUtil.decrypt(ks.getKey(), dis);
+                return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+            }
+            default:
+                throw new IOException("Unsupported version " + version);
+        }
     }
 
     static RebootEscrowData fromSyntheticPassword(RebootEscrowKey ks, byte spVersion,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 06962d4..30ea555 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -21,6 +21,7 @@
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
@@ -39,6 +40,7 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 
 import javax.crypto.SecretKey;
 
@@ -76,6 +78,13 @@
     private static final int BOOT_COUNT_TOLERANCE = 5;
 
     /**
+     * The default retry specs for loading reboot escrow data. We will attempt to retry loading
+     * escrow data on temporarily errors, e.g. unavailable network.
+     */
+    private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
+    private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+
+    /**
      * Logs events for later debugging in bugreports.
      */
     private final RebootEscrowEventLog mEventLog;
@@ -137,6 +146,7 @@
             RebootEscrowProviderInterface rebootEscrowProvider;
             if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
                     "server_based_ror_enabled", false)) {
+                Slog.i(TAG, "Using server based resume on reboot");
                 rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
             } else {
                 rebootEscrowProvider = new RebootEscrowProviderHalImpl();
@@ -148,6 +158,14 @@
             return null;
         }
 
+        void post(Handler handler, Runnable runnable) {
+            handler.post(runnable);
+        }
+
+        void postDelayed(Handler handler, Runnable runnable, long delayMillis) {
+            handler.postDelayed(runnable, delayMillis);
+        }
+
         public Context getContext() {
             return mContext;
         }
@@ -199,7 +217,18 @@
         mKeyStoreManager = injector.getKeyStoreManager();
     }
 
-    void loadRebootEscrowDataIfAvailable() {
+    private void onGetRebootEscrowKeyFailed(List<UserInfo> users) {
+        Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
+        for (UserInfo user : users) {
+            mStorage.removeRebootEscrow(user.id);
+        }
+
+        // Clear the old key in keystore.
+        mKeyStoreManager.clearKeyStoreEncryptionKey();
+        onEscrowRestoreComplete(false);
+    }
+
+    void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
         List<UserInfo> users = mUserManager.getUsers();
         List<UserInfo> rebootEscrowUsers = new ArrayList<>();
         for (UserInfo user : users) {
@@ -212,17 +241,53 @@
             return;
         }
 
+        mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
+                retryHandler, 0, users, rebootEscrowUsers));
+    }
+
+    void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
+            List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+        Objects.requireNonNull(retryHandler);
+
+        final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+                "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
+        final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+                "load_escrow_data_retry_interval_seconds",
+                DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
+
+        if (attemptNumber < retryLimit) {
+            Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
+            mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
+                    retryHandler, attemptNumber, users, rebootEscrowUsers),
+                    retryIntervalInSeconds * 1000);
+            return;
+        }
+
+        Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+        onGetRebootEscrowKeyFailed(users);
+    }
+
+    void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
+            List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
         // Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
         // generated before reboot. Note that we will clear the escrow key even if the keystore key
         // is null.
         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
-        RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(kk);
-        if (kk == null || escrowKey == null) {
-            Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
-            for (UserInfo user : users) {
-                mStorage.removeRebootEscrow(user.id);
-            }
-            onEscrowRestoreComplete(false);
+        if (kk == null) {
+            Slog.i(TAG, "Failed to load the key for resume on reboot from key store.");
+        }
+
+        RebootEscrowKey escrowKey;
+        try {
+            escrowKey = getAndClearRebootEscrowKey(kk);
+        } catch (IOException e) {
+            scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
+                    rebootEscrowUsers);
+            return;
+        }
+
+        if (escrowKey == null) {
+            onGetRebootEscrowKeyFailed(users);
             return;
         }
 
@@ -249,7 +314,7 @@
         }
     }
 
-    private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) {
+    private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
         RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
         if (rebootEscrowProvider == null) {
             Slog.w(TAG,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
index 6c1040b..4b00772 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -33,7 +33,7 @@
  * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL.
  */
 class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
-    private static final String TAG = "RebootEscrowProvider";
+    private static final String TAG = "RebootEscrowProviderHal";
 
     private final Injector mInjector;
 
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
index 857ad5f..af6faad 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -16,6 +16,8 @@
 
 package com.android.server.locksettings;
 
+import java.io.IOException;
+
 import javax.crypto.SecretKey;
 
 /**
@@ -33,9 +35,10 @@
 
     /**
      * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted,
-     * use the input key to decrypt the RebootEscrowKey. Returns null on failure.
+     * use the input key to decrypt the RebootEscrowKey. Returns null on failure. Throws an
+     * IOException if the failure is non-fatal, and a retry may succeed.
      */
-    RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey);
+    RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException;
 
     /**
      * Clears the stored RebootEscrowKey.
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index ba1a680..b3b4546 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -35,7 +35,7 @@
  * encrypt & decrypt the blob.
  */
 class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface {
-    private static final String TAG = "RebootEscrowProvider";
+    private static final String TAG = "RebootEscrowProviderServerBased";
 
     // Timeout for service binding
     private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10;
@@ -50,6 +50,8 @@
 
     private final Injector mInjector;
 
+    private byte[] mServerBlob;
+
     static class Injector {
         private ResumeOnRebootServiceConnection mServiceConnection = null;
 
@@ -124,17 +126,25 @@
     }
 
     @Override
-    public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
-        byte[] serverBlob = mStorage.readRebootEscrowServerBlob();
+    public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException {
+        if (mServerBlob == null) {
+            mServerBlob = mStorage.readRebootEscrowServerBlob();
+        }
         // Delete the server blob in storage.
         mStorage.removeRebootEscrowServerBlob();
-        if (serverBlob == null) {
+        if (mServerBlob == null) {
             Slog.w(TAG, "Failed to read reboot escrow server blob from storage");
             return null;
         }
+        if (decryptionKey == null) {
+            Slog.w(TAG, "Failed to decrypt the escrow key; decryption key from keystore is"
+                    + " null.");
+            return null;
+        }
 
+        Slog.i(TAG, "Loaded reboot escrow server blob from storage");
         try {
-            byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey);
+            byte[] escrowKeyBytes = unwrapServerBlob(mServerBlob, decryptionKey);
             if (escrowKeyBytes == null) {
                 Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null");
                 return null;
@@ -145,7 +155,7 @@
             }
 
             return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
-        } catch (TimeoutException | RemoteException | IOException e) {
+        } catch (TimeoutException | RemoteException e) {
             Slog.w(TAG, "Failed to decrypt the server blob ", e);
             return null;
         }
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index a1e18bd..9c471b8 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -31,6 +31,7 @@
 import android.os.ParcelableException;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.service.resumeonreboot.IResumeOnRebootService;
@@ -55,6 +56,10 @@
             Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
     private static final String TAG = "ResumeOnRebootServiceProvider";
 
+    // The system property name that overrides the default service provider package name.
+    static final String PROP_ROR_PROVIDER_PACKAGE =
+            "persist.sys.resume_on_reboot_provider_package";
+
     private final Context mContext;
     private final PackageManager mPackageManager;
 
@@ -72,12 +77,19 @@
     private ServiceInfo resolveService() {
         Intent intent = new Intent();
         intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
-        if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
-            intent.setPackage(PROVIDER_PACKAGE);
+        int queryFlag = PackageManager.GET_SERVICES;
+        String testAppName = SystemProperties.get(PROP_ROR_PROVIDER_PACKAGE, "");
+        if (!testAppName.isEmpty()) {
+            Slog.i(TAG, "Using test app: " + testAppName);
+            intent.setPackage(testAppName);
+        } else {
+            queryFlag |= PackageManager.MATCH_SYSTEM_ONLY;
+            if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+                intent.setPackage(PROVIDER_PACKAGE);
+            }
         }
 
-        List<ResolveInfo> resolvedIntents =
-                mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+        List<ResolveInfo> resolvedIntents = mPackageManager.queryIntentServices(intent, queryFlag);
         for (ResolveInfo resolvedInfo : resolvedIntents) {
             if (resolvedInfo.serviceInfo != null
                     && PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
@@ -120,6 +132,7 @@
             if (mServiceConnection != null) {
                 mContext.unbindService(mServiceConnection);
             }
+            mBinder = null;
         }
 
         /** Bind to the service */
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index 6d420a9..35e6489 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -18,7 +18,6 @@
 
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
-import android.security.keystore2.AndroidKeyStoreProvider;
 import android.util.Slog;
 
 import java.io.ByteArrayOutputStream;
@@ -141,19 +140,8 @@
         }
     }
 
-    /**
-     * TODO This function redirects keystore access to the legacy keystore during a transitional
-     *      phase during which not all calling code has been adjusted to use Keystore 2.0.
-     *      This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete.
-     *      The specific bug for this component is b/171305115.
-     */
     static String androidKeystoreProviderName() {
-        if (AndroidKeyStoreProvider.isInstalled()) {
-            return "AndroidKeyStoreLegacy";
-        } else {
-            return "AndroidKeystore";
-        }
-
+        return "AndroidKeyStore";
     }
 
     public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 6d1c680..3cc32be 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,10 +16,10 @@
 
 package com.android.server.net;
 
-import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
 import static android.provider.Settings.ACTION_VPN_SETTINGS;
 
-import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,43 +28,37 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.Network;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
-import com.android.server.ConnectivityService;
-import com.android.server.EventLogTags;
 import com.android.server.connectivity.Vpn;
 
 import java.util.List;
 import java.util.Objects;
 
 /**
- * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be
- * connected and kicks off VPN connection, managing any required {@code netd}
- * firewall rules.
+ * State tracker for legacy lockdown VPN. Watches for physical networks to be
+ * connected and kicks off VPN connection.
  */
 public class LockdownVpnTracker {
     private static final String TAG = "LockdownVpnTracker";
 
-    /** Number of VPN attempts before waiting for user intervention. */
-    private static final int MAX_ERROR_COUNT = 4;
-
     public static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
 
     @NonNull private final Context mContext;
-    @NonNull private final ConnectivityService mConnService;
+    @NonNull private final ConnectivityManager mCm;
     @NonNull private final NotificationManager mNotificationManager;
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
@@ -76,19 +70,73 @@
     @NonNull private final PendingIntent mConfigIntent;
     @NonNull private final PendingIntent mResetIntent;
 
+    @NonNull private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback();
+    @NonNull private final VpnNetworkCallback mVpnNetworkCallback = new VpnNetworkCallback();
+
+    private class NetworkCallback extends ConnectivityManager.NetworkCallback {
+        private Network mNetwork = null;
+        private LinkProperties mLinkProperties = null;
+
+        @Override
+        public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
+            boolean networkChanged = false;
+            if (!network.equals(mNetwork)) {
+                // The default network just changed.
+                mNetwork = network;
+                networkChanged = true;
+            }
+            mLinkProperties = lp;
+            // Backwards compatibility: previously, LockdownVpnTracker only responded to connects
+            // and disconnects, not LinkProperties changes on existing networks.
+            if (networkChanged) {
+                synchronized (mStateLock) {
+                    handleStateChangedLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            // The default network has gone down.
+            mNetwork = null;
+            mLinkProperties = null;
+            synchronized (mStateLock) {
+                handleStateChangedLocked();
+            }
+        }
+
+        public Network getNetwork() {
+            return mNetwork;
+        }
+
+        public LinkProperties getLinkProperties() {
+            return mLinkProperties;
+        }
+    }
+
+    private class VpnNetworkCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            synchronized (mStateLock) {
+                handleStateChangedLocked();
+            }
+        }
+        @Override
+        public void onLost(Network network) {
+            onAvailable(network);
+        }
+    }
+
     @Nullable
     private String mAcceptedEgressIface;
 
-    private int mErrorCount;
-
     public LockdownVpnTracker(@NonNull Context context,
-            @NonNull ConnectivityService connService,
             @NonNull Handler handler,
             @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
-        mConnService = Objects.requireNonNull(connService);
+        mCm = mContext.getSystemService(ConnectivityManager.class);
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
@@ -110,24 +158,20 @@
      * connection when ready, or setting firewall rules once VPN is connected.
      */
     private void handleStateChangedLocked() {
-
-        final NetworkInfo egressInfo = mConnService.getActiveNetworkInfoUnfiltered();
-        final LinkProperties egressProp = mConnService.getActiveLinkProperties();
+        final Network network = mDefaultNetworkCallback.getNetwork();
+        final LinkProperties egressProp = mDefaultNetworkCallback.getLinkProperties();
 
         final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
         final VpnConfig vpnConfig = mVpn.getLegacyVpnConfig();
 
         // Restart VPN when egress network disconnected or changed
-        final boolean egressDisconnected = egressInfo == null
-                || State.DISCONNECTED.equals(egressInfo.getState());
+        final boolean egressDisconnected = (network == null);
         final boolean egressChanged = egressProp == null
                 || !TextUtils.equals(mAcceptedEgressIface, egressProp.getInterfaceName());
 
-        final int egressType = (egressInfo == null) ? TYPE_NONE : egressInfo.getType();
         final String egressIface = (egressProp == null) ?
                 null : egressProp.getInterfaceName();
-        Log.d(TAG, "handleStateChanged: egress=" + egressType
-                + " " + mAcceptedEgressIface + "->" + egressIface);
+        Log.d(TAG, "handleStateChanged: egress=" + mAcceptedEgressIface + "->" + egressIface);
 
         if (egressDisconnected || egressChanged) {
             mAcceptedEgressIface = null;
@@ -138,46 +182,49 @@
             return;
         }
 
-        if (vpnInfo.getDetailedState() == DetailedState.FAILED) {
-            EventLogTags.writeLockdownVpnError(egressType);
-        }
-
-        if (mErrorCount > MAX_ERROR_COUNT) {
-            showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
-
-        } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) {
-            if (mProfile.isValidLockdownProfile()) {
-                Log.d(TAG, "Active network connected; starting VPN");
-                EventLogTags.writeLockdownVpnConnecting(egressType);
-                showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
-
-                mAcceptedEgressIface = egressProp.getInterfaceName();
-                try {
-                    // Use the privileged method because Lockdown VPN is initiated by the system, so
-                    // no additional permission checks are necessary.
-                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, null, egressProp);
-                } catch (IllegalStateException e) {
-                    mAcceptedEgressIface = null;
-                    Log.e(TAG, "Failed to start VPN", e);
-                    showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
-                }
-            } else {
+        // At this point, |network| is known to be non-null.
+        if (!vpnInfo.isConnectedOrConnecting()) {
+            if (!mProfile.isValidLockdownProfile()) {
                 Log.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
                 showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
+                return;
             }
 
+            Log.d(TAG, "Active network connected; starting VPN");
+            showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
+
+            mAcceptedEgressIface = egressIface;
+            try {
+                // Use the privileged method because Lockdown VPN is initiated by the system, so
+                // no additional permission checks are necessary.
+                //
+                // Pass in the underlying network here because the legacy VPN is, in fact, tightly
+                // coupled to a given underlying network and cannot provide mobility. This makes
+                // things marginally more correct in two ways:
+                //
+                // 1. When the legacy lockdown VPN connects, LegacyTypeTracker broadcasts an extra
+                //    CONNECTED broadcast for the underlying network type. The underlying type comes
+                //    from here. LTT *could* assume that the underlying network is the default
+                //    network, but that might introduce a race condition if, say, the VPN starts
+                //    connecting on cell, but when the connection succeeds and the agent is
+                //    registered, the default network is now wifi.
+                // 2. If no underlying network is passed in, then CS will assume the underlying
+                //    network is the system default. So, if the VPN  is up and underlying network
+                //    (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have
+                //    changed to match the new default network (e.g., cell).
+                mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, network, egressProp);
+            } catch (IllegalStateException e) {
+                mAcceptedEgressIface = null;
+                Log.e(TAG, "Failed to start VPN", e);
+                showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
+            }
         } else if (vpnInfo.isConnected() && vpnConfig != null) {
             final String iface = vpnConfig.interfaze;
             final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
 
             Log.d(TAG, "VPN connected using iface=" + iface
                     + ", sourceAddr=" + sourceAddrs.toString());
-            EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
-
-            final NetworkInfo clone = new NetworkInfo(egressInfo);
-            augmentNetworkInfo(clone);
-            mConnService.sendConnectedBroadcast(clone);
         }
     }
 
@@ -192,7 +239,15 @@
 
         mVpn.setEnableTeardown(false);
         mVpn.setLockdown(true);
+        mCm.setLegacyLockdownVpnEnabled(true);
         handleStateChangedLocked();
+
+        mCm.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
+        final NetworkRequest vpnRequest = new NetworkRequest.Builder()
+                .clearCapabilities()
+                .addTransportType(TRANSPORT_VPN)
+                .build();
+        mCm.registerNetworkCallback(vpnRequest, mVpnNetworkCallback, mHandler);
     }
 
     public void shutdown() {
@@ -205,20 +260,21 @@
         Log.d(TAG, "shutdownLocked()");
 
         mAcceptedEgressIface = null;
-        mErrorCount = 0;
 
         mVpn.stopVpnRunnerPrivileged();
         mVpn.setLockdown(false);
+        mCm.setLegacyLockdownVpnEnabled(false);
         hideNotification();
 
         mVpn.setEnableTeardown(true);
+        mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
+        mCm.unregisterNetworkCallback(mVpnNetworkCallback);
     }
 
     /**
      * Reset VPN lockdown tracker. Called by ConnectivityService when receiving
      * {@link #ACTION_LOCKDOWN_RESET} pending intent.
      */
-    @GuardedBy("mConnService.mVpns")
     public void reset() {
         Log.d(TAG, "reset()");
         synchronized (mStateLock) {
@@ -229,28 +285,6 @@
         }
     }
 
-    public void onNetworkInfoChanged() {
-        synchronized (mStateLock) {
-            handleStateChangedLocked();
-        }
-    }
-
-    public void onVpnStateChanged(NetworkInfo info) {
-        if (info.getDetailedState() == DetailedState.FAILED) {
-            mErrorCount++;
-        }
-        synchronized (mStateLock) {
-            handleStateChangedLocked();
-        }
-    }
-
-    public void augmentNetworkInfo(NetworkInfo info) {
-        if (info.isConnected()) {
-            final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
-            info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
-        }
-    }
-
     private void showNotification(int titleRes, int iconRes) {
         final Notification.Builder builder =
                 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_VPN)
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index f92f3dc..39ed7e8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -16,8 +16,6 @@
 
 package com.android.server.net;
 
-import static com.android.server.net.NetworkPolicyManagerService.isUidNetworkingBlockedInternal;
-
 import android.annotation.NonNull;
 import android.net.Network;
 import android.net.NetworkTemplate;
@@ -39,28 +37,6 @@
     public abstract void resetUserState(int userId);
 
     /**
-     * Figure out if networking is blocked for a given set of conditions.
-     *
-     * This is used by ConnectivityService via passing stale copies of conditions, so it must not
-     * take any locks.
-     *
-     * @param uid The target uid.
-     * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
-     * @param isNetworkMetered True if the network is metered.
-     * @param isBackgroundRestricted True if data saver is enabled.
-     *
-     * @return true if networking is blocked for the UID under the specified conditions.
-     */
-    public static boolean isUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered,
-            boolean isBackgroundRestricted) {
-        // Log of invoking internal function is disabled because it will be called very
-        // frequently. And metrics are unlikely needed on this method because the callers are
-        // external and this method doesn't take any locks or perform expensive operations.
-        return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
-                isBackgroundRestricted, null);
-    }
-
-    /**
      * Informs that an appId has been added or removed from the temp-powersave-allowlist so that
      * that network rules for that appId can be updated.
      *
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0fd39a4..b5c0f28 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -70,6 +70,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
 import static android.net.NetworkPolicyManager.resolveNetworkId;
@@ -231,6 +232,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.ConcurrentUtils;
@@ -1253,7 +1255,7 @@
                 // identified carrier, which may want to manage their own notifications. This method
                 // should be called every time the carrier config changes anyways, and there's no
                 // reason to alert if there isn't a carrier.
-                return;
+                continue;
             }
 
             final boolean notifyWarning = getBooleanDefeatingNullable(config,
@@ -1960,14 +1962,13 @@
             if (state.network != null) {
                 mNetIdToSubId.put(state.network.netId, parseSubId(state));
             }
-            if (state.networkInfo != null && state.networkInfo.isConnected()) {
-                // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
-                // in the object created here is never used and its value doesn't matter, so use
-                // NETWORK_TYPE_UNKNOWN.
-                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
-                        true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
-                identified.put(state, ident);
-            }
+
+            // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+            // in the object created here is never used and its value doesn't matter, so use
+            // NETWORK_TYPE_UNKNOWN.
+            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+                    true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
+            identified.put(state, ident);
         }
 
         final ArraySet<String> newMeteredIfaces = new ArraySet<>();
@@ -2042,8 +2043,7 @@
         // One final pass to catch any metered ifaces that don't have explicitly
         // defined policies; typically Wi-Fi networks.
         for (NetworkState state : states) {
-            if (state.networkInfo != null && state.networkInfo.isConnected()
-                    && !state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+            if (!state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
                 matchingIfaces.clear();
                 collectIfaces(matchingIfaces, state);
                 for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
@@ -3488,13 +3488,27 @@
 
     @Override
     public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
-            long timeoutMillis, String callingPackage) {
+            int[] networkTypes, long timeoutMillis, String callingPackage) {
         enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
 
-        // We can only override when carrier told us about plans
+        final ArraySet<Integer> allNetworksSet = new ArraySet<>();
+        addAll(allNetworksSet, TelephonyManager.getAllNetworkTypes());
+        final IntArray applicableNetworks = new IntArray();
+
+        // ensure all network types are valid
+        for (int networkType : networkTypes) {
+            if (allNetworksSet.contains(networkType)) {
+                applicableNetworks.add(networkType);
+            } else {
+                Log.d(TAG, "setSubscriptionOverride removing invalid network type: " + networkType);
+            }
+        }
+
+        // We can only override when carrier told us about plans. For the unmetered case,
+        // allow override without having plans defined.
         synchronized (mNetworkPoliciesSecondLock) {
             final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
-            if (plan == null
+            if (overrideMask != SUBSCRIPTION_OVERRIDE_UNMETERED && plan == null
                     || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
                 throw new IllegalStateException(
                         "Must provide valid SubscriptionPlan to enable overriding");
@@ -3506,11 +3520,16 @@
         final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 NETPOLICY_OVERRIDE_ENABLED, 1) != 0;
         if (overrideEnabled || overrideValue == 0) {
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
-                    overrideMask, overrideValue, subId));
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = subId;
+            args.arg2 = overrideMask;
+            args.arg3 = overrideValue;
+            args.arg4 = applicableNetworks.toArray();
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args));
             if (timeoutMillis > 0) {
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
-                        overrideMask, 0, subId), timeoutMillis);
+                args.arg3 = 0;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args),
+                        timeoutMillis);
             }
         }
     }
@@ -4778,10 +4797,10 @@
     }
 
     private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
-            int overrideMask, int overrideValue) {
+            int overrideMask, int overrideValue, int[] networkTypes) {
         if (listener != null) {
             try {
-                listener.onSubscriptionOverride(subId, overrideMask, overrideValue);
+                listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
             } catch (RemoteException ignored) {
             }
         }
@@ -4913,13 +4932,16 @@
                     return true;
                 }
                 case MSG_SUBSCRIPTION_OVERRIDE: {
-                    final int overrideMask = msg.arg1;
-                    final int overrideValue = msg.arg2;
-                    final int subId = (int) msg.obj;
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final int subId = (int) args.arg1;
+                    final int overrideMask = (int) args.arg2;
+                    final int overrideValue = (int) args.arg3;
+                    final int[] networkTypes = (int[]) args.arg4;
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
-                        dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue);
+                        dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue,
+                                networkTypes);
                     }
                     mListeners.finishBroadcast();
                     return true;
@@ -5380,6 +5402,17 @@
     }
 
     @Override
+    public boolean checkUidNetworkingBlocked(int uid, int uidRules,
+            boolean isNetworkMetered, boolean isBackgroundRestricted) {
+        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+        // Log of invoking this function is disabled because it will be called very frequently. And
+        // metrics are unlikely needed on this method because the callers are external and this
+        // method doesn't take any locks or perform expensive operations.
+        return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
+                isBackgroundRestricted, null);
+    }
+
+    @Override
     public boolean isUidRestrictedOnMeteredNetworks(int uid) {
         mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         final int uidRules;
@@ -5388,9 +5421,9 @@
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             isBackgroundRestricted = mRestrictBackground;
         }
-        //TODO(b/177490332): The logic here might not be correct because it doesn't consider
-        // RULE_REJECT_METERED condition. And it could be replaced by
-        // isUidNetworkingBlockedInternal().
+        // TODO(b/177490332): The logic here might not be correct because it doesn't consider
+        //  RULE_REJECT_METERED condition. And it could be replaced by
+        //  isUidNetworkingBlockedInternal().
         return isBackgroundRestricted
                 && !hasRule(uidRules, RULE_ALLOW_METERED)
                 && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0ab35a9..9706bce 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -96,7 +96,6 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
-import android.net.NetworkInfo;
 import android.net.NetworkStack;
 import android.net.NetworkState;
 import android.net.NetworkStats;
@@ -1264,7 +1263,7 @@
 
     /**
      * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link
-     * NetworkStatsHistory}. When multiple {@link NetworkInfo} are active on a single {@code iface},
+     * NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
      * they are combined under a single {@link NetworkIdentitySet}.
      */
     @GuardedBy("mStatsLock")
@@ -1294,84 +1293,82 @@
         final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
         for (NetworkState state : states) {
-            if (state.networkInfo.isConnected()) {
-                final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
-                final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
-                final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
-                        : getSubTypeForState(state);
-                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
-                        isDefault, subType);
+            final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType);
+            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+            final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
+                    : getSubTypeForState(state);
+            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+                    isDefault, subType);
 
-                // Traffic occurring on the base interface is always counted for
-                // both total usage and UID details.
-                final String baseIface = state.linkProperties.getInterfaceName();
-                if (baseIface != null) {
-                    findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
-                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
+            // Traffic occurring on the base interface is always counted for
+            // both total usage and UID details.
+            final String baseIface = state.linkProperties.getInterfaceName();
+            if (baseIface != null) {
+                findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
+                findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
 
-                    // Build a separate virtual interface for VT (Video Telephony) data usage.
-                    // Only do this when IMS is not metered, but VT is metered.
-                    // If IMS is metered, then the IMS network usage has already included VT usage.
-                    // VT is considered always metered in framework's layer. If VT is not metered
-                    // per carrier's policy, modem will report 0 usage for VT calls.
-                    if (state.networkCapabilities.hasCapability(
-                            NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
+                // Build a separate virtual interface for VT (Video Telephony) data usage.
+                // Only do this when IMS is not metered, but VT is metered.
+                // If IMS is metered, then the IMS network usage has already included VT usage.
+                // VT is considered always metered in framework's layer. If VT is not metered
+                // per carrier's policy, modem will report 0 usage for VT calls.
+                if (state.networkCapabilities.hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
 
-                        // Copy the identify from IMS one but mark it as metered.
-                        NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
-                                ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
-                                ident.getRoaming(), true /* metered */,
-                                true /* onDefaultNetwork */);
-                        findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
-                        findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
-                    }
-
-                    if (isMobile) {
-                        mobileIfaces.add(baseIface);
-                    }
+                    // Copy the identify from IMS one but mark it as metered.
+                    NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
+                            ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
+                            ident.getRoaming(), true /* metered */,
+                            true /* onDefaultNetwork */);
+                    findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
+                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
                 }
 
-                // Traffic occurring on stacked interfaces is usually clatd.
-                //
-                // UID stats are always counted on the stacked interface and never on the base
-                // interface, because the packets on the base interface do not actually match
-                // application sockets (they're not IPv4) and thus the app uid is not known.
-                // For receive this is obvious: packets must be translated from IPv6 to IPv4
-                // before the application socket can be found.
-                // For transmit: either they go through the clat daemon which by virtue of going
-                // through userspace strips the original socket association during the IPv4 to
-                // IPv6 translation process, or they are offloaded by eBPF, which doesn't:
-                // However, on an ebpf device the accounting is done in cgroup ebpf hooks,
-                // which don't trigger again post ebpf translation.
-                // (as such stats accounted to the clat uid are ignored)
-                //
-                // Interface stats are more complicated.
-                //
-                // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus
-                // *all* statistics are collected by iptables on the stacked v4-* interface.
-                //
-                // Additionally for ingress all packets bound for the clat IPv6 address are dropped
-                // in ip6tables raw prerouting and thus even non-offloaded packets are only
-                // accounted for on the stacked interface.
-                //
-                // For egress, packets subject to eBPF offload never appear on the base interface
-                // and only appear on the stacked interface. Thus to ensure packets increment
-                // interface stats, we must collate data from stacked interfaces. For xt_qtaguid
-                // (or non eBPF offloaded) TX they would appear on both, however egress interface
-                // accounting is explicitly bypassed for traffic from the clat uid.
-                //
-                final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
-                for (LinkProperties stackedLink : stackedLinks) {
-                    final String stackedIface = stackedLink.getInterfaceName();
-                    if (stackedIface != null) {
-                        findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
-                        findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
-                        if (isMobile) {
-                            mobileIfaces.add(stackedIface);
-                        }
+                if (isMobile) {
+                    mobileIfaces.add(baseIface);
+                }
+            }
 
-                        mStatsFactory.noteStackedIface(stackedIface, baseIface);
+            // Traffic occurring on stacked interfaces is usually clatd.
+            //
+            // UID stats are always counted on the stacked interface and never on the base
+            // interface, because the packets on the base interface do not actually match
+            // application sockets (they're not IPv4) and thus the app uid is not known.
+            // For receive this is obvious: packets must be translated from IPv6 to IPv4
+            // before the application socket can be found.
+            // For transmit: either they go through the clat daemon which by virtue of going
+            // through userspace strips the original socket association during the IPv4 to
+            // IPv6 translation process, or they are offloaded by eBPF, which doesn't:
+            // However, on an ebpf device the accounting is done in cgroup ebpf hooks,
+            // which don't trigger again post ebpf translation.
+            // (as such stats accounted to the clat uid are ignored)
+            //
+            // Interface stats are more complicated.
+            //
+            // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus
+            // *all* statistics are collected by iptables on the stacked v4-* interface.
+            //
+            // Additionally for ingress all packets bound for the clat IPv6 address are dropped
+            // in ip6tables raw prerouting and thus even non-offloaded packets are only
+            // accounted for on the stacked interface.
+            //
+            // For egress, packets subject to eBPF offload never appear on the base interface
+            // and only appear on the stacked interface. Thus to ensure packets increment
+            // interface stats, we must collate data from stacked interfaces. For xt_qtaguid
+            // (or non eBPF offloaded) TX they would appear on both, however egress interface
+            // accounting is explicitly bypassed for traffic from the clat uid.
+            //
+            final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
+            for (LinkProperties stackedLink : stackedLinks) {
+                final String stackedIface = stackedLink.getInterfaceName();
+                if (stackedIface != null) {
+                    findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
+                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
+                    if (isMobile) {
+                        mobileIfaces.add(stackedIface);
                     }
+
+                    mStatsFactory.noteStackedIface(stackedIface, baseIface);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index c3cb42f..45419fe 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,8 +22,8 @@
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5417275..2067fd0 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,8 +21,8 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
 import static android.service.notification.DNDModeProto.ROOT_CONFIG;
+import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 
 import android.app.AppOpsManager;
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
new file mode 100644
index 0000000..9c4c510
--- /dev/null
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -0,0 +1,550 @@
+/*
+ * 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 com.android.server.os;
+
+import static android.app.ApplicationExitInfo.REASON_CRASH_NATIVE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+
+import android.annotation.AppIdInt;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ApplicationExitInfo;
+import android.app.IParcelFileDescriptorRetriever;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.FileObserver;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoParseException;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.BootReceiver;
+import com.android.server.ServiceThread;
+import com.android.server.os.TombstoneProtos.Cause;
+import com.android.server.os.TombstoneProtos.Tombstone;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A class to manage native tombstones.
+ */
+public final class NativeTombstoneManager {
+    private static final String TAG = NativeTombstoneManager.class.getSimpleName();
+
+    private static final File TOMBSTONE_DIR = new File("/data/tombstones");
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final TombstoneWatcher mWatcher;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final SparseArray<TombstoneFile> mTombstones;
+
+    NativeTombstoneManager(Context context) {
+        mTombstones = new SparseArray<TombstoneFile>();
+        mContext = context;
+
+        final ServiceThread thread = new ServiceThread(TAG + ":tombstoneWatcher",
+                THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+        thread.start();
+        mHandler = thread.getThreadHandler();
+
+        mWatcher = new TombstoneWatcher();
+        mWatcher.startWatching();
+    }
+
+    void onSystemReady() {
+        registerForUserRemoval();
+        registerForPackageRemoval();
+
+        // Scan existing tombstones.
+        mHandler.post(() -> {
+            final File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
+            for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
+                if (tombstoneFiles[i].isFile()) {
+                    handleTombstone(tombstoneFiles[i]);
+                }
+            }
+        });
+    }
+
+    private void handleTombstone(File path) {
+        final String filename = path.getName();
+        if (!filename.startsWith("tombstone_")) {
+            return;
+        }
+
+        if (filename.endsWith(".pb")) {
+            handleProtoTombstone(path);
+            BootReceiver.addTombstoneToDropBox(mContext, path, true);
+        } else {
+            BootReceiver.addTombstoneToDropBox(mContext, path, false);
+        }
+    }
+
+    private void handleProtoTombstone(File path) {
+        final String filename = path.getName();
+        if (!filename.endsWith(".pb")) {
+            Slog.w(TAG, "unexpected tombstone name: " + path);
+            return;
+        }
+
+        final String suffix = filename.substring("tombstone_".length());
+        final String numberStr = suffix.substring(0, suffix.length() - 3);
+
+        int number;
+        try {
+            number = Integer.parseInt(numberStr);
+            if (number < 0 || number > 99) {
+                Slog.w(TAG, "unexpected tombstone name: " + path);
+                return;
+            }
+        } catch (NumberFormatException ex) {
+            Slog.w(TAG, "unexpected tombstone name: " + path);
+            return;
+        }
+
+        ParcelFileDescriptor pfd;
+        try {
+            pfd = ParcelFileDescriptor.open(path, MODE_READ_WRITE);
+        } catch (FileNotFoundException ex) {
+            Slog.w(TAG, "failed to open " + path, ex);
+            return;
+        }
+
+        final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd);
+        if (!parsedTombstone.isPresent()) {
+            IoUtils.closeQuietly(pfd);
+            return;
+        }
+
+        synchronized (mLock) {
+            TombstoneFile previous = mTombstones.get(number);
+            if (previous != null) {
+                previous.dispose();
+            }
+
+            mTombstones.put(number, parsedTombstone.get());
+        }
+    }
+
+    /**
+     * Remove native tombstones matching a user and/or app.
+     *
+     * @param userId user id to filter by, selects all users if empty
+     * @param appId app id to filter by, selects all users if empty
+     */
+    public void purge(Optional<Integer> userId, Optional<Integer> appId) {
+        mHandler.post(() -> {
+            synchronized (mLock) {
+                for (int i = mTombstones.size() - 1; i >= 0; --i) {
+                    TombstoneFile tombstone = mTombstones.valueAt(i);
+                    if (tombstone.matches(userId, appId)) {
+                        tombstone.purge();
+                        mTombstones.removeAt(i);
+                    }
+                }
+            }
+        });
+    }
+
+    private void purgePackage(int uid, boolean allUsers) {
+        final int appId = UserHandle.getAppId(uid);
+        Optional<Integer> userId;
+        if (allUsers) {
+            userId = Optional.empty();
+        } else {
+            userId = Optional.of(UserHandle.getUserId(uid));
+        }
+        purge(userId, Optional.of(appId));
+    }
+
+    private void purgeUser(int uid) {
+        purge(Optional.of(uid), Optional.empty());
+    }
+
+    private void registerForPackageRemoval() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+        filter.addDataScheme("package");
+        mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int uid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
+                if (uid == UserHandle.USER_NULL) return;
+
+                final boolean allUsers = intent.getBooleanExtra(
+                        Intent.EXTRA_REMOVED_FOR_ALL_USERS, false);
+
+                purgePackage(uid, allUsers);
+            }
+        }, filter, null, mHandler);
+    }
+
+    private void registerForUserRemoval() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                if (userId < 1) return;
+
+                purgeUser(userId);
+            }
+        }, filter, null, mHandler);
+    }
+
+    /**
+     * Collect native tombstones.
+     *
+     * @param output list to append to
+     * @param callingUid POSIX uid to filter by
+     * @param pid pid to filter by, ignored if zero
+     * @param maxNum maximum number of elements in output
+     */
+    public void collectTombstones(ArrayList<ApplicationExitInfo> output, int callingUid, int pid,
+            int maxNum) {
+        CompletableFuture<Object> future = new CompletableFuture<>();
+
+        if (!UserHandle.isApp(callingUid)) {
+            return;
+        }
+
+        final int userId = UserHandle.getUserId(callingUid);
+        final int appId = UserHandle.getAppId(callingUid);
+
+        mHandler.post(() -> {
+            boolean appendedTombstones = false;
+
+            synchronized (mLock) {
+                final int tombstonesSize = mTombstones.size();
+
+            tombstoneIter:
+                for (int i = 0; i < tombstonesSize; ++i) {
+                    TombstoneFile tombstone = mTombstones.valueAt(i);
+                    if (tombstone.matches(Optional.of(userId), Optional.of(appId))) {
+                        if (pid != 0 && tombstone.mPid != pid) {
+                            continue;
+                        }
+
+                        // Try to attach to an existing REASON_CRASH_NATIVE.
+                        final int outputSize = output.size();
+                        for (int j = 0; j < outputSize; ++j) {
+                            ApplicationExitInfo exitInfo = output.get(j);
+                            if (tombstone.matches(exitInfo)) {
+                                exitInfo.setNativeTombstoneRetriever(tombstone.getPfdRetriever());
+                                continue tombstoneIter;
+                            }
+                        }
+
+                        if (output.size() < maxNum) {
+                            appendedTombstones = true;
+                            output.add(tombstone.toAppExitInfo());
+                        }
+                    }
+                }
+            }
+
+            if (appendedTombstones) {
+                Collections.sort(output, (lhs, rhs) -> {
+                    // Reports should be ordered with newest reports first.
+                    long diff = rhs.getTimestamp() - lhs.getTimestamp();
+                    if (diff < 0) {
+                        return -1;
+                    } else if (diff == 0) {
+                        return 0;
+                    } else {
+                        return 1;
+                    }
+                });
+            }
+            future.complete(null);
+        });
+
+        try {
+            future.get();
+        } catch (ExecutionException | InterruptedException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    static class TombstoneFile {
+        final ParcelFileDescriptor mPfd;
+
+        @UserIdInt int mUserId;
+        @AppIdInt int mAppId;
+
+        int mPid;
+        int mUid;
+        String mProcessName;
+        @CurrentTimeMillisLong long mTimestampMs;
+        String mCrashReason;
+
+        boolean mPurged = false;
+        final IParcelFileDescriptorRetriever mRetriever = new ParcelFileDescriptorRetriever();
+
+        TombstoneFile(ParcelFileDescriptor pfd) {
+            mPfd = pfd;
+        }
+
+        public boolean matches(Optional<Integer> userId, Optional<Integer> appId) {
+            if (mPurged) {
+                return false;
+            }
+
+            if (userId.isPresent() && userId.get() != mUserId) {
+                return false;
+            }
+
+            if (appId.isPresent() && appId.get() != mAppId) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public boolean matches(ApplicationExitInfo exitInfo) {
+            if (exitInfo.getReason() != REASON_CRASH_NATIVE) {
+                return false;
+            }
+
+            if (exitInfo.getPid() != mPid) {
+                return false;
+            }
+
+            if (exitInfo.getRealUid() != mUid) {
+                return false;
+            }
+
+            if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 1000) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public void dispose() {
+            IoUtils.closeQuietly(mPfd);
+        }
+
+        public void purge() {
+            if (!mPurged) {
+                // There's no way to atomically unlink a specific file for which we have an fd from
+                // a path, which means that we can't safely delete a tombstone without coordination
+                // with tombstoned (which has a risk of deadlock if for example, system_server hangs
+                // with a flock). Do the next best thing, and just truncate the file.
+                //
+                // We don't have to worry about inflicting a SIGBUS on a process that has the
+                // tombstone mmaped, because we only clear if the package has been removed, which
+                // means no one with access to the tombstone should be left.
+                try {
+                    Os.ftruncate(mPfd.getFileDescriptor(), 0);
+                } catch (ErrnoException ex) {
+                    Slog.e(TAG, "Failed to truncate tombstone", ex);
+                }
+                mPurged = true;
+            }
+        }
+
+        static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) {
+            final FileInputStream is = new FileInputStream(pfd.getFileDescriptor());
+            final ProtoInputStream stream = new ProtoInputStream(is);
+
+            int pid = 0;
+            int uid = 0;
+            String processName = "";
+            String crashReason = "";
+            String selinuxLabel = "";
+
+            try {
+                while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    switch (stream.getFieldNumber()) {
+                        case (int) Tombstone.PID:
+                            pid = stream.readInt(Tombstone.PID);
+                            break;
+
+                        case (int) Tombstone.UID:
+                            uid = stream.readInt(Tombstone.UID);
+                            break;
+
+                        case (int) Tombstone.PROCESS_NAME:
+                            processName = stream.readString(Tombstone.PROCESS_NAME);
+                            break;
+
+                        case (int) Tombstone.CAUSE:
+                            long token = stream.start(Tombstone.CAUSE);
+                        cause:
+                            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                                switch (stream.getFieldNumber()) {
+                                    case (int) Cause.HUMAN_READABLE:
+                                        crashReason = stream.readString(Cause.HUMAN_READABLE);
+                                        break cause;
+
+                                    default:
+                                        break;
+                                }
+                            }
+                            stream.end(token);
+                            break;
+
+                        case (int) Tombstone.SELINUX_LABEL:
+                            selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL);
+                            break;
+
+                        default:
+                            break;
+                    }
+                }
+            } catch (IOException | ProtoParseException ex) {
+                Slog.e(TAG, "Failed to parse tombstone", ex);
+                return Optional.empty();
+            }
+
+            if (!UserHandle.isApp(uid)) {
+                Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring");
+                return Optional.empty();
+            }
+
+            long timestampMs = 0;
+            try {
+                StructStat stat = Os.fstat(pfd.getFileDescriptor());
+                timestampMs = stat.st_atim.tv_sec * 1000 + stat.st_atim.tv_nsec / 1000000;
+            } catch (ErrnoException ex) {
+                Slog.e(TAG, "Failed to get timestamp of tombstone", ex);
+            }
+
+            final int userId = UserHandle.getUserId(uid);
+            final int appId = UserHandle.getAppId(uid);
+
+            if (!selinuxLabel.startsWith("u:r:untrusted_app")) {
+                Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring");
+                return Optional.empty();
+            }
+
+            TombstoneFile result = new TombstoneFile(pfd);
+
+            result.mUserId = userId;
+            result.mAppId = appId;
+            result.mPid = pid;
+            result.mUid = uid;
+            result.mProcessName = processName;
+            result.mTimestampMs = timestampMs;
+            result.mCrashReason = crashReason;
+
+            return Optional.of(result);
+        }
+
+        public IParcelFileDescriptorRetriever getPfdRetriever() {
+            return mRetriever;
+        }
+
+        public ApplicationExitInfo toAppExitInfo() {
+            ApplicationExitInfo info = new ApplicationExitInfo();
+            info.setPid(mPid);
+            info.setRealUid(mUid);
+            info.setPackageUid(mUid);
+            info.setDefiningUid(mUid);
+            info.setProcessName(mProcessName);
+            info.setReason(ApplicationExitInfo.REASON_CRASH_NATIVE);
+
+            // Signal numbers are architecture-specific!
+            // We choose to provide nothing here, to avoid leading users astray.
+            info.setStatus(0);
+
+            // No way for us to find out.
+            info.setImportance(RunningAppProcessInfo.IMPORTANCE_GONE);
+            info.setPackageName("");
+            info.setProcessStateSummary(null);
+
+            // We could find out, but they didn't get OOM-killed...
+            info.setPss(0);
+            info.setRss(0);
+
+            info.setTimestamp(mTimestampMs);
+            info.setDescription(mCrashReason);
+
+            info.setSubReason(ApplicationExitInfo.SUBREASON_UNKNOWN);
+            info.setNativeTombstoneRetriever(mRetriever);
+
+            return info;
+        }
+
+
+        class ParcelFileDescriptorRetriever extends IParcelFileDescriptorRetriever.Stub {
+            ParcelFileDescriptorRetriever() {}
+
+            public @Nullable ParcelFileDescriptor getPfd() {
+                if (mPurged) {
+                    return null;
+                }
+
+                // Reopen the file descriptor as read-only.
+                try {
+                    final String path = "/proc/self/fd/" + mPfd.getFd();
+                    ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(path),
+                            MODE_READ_ONLY);
+                    return pfd;
+                } catch (FileNotFoundException ex) {
+                    Slog.e(TAG, "failed to reopen file descriptor as read-only", ex);
+                    return null;
+                }
+            }
+        }
+    }
+
+    class TombstoneWatcher extends FileObserver {
+        TombstoneWatcher() {
+            // Tombstones can be created either by linking an O_TMPFILE temporary file (CREATE),
+            // or by moving a named temporary file in the same directory on kernels where O_TMPFILE
+            // isn't supported (MOVED_TO).
+            super(TOMBSTONE_DIR, FileObserver.CREATE | FileObserver.MOVED_TO);
+        }
+
+        @Override
+        public void onEvent(int event, @Nullable String path) {
+            mHandler.post(() -> {
+                handleTombstone(new File(TOMBSTONE_DIR, path));
+            });
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManagerService.java b/services/core/java/com/android/server/os/NativeTombstoneManagerService.java
new file mode 100644
index 0000000..cb3c7ff0
--- /dev/null
+++ b/services/core/java/com/android/server/os/NativeTombstoneManagerService.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.android.server.os;
+
+import android.content.Context;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+/**
+ * Service that tracks and manages native tombstones.
+ *
+ * @hide
+ */
+public class NativeTombstoneManagerService extends SystemService {
+    private static final String TAG = "NativeTombstoneManagerService";
+
+    private NativeTombstoneManager mManager;
+
+    public NativeTombstoneManagerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        mManager = new NativeTombstoneManager(getContext());
+        LocalServices.addService(NativeTombstoneManager.class, mManager);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+            mManager.onSystemReady();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 48ec9b4..acec93c 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -241,7 +241,7 @@
             // trade-off worth doing to save boot time work.
             int result = pm.performDexOptWithStatus(new DexoptOptions(
                     pkg,
-                    PackageManagerService.REASON_BOOT,
+                    PackageManagerService.REASON_POST_BOOT,
                     DexoptOptions.DEXOPT_BOOT_COMPLETE));
             if (result == PackageDexOptimizer.DEX_OPT_PERFORMED)  {
                 updatedPackages.add(pkg);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 7960735..4a2fb5d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -687,7 +687,8 @@
         boolean generateCompactDex = true;
         switch (compilationReason) {
             case PackageManagerService.REASON_FIRST_BOOT:
-            case PackageManagerService.REASON_BOOT:
+            case PackageManagerService.REASON_BOOT_AFTER_OTA:
+            case PackageManagerService.REASON_POST_BOOT:
             case PackageManagerService.REASON_INSTALL:
                  generateCompactDex = false;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 330f995..9f0efa5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -299,6 +299,10 @@
         final ArraySet<File> unclaimedStages = newArraySet(
                 stagingDir.listFiles(sStageFilter));
 
+        // We also need to clean up orphaned staging directory for staged sessions
+        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
+        unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
+
         // Ignore stages claimed by active sessions
         for (int i = 0; i < mSessions.size(); i++) {
             final PackageInstallerSession session = mSessions.valueAt(i);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6594a90..ae2e58f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1598,6 +1598,10 @@
         destroyInternal();
         // Dispatch message to remove session from PackageInstallerService.
         dispatchSessionFinished(error, detailMessage, null);
+        // TODO(b/173194203): clean up staged session in destroyInternal() call instead
+        if (isStaged() && stageDir != null) {
+            cleanStageDir();
+        }
     }
 
     private void onStorageUnhealthy() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a7b9622..febbfbc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -676,17 +676,18 @@
     // Compilation reasons.
     public static final int REASON_UNKNOWN = -1;
     public static final int REASON_FIRST_BOOT = 0;
-    public static final int REASON_BOOT = 1;
-    public static final int REASON_INSTALL = 2;
-    public static final int REASON_INSTALL_FAST = 3;
-    public static final int REASON_INSTALL_BULK = 4;
-    public static final int REASON_INSTALL_BULK_SECONDARY = 5;
-    public static final int REASON_INSTALL_BULK_DOWNGRADED = 6;
-    public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 7;
-    public static final int REASON_BACKGROUND_DEXOPT = 8;
-    public static final int REASON_AB_OTA = 9;
-    public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 10;
-    public static final int REASON_SHARED = 11;
+    public static final int REASON_BOOT_AFTER_OTA = 1;
+    public static final int REASON_POST_BOOT = 2;
+    public static final int REASON_INSTALL = 3;
+    public static final int REASON_INSTALL_FAST = 4;
+    public static final int REASON_INSTALL_BULK = 5;
+    public static final int REASON_INSTALL_BULK_SECONDARY = 6;
+    public static final int REASON_INSTALL_BULK_DOWNGRADED = 7;
+    public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 8;
+    public static final int REASON_BACKGROUND_DEXOPT = 9;
+    public static final int REASON_AB_OTA = 10;
+    public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11;
+    public static final int REASON_SHARED = 12;
 
     public static final int REASON_LAST = REASON_SHARED;
 
@@ -9664,10 +9665,7 @@
         //       first boot, as they do not have profile data.
         boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
 
-        // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
-        boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
-
-        if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
+        if (!causeUpgrade && !causeFirstBoot) {
             return;
         }
 
@@ -9684,7 +9682,7 @@
 
         final long startTime = System.nanoTime();
         final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
-                    causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
+                    causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT_AFTER_OTA,
                     false /* bootComplete */);
 
         final int elapsedTimeSeconds =
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 9cd55a6..636db11 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -29,7 +29,8 @@
     // Names for compilation reasons.
     public static final String REASON_STRINGS[] = {
         "first-boot",
-        "boot",
+        "boot-after-ota",
+        "post-boot",
         "install",
         "install-fast",
         "install-bulk",
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 6e145b5..7de5c94 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -587,7 +587,7 @@
     private static final int TRON_COMPILATION_REASON_ERROR = 0;
     private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
     private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
-    private static final int TRON_COMPILATION_REASON_BOOT = 3;
+    private static final int TRON_COMPILATION_REASON_BOOT_DEPRECATED_SINCE_S = 3;
     private static final int TRON_COMPILATION_REASON_INSTALL = 4;
     private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
     private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
@@ -605,6 +605,8 @@
     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18;
     private static final int
             TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
+    private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
+    private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
 
     // The annotation to add as a suffix to the compilation reason when dexopt was
     // performed with dex metadata.
@@ -618,7 +620,8 @@
             case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
             case "error" : return TRON_COMPILATION_REASON_ERROR;
             case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
-            case "boot" : return TRON_COMPILATION_REASON_BOOT;
+            case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
+            case "post-boot" : return TRON_COMPILATION_REASON_POST_BOOT;
             case "install" : return TRON_COMPILATION_REASON_INSTALL;
             case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index cc6d80a..6d3de96 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -215,7 +215,7 @@
                         searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
 
                 if (primaryOrSplit && !isUsedByOtherApps
-                        && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) {
+                        && !isPlatformPackage(searchResult.mOwningPackageName)) {
                     // If the dex file is the primary apk (or a split) and not isUsedByOtherApps
                     // do not record it. This case does not bring any new usable information
                     // and can be safely skipped.
@@ -232,15 +232,24 @@
                 }
 
                 String classLoaderContext = mapping.getValue();
+
+                // Overwrite the class loader context for system server (instead of merging it).
+                // We expect system server jars to only change contexts in between OTAs and to
+                // otherwise be stable.
+                // Instead of implementing a complex clear-context logic post OTA, it is much
+                // simpler to always override the context for system server. This way, the context
+                // will always be up to date and we will avoid merging which could lead to the
+                // the context being marked as variable and thus making dexopt non-optimal.
+                boolean overwriteCLC = isPlatformPackage(searchResult.mOwningPackageName);
+
                 if (classLoaderContext != null
                         && VMRuntime.isValidClassLoaderContext(classLoaderContext)) {
                     // Record dex file usage. If the current usage is a new pattern (e.g. new
                     // secondary, or UsedByOtherApps), record will return true and we trigger an
                     // async write to disk to make sure we don't loose the data in case of a reboot.
-
                     if (mPackageDexUsage.record(searchResult.mOwningPackageName,
                             dexPath, loaderUserId, loaderIsa, primaryOrSplit,
-                            loadingAppInfo.packageName, classLoaderContext)) {
+                            loadingAppInfo.packageName, classLoaderContext, overwriteCLC)) {
                         mPackageDexUsage.maybeWriteAsync();
                     }
                 }
@@ -474,7 +483,7 @@
      *         because they don't need to be compiled)..
      */
     public boolean dexoptSecondaryDex(DexoptOptions options) {
-        if (PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) {
+        if (isPlatformPackage(options.getPackageName())) {
             // We could easily redirect to #dexoptSystemServer in this case. But there should be
             // no-one calling this method directly for system server.
             // As such we prefer to abort in this case.
@@ -534,7 +543,7 @@
      * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded.
      */
     public int dexoptSystemServer(DexoptOptions options) {
-        if (!PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) {
+        if (!isPlatformPackage(options.getPackageName())) {
             Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:"
                     + options.getPackageName());
             return PackageDexOptimizer.DEX_OPT_FAILED;
@@ -662,7 +671,7 @@
             // Special handle system server files.
             // We don't need an installd call because we have permissions to check if the file
             // exists.
-            if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+            if (isPlatformPackage(packageName)) {
                 if (!Files.exists(Paths.get(dexPath))) {
                     if (DEBUG) {
                         Slog.w(TAG, "A dex file previously loaded by System Server does not exist "
@@ -739,7 +748,8 @@
             boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
                     dexPath, userId, isa, /*primaryOrSplit*/ false,
                     loadingPackage,
-                    PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
+                    PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT,
+                    /*overwriteCLC*/ false);
             update |= newUpdate;
         }
         if (update) {
@@ -809,7 +819,7 @@
         // Note: We don't have any way to detect which code paths are actually
         // owned by system server. We can only assume that such paths are on
         // system partitions.
-        if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) {
+        if (isPlatformPackage(loadingAppInfo.packageName)) {
             if (isSystemServerDexPathSupportedForOdex(dexPath)) {
                 // We record system server dex files as secondary dex files.
                 // The reason is that we only record the class loader context for secondary dex
@@ -842,6 +852,11 @@
         return new DexSearchResult(null, DEX_SEARCH_NOT_FOUND);
     }
 
+    /** Returns true if this is the platform package .*/
+    private static boolean isPlatformPackage(String packageName) {
+        return PLATFORM_PACKAGE_NAME.equals(packageName);
+    }
+
     private static <K,V> V putIfAbsent(Map<K,V> map, K key, V newValue) {
         V existingValue = map.putIfAbsent(key, newValue);
         return existingValue == null ? newValue : existingValue;
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 10760f5..3d63b75 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -111,17 +111,18 @@
      * @param dexPath the path of the dex files being loaded
      * @param ownerUserId the user id which runs the code loading the dex files
      * @param loaderIsa the ISA of the app loading the dex files
-     * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package
      * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates
      *        the file is either primary or a split. False indicates the file is secondary dex.
      * @param loadingPackageName the package performing the load. Recorded only if it is different
      *        than {@param owningPackageName}.
+     * @param overwriteCLC if true, the class loader context will be overwritten instead of being
+     *        merged
      * @return true if the dex load constitutes new information, or false if this information
      *         has been seen before.
      */
     /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId,
             String loaderIsa, boolean primaryOrSplit,
-            String loadingPackageName, String classLoaderContext) {
+            String loadingPackageName, String classLoaderContext, boolean overwriteCLC) {
         if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
             throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported");
         }
@@ -193,7 +194,7 @@
                         }
                         // Merge the information into the existing data.
                         // Returns true if there was an update.
-                        return existingData.merge(newData) || updateLoadingPackages;
+                        return existingData.merge(newData, overwriteCLC) || updateLoadingPackages;
                     }
                 }
             }
@@ -809,14 +810,16 @@
             mLoadingPackages = new HashSet<>(other.mLoadingPackages);
         }
 
-        private boolean merge(DexUseInfo dexUseInfo) {
+        private boolean merge(DexUseInfo dexUseInfo, boolean overwriteCLC) {
             boolean oldIsUsedByOtherApps = mIsUsedByOtherApps;
             mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps;
             boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas);
             boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
 
             String oldClassLoaderContext = mClassLoaderContext;
-            if (isUnsupportedContext(mClassLoaderContext)) {
+            if (overwriteCLC) {
+                mClassLoaderContext = dexUseInfo.mClassLoaderContext;
+            } else if (isUnsupportedContext(mClassLoaderContext)) {
                 mClassLoaderContext = dexUseInfo.mClassLoaderContext;
             } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
                 // We detected a context change.
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
new file mode 100644
index 0000000..6cdd4df
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.android.server.pm.parsing.library;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/**
+ * Updates a package to remove dependency on android.net.ipsec.ike library.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidNetIpSecIkeUpdater extends PackageSharedLibraryUpdater {
+
+    private static final String LIBRARY_NAME = "android.net.ipsec.ike";
+
+    @Override
+    public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
+        removeLibrary(parsedPackage, LIBRARY_NAME);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 1405a7d..8a8a302 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -45,6 +45,9 @@
     static {
         final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
 
+        // Remove android.net.ipsec.ike library, it is added to boot classpath since Android S.
+        packageUpdaters.add(new AndroidNetIpSecIkeUpdater());
+
         // Remove com.google.android.maps library.
         packageUpdaters.add(new ComGoogleAndroidMapsUpdater());
 
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index a6f02e7..24d49a3 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -125,8 +125,10 @@
     public static void validatePackageDexMetadata(AndroidPackage pkg)
             throws PackageParserException {
         Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
+        String packageName = pkg.getPackageName();
+        long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
         for (String dexMetadata : apkToDexMetadataList) {
-            DexMetadataHelper.validateDexMetadataFile(dexMetadata);
+            DexMetadataHelper.validateDexMetadataFile(dexMetadata, packageName, versionCode);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 0e88862..e05ef48 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,4 +1,3 @@
-moltmann@google.com
 zhanghai@google.com
 per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
 per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
@@ -7,5 +6,4 @@
 per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
 per-file DefaultPermissionGrantPolicy.java = patb@google.com
 per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
-per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
 per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/role/OWNERS b/services/core/java/com/android/server/role/OWNERS
index b94d988..31e3549 100644
--- a/services/core/java/com/android/server/role/OWNERS
+++ b/services/core/java/com/android/server/role/OWNERS
@@ -1,5 +1,4 @@
 svetoslavganov@google.com
-moltmann@google.com
 zhanghai@google.com
 evanseverson@google.com
 eugenesusla@google.com
diff --git a/services/core/java/com/android/server/tracing/OWNERS b/services/core/java/com/android/server/tracing/OWNERS
new file mode 100644
index 0000000..f5de4eb
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
new file mode 100644
index 0000000..8f22748
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
@@ -0,0 +1,99 @@
+/*
+ * 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 com.android.server.tracing;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.UserHandle;
+import android.tracing.ITracingServiceProxy;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * TracingServiceProxy is the system_server intermediary between the Perfetto tracing daemon and the
+ * system tracing app Traceur.
+ *
+ * @hide
+ */
+public class TracingServiceProxy extends SystemService {
+    private static final String TAG = "TracingServiceProxy";
+
+    public static final String TRACING_SERVICE_PROXY_BINDER_NAME = "tracing.proxy";
+
+    private static final String TRACING_APP_PACKAGE_NAME = "com.android.traceur";
+    private static final String TRACING_APP_ACTIVITY = "com.android.traceur.StopTraceService";
+
+    // Keep this in sync with the definitions in TraceService
+    private static final String INTENT_ACTION_NOTIFY_SESSION_STOPPED =
+            "com.android.traceur.NOTIFY_SESSION_STOPPED";
+    private static final String INTENT_ACTION_NOTIFY_SESSION_STOLEN =
+            "com.android.traceur.NOTIFY_SESSION_STOLEN";
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+
+    private final ITracingServiceProxy.Stub mTracingServiceProxy = new ITracingServiceProxy.Stub() {
+        /**
+          * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+          * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+          * there is no buffer available to dump.
+          */
+        @Override
+        public void notifyTraceSessionEnded(boolean sessionStolen) {
+            notifyTraceur(sessionStolen);
+        }
+    };
+
+    public TracingServiceProxy(Context context) {
+        super(context);
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy);
+    }
+
+    private void notifyTraceur(boolean sessionStolen) {
+        final Intent intent = new Intent();
+
+        try {
+            // Validate that Traceur is a system app.
+            PackageInfo info = mPackageManager.getPackageInfo(TRACING_APP_PACKAGE_NAME,
+                    PackageManager.MATCH_SYSTEM_ONLY);
+
+            intent.setClassName(info.packageName, TRACING_APP_ACTIVITY);
+            if (sessionStolen) {
+                intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOLEN);
+            } else {
+                intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOPPED);
+            }
+
+            try {
+                mContext.startForegroundServiceAsUser(intent, UserHandle.SYSTEM);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Failed to notifyTraceSessionEnded", e);
+            }
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Failed to locate Traceur", e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 75277d1..afcf81f 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -700,7 +700,7 @@
         if (changed) {
             dispatchDeviceLocked(userId, locked);
 
-            mAuthorizationService.onLockScreenEvent(locked, userId, null);
+            Authorization.onLockScreenEvent(locked, userId, null);
             KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
             // Also update the user's profiles who have unified challenge, since they
             // share the same unlocked state (see {@link #isDeviceLocked(int)})
@@ -1258,7 +1258,7 @@
                         mDeviceLockedForUser.put(userId, locked);
                     }
 
-                    mAuthorizationService.onLockScreenEvent(locked, userId, null);
+                    Authorization.onLockScreenEvent(locked, userId, null);
                     KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
 
                     if (locked) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 3dfb99e..bba5dcb 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -976,7 +976,7 @@
             AudioPortConfig sourceConfig = mAudioSource.activeConfig();
             List<AudioPortConfig> sinkConfigs = new ArrayList<>();
             AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
-            boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated;
+            boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated || mAudioPatch == null;
 
             for (AudioDevicePort audioSink : mAudioSink) {
                 AudioPortConfig sinkConfig = audioSink.activeConfig();
diff --git a/services/core/java/com/android/server/vcn/Android.bp b/services/core/java/com/android/server/vcn/Android.bp
index 5ed204f..ab5da3e 100644
--- a/services/core/java/com/android/server/vcn/Android.bp
+++ b/services/core/java/com/android/server/vcn/Android.bp
@@ -1,4 +1,13 @@
+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-vcn-util-sources",
     srcs: ["util/**/*.java"],
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index fd12c2d2..b6ddd93 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -28,16 +28,15 @@
 import android.net.TelephonyNetworkSpecifier;
 import android.os.Handler;
 import android.os.ParcelUuid;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 
-import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -55,19 +54,18 @@
 
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
+    @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
     @NonNull private final UnderlyingNetworkTrackerCallback mCb;
     @NonNull private final Dependencies mDeps;
     @NonNull private final Handler mHandler;
     @NonNull private final ConnectivityManager mConnectivityManager;
-    @NonNull private final SubscriptionManager mSubscriptionManager;
 
-    @NonNull private final SparseArray<NetworkCallback> mCellBringupCallbacks = new SparseArray<>();
+    @NonNull private final Map<Integer, NetworkCallback> mCellBringupCallbacks = new ArrayMap<>();
     @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback();
     @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
 
-    @NonNull private final Set<Integer> mSubIds = new ArraySet<>();
-
-    @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
+    @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
+    private boolean mIsRunning = true;
 
     @Nullable private UnderlyingNetworkRecord mCurrentRecord;
     @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
@@ -75,11 +73,13 @@
     public UnderlyingNetworkTracker(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
             @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
             @NonNull UnderlyingNetworkTrackerCallback cb) {
         this(
                 vcnContext,
                 subscriptionGroup,
+                snapshot,
                 requiredUnderlyingNetworkCapabilities,
                 cb,
                 new Dependencies());
@@ -88,11 +88,13 @@
     private UnderlyingNetworkTracker(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
             @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
             @NonNull UnderlyingNetworkTrackerCallback cb,
             @NonNull Dependencies deps) {
         mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
         mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
+        mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
         mRequiredUnderlyingNetworkCapabilities =
                 Objects.requireNonNull(
                         requiredUnderlyingNetworkCapabilities,
@@ -103,7 +105,6 @@
         mHandler = new Handler(mVcnContext.getLooper());
 
         mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
-        mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class);
 
         registerNetworkRequests();
     }
@@ -149,34 +150,47 @@
     private void updateSubIdsAndCellularRequests() {
         mVcnContext.ensureRunningOnLooperThread();
 
-        Set<Integer> prevSubIds = new ArraySet<>(mSubIds);
-        mSubIds.clear();
-
-        // Ensure NetworkRequests filed for all current subIds in mSubscriptionGroup
-        // STOPSHIP: b/177364490 use TelephonySubscriptionSnapshot to avoid querying Telephony
-        List<SubscriptionInfo> subInfos =
-                mSubscriptionManager.getSubscriptionsInGroup(mSubscriptionGroup);
-
-        for (SubscriptionInfo subInfo : subInfos) {
-            final int subId = subInfo.getSubscriptionId();
-            mSubIds.add(subId);
-
-            if (!mCellBringupCallbacks.contains(subId)) {
-                final NetworkBringupCallback cb = new NetworkBringupCallback();
-                mCellBringupCallbacks.put(subId, cb);
-
-                mConnectivityManager.requestBackgroundNetwork(
-                        getCellNetworkRequestForSubId(subId), mHandler, cb);
-            }
+        // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
+        if (!mIsRunning) {
+            return;
         }
 
-        // unregister all NetworkCallbacks for outdated subIds
-        for (final int subId : prevSubIds) {
-            if (!mSubIds.contains(subId)) {
-                final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
-                mConnectivityManager.unregisterNetworkCallback(cb);
-            }
+        final Set<Integer> subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup);
+
+        // new subIds to track = (updated list of subIds) - (currently tracked subIds)
+        final Set<Integer> subIdsToRegister = new ArraySet<>(subIdsInSubGroup);
+        subIdsToRegister.removeAll(mCellBringupCallbacks.keySet());
+
+        // subIds to stop tracking = (currently tracked subIds) - (updated list of subIds)
+        final Set<Integer> subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet());
+        subIdsToUnregister.removeAll(subIdsInSubGroup);
+
+        for (final int subId : subIdsToRegister) {
+            final NetworkBringupCallback cb = new NetworkBringupCallback();
+            mCellBringupCallbacks.put(subId, cb);
+
+            mConnectivityManager.requestBackgroundNetwork(
+                    getCellNetworkRequestForSubId(subId), mHandler, cb);
         }
+
+        for (final int subId : subIdsToUnregister) {
+            final NetworkCallback cb = mCellBringupCallbacks.remove(subId);
+            mConnectivityManager.unregisterNetworkCallback(cb);
+        }
+    }
+
+    /**
+     * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot.
+     *
+     * <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to
+     * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
+     * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
+     */
+    public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
+        Objects.requireNonNull(snapshot, "Missing snapshot");
+
+        mLastSnapshot = snapshot;
+        updateSubIdsAndCellularRequests();
     }
 
     /** Tears down this Tracker, and releases all underlying network requests. */
@@ -186,11 +200,12 @@
         mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback);
         mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback);
 
-        for (final int subId : mSubIds) {
-            final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
+        for (final NetworkCallback cb : mCellBringupCallbacks.values()) {
             mConnectivityManager.unregisterNetworkCallback(cb);
         }
-        mSubIds.clear();
+        mCellBringupCallbacks.clear();
+
+        mIsRunning = false;
     }
 
     /** Returns whether the currently selected Network matches the given network. */
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 132883e..6ad30b5 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,20 +16,32 @@
 
 package com.android.server.vcn;
 
+import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnManager.VcnErrorCode;
 import android.os.Handler;
 import android.os.Message;
 import android.os.ParcelUuid;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.VcnManagementService.VcnCallback;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Represents an single instance of a VCN.
@@ -63,41 +75,79 @@
      */
     private static final int MSG_EVENT_NETWORK_REQUESTED = MSG_EVENT_BASE + 1;
 
+    /**
+     * The TelephonySubscriptionSnapshot tracked by VcnManagementService has changed.
+     *
+     * <p>This updated snapshot should be cached locally and passed to all VcnGatewayConnections.
+     *
+     * @param obj TelephonySubscriptionSnapshot
+     */
+    private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;
+
     /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
     private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
 
+    /**
+     * Causes this VCN to immediately enter safe mode.
+     *
+     * <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
+     * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
+     */
+    private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
+
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @NonNull private final Dependencies mDeps;
     @NonNull private final VcnNetworkRequestListener mRequestListener;
+    @NonNull private final VcnCallback mVcnCallback;
 
     @NonNull
     private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections =
             new HashMap<>();
 
     @NonNull private VcnConfig mConfig;
+    @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
 
-    private boolean mIsRunning = true;
+    /**
+     * Whether this Vcn instance is active and running.
+     *
+     * <p>The value will be {@code true} while running. It will be {@code false} if the VCN has been
+     * shut down or has entered safe mode.
+     *
+     * <p>This AtomicBoolean is required in order to ensure consistency and correctness across
+     * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads
+     * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN
+     * Looper.
+     */
+    // TODO(b/179429339): update when exiting safemode (when a new VcnConfig is provided)
+    private final AtomicBoolean mIsActive = new AtomicBoolean(true);
 
     public Vcn(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
-            @NonNull VcnConfig config) {
-        this(vcnContext, subscriptionGroup, config, new Dependencies());
+            @NonNull VcnConfig config,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
+            @NonNull VcnCallback vcnCallback) {
+        this(vcnContext, subscriptionGroup, config, snapshot, vcnCallback, new Dependencies());
     }
 
-    private Vcn(
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public Vcn(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
             @NonNull VcnConfig config,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
+            @NonNull VcnCallback vcnCallback,
             @NonNull Dependencies deps) {
         super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
         mVcnContext = vcnContext;
         mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
+        mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
         mDeps = Objects.requireNonNull(deps, "Missing deps");
         mRequestListener = new VcnNetworkRequestListener();
 
         mConfig = Objects.requireNonNull(config, "Missing config");
+        mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
 
         // Register to receive cached and future NetworkRequests
         mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
@@ -110,11 +160,29 @@
         sendMessage(obtainMessage(MSG_EVENT_CONFIG_UPDATED, config));
     }
 
+    /** Asynchronously updates the Subscription snapshot for this VCN. */
+    public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
+        Objects.requireNonNull(snapshot, "Missing snapshot");
+
+        sendMessage(obtainMessage(MSG_EVENT_SUBSCRIPTIONS_CHANGED, snapshot));
+    }
+
     /** Asynchronously tears down this Vcn instance, including VcnGatewayConnection(s) */
     public void teardownAsynchronously() {
         sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN));
     }
 
+    /** Synchronously checks whether this Vcn is active. */
+    public boolean isActive() {
+        return mIsActive.get();
+    }
+
+    /** Get current Gateways for testing purposes */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public Set<VcnGatewayConnection> getVcnGatewayConnections() {
+        return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values()));
+    }
+
     private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
         @Override
         public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -126,7 +194,7 @@
 
     @Override
     public void handleMessage(@NonNull Message msg) {
-        if (!mIsRunning) {
+        if (!isActive()) {
             return;
         }
 
@@ -137,9 +205,15 @@
             case MSG_EVENT_NETWORK_REQUESTED:
                 handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
                 break;
+            case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
+                handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
+                break;
             case MSG_CMD_TEARDOWN:
                 handleTeardown();
                 break;
+            case MSG_CMD_ENTER_SAFE_MODE:
+                handleEnterSafeMode();
+                break;
             default:
                 Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
         }
@@ -147,7 +221,7 @@
 
     private void handleConfigUpdated(@NonNull VcnConfig config) {
         // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode()
-        Slog.v(getLogTag(), String.format("Config updated: config = %s", config.hashCode()));
+        Slog.v(getLogTag(), "Config updated: config = " + config.hashCode());
 
         mConfig = config;
 
@@ -161,23 +235,41 @@
             gatewayConnection.teardownAsynchronously();
         }
 
-        mIsRunning = false;
+        mIsActive.set(false);
+    }
+
+    private void handleEnterSafeMode() {
+        handleTeardown();
+
+        mVcnCallback.onEnteredSafeMode();
     }
 
     private void handleNetworkRequested(
             @NonNull NetworkRequest request, int score, int providerId) {
         if (score > getNetworkScore()) {
-            Slog.v(getLogTag(),
-                    "Request already satisfied by higher-scoring (" + score + ") network from "
-                            + "provider " + providerId + ": " + request);
+            if (VDBG) {
+                Slog.v(
+                        getLogTag(),
+                        "Request already satisfied by higher-scoring ("
+                                + score
+                                + ") network from "
+                                + "provider "
+                                + providerId
+                                + ": "
+                                + request);
+            }
             return;
         }
 
         // If preexisting VcnGatewayConnection(s) satisfy request, return
         for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
             if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
-                Slog.v(getLogTag(),
-                        "Request already satisfied by existing VcnGatewayConnection: " + request);
+                if (VDBG) {
+                    Slog.v(
+                            getLogTag(),
+                            "Request already satisfied by existing VcnGatewayConnection: "
+                                    + request);
+                }
                 return;
             }
         }
@@ -192,13 +284,27 @@
                         "Bringing up new VcnGatewayConnection for request " + request.requestId);
 
                 final VcnGatewayConnection vcnGatewayConnection =
-                        new VcnGatewayConnection(
-                                mVcnContext, mSubscriptionGroup, gatewayConnectionConfig);
+                        mDeps.newVcnGatewayConnection(
+                                mVcnContext,
+                                mSubscriptionGroup,
+                                mLastSnapshot,
+                                gatewayConnectionConfig,
+                                new VcnGatewayStatusCallbackImpl());
                 mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
             }
         }
     }
 
+    private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
+        mLastSnapshot = snapshot;
+
+        if (isActive()) {
+            for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+                gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
+            }
+        }
+    }
+
     private boolean requestSatisfiedByGatewayConnectionConfig(
             @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
@@ -210,15 +316,64 @@
     }
 
     private String getLogTag() {
-        return String.format("%s [%d]", TAG, mSubscriptionGroup.hashCode());
+        return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
     }
 
     /** Retrieves the network score for a VCN Network */
-    private int getNetworkScore() {
+    // Package visibility for use in VcnGatewayConnection
+    static int getNetworkScore() {
         // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in
         //                               subGrp" value
         return 52;
     }
 
-    private static class Dependencies {}
+    /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public interface VcnGatewayStatusCallback {
+        /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
+        void onEnteredSafeMode();
+
+        /** Callback by a VcnGatewayConnection to indicate that an error occurred. */
+        void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable String exceptionClass,
+                @Nullable String exceptionMessage);
+    }
+
+    private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
+        @Override
+        public void onEnteredSafeMode() {
+            sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
+        }
+
+        @Override
+        public void onGatewayConnectionError(
+                @NonNull int[] networkCapabilities,
+                @VcnErrorCode int errorCode,
+                @Nullable String exceptionClass,
+                @Nullable String exceptionMessage) {
+            mVcnCallback.onGatewayConnectionError(
+                    networkCapabilities, errorCode, exceptionClass, exceptionMessage);
+        }
+    }
+
+    /** External dependencies used by Vcn, for injection in tests */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class Dependencies {
+        /** Builds a new VcnGatewayConnection */
+        public VcnGatewayConnection newVcnGatewayConnection(
+                VcnContext vcnContext,
+                ParcelUuid subscriptionGroup,
+                TelephonySubscriptionSnapshot snapshot,
+                VcnGatewayConnectionConfig connectionConfig,
+                VcnGatewayStatusCallback gatewayStatusCallback) {
+            return new VcnGatewayConnection(
+                    vcnContext,
+                    subscriptionGroup,
+                    snapshot,
+                    connectionConfig,
+                    gatewayStatusCallback);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 39c9606..06748a3 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -17,13 +17,20 @@
 package com.android.server.vcn;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
 
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
@@ -34,8 +41,12 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkAgent;
+import android.net.NetworkAgent.ValidationStatus;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.RouteInfo;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.Uri;
 import android.net.annotations.PolicyDirection;
 import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.ChildSessionConfiguration;
@@ -44,26 +55,39 @@
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.ipsec.ike.IkeSessionConfiguration;
 import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
 import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
 import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnTransportInfo;
+import android.net.wifi.WifiInfo;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Message;
 import android.os.ParcelUuid;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
+import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
 
 import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -108,12 +132,37 @@
  * +----------------------------+
  * </pre>
  *
+ * <p>All messages in VcnGatewayConnection <b>should</b> be enqueued using {@link
+ * #sendMessageAndAcquireWakeLock}. Careful consideration should be given to any uses of {@link
+ * #sendMessage} directly, as they are not guaranteed to be processed in a timely manner (due to the
+ * lack of WakeLocks).
+ *
+ * <p>Any attempt to remove messages from the Handler should be done using {@link
+ * #removeEqualMessages}. This is necessary to ensure that the WakeLock is correctly released when
+ * no messages remain in the Handler queue.
+ *
  * @hide
  */
 public class VcnGatewayConnection extends StateMachine {
     private static final String TAG = VcnGatewayConnection.class.getSimpleName();
 
-    private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final String TEARDOWN_TIMEOUT_ALARM = TAG + "_TEARDOWN_TIMEOUT_ALARM";
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final String DISCONNECT_REQUEST_ALARM = TAG + "_DISCONNECT_REQUEST_ALARM";
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final String RETRY_TIMEOUT_ALARM = TAG + "_RETRY_TIMEOUT_ALARM";
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final String SAFEMODE_TIMEOUT_ALARM = TAG + "_SAFEMODE_TIMEOUT_ALARM";
+
+    private static final int[] MERGED_CAPABILITIES =
+            new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING};
     private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE;
 
     private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: ";
@@ -122,11 +171,15 @@
     private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
     private static final int TOKEN_ALL = Integer.MIN_VALUE;
 
-    private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static final int TEARDOWN_TIMEOUT_SECONDS = 5;
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final int SAFEMODE_TIMEOUT_SECONDS = 30;
+
     private interface EventInfo {}
 
     /**
@@ -283,9 +336,9 @@
     private static final int EVENT_SETUP_COMPLETED = 6;
 
     private static class EventSetupCompletedInfo implements EventInfo {
-        @NonNull public final ChildSessionConfiguration childSessionConfig;
+        @NonNull public final VcnChildSessionConfiguration childSessionConfig;
 
-        EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) {
+        EventSetupCompletedInfo(@NonNull VcnChildSessionConfiguration childSessionConfig) {
             this.childSessionConfig = Objects.requireNonNull(childSessionConfig);
         }
 
@@ -359,6 +412,33 @@
      */
     private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
 
+    /**
+     * Sent when this VcnGatewayConnection is notified of a change in TelephonySubscriptions.
+     *
+     * <p>Relevant in all states.
+     *
+     * @param arg1 The "all" token; this signal is always honored.
+     */
+    // TODO(b/178426520): implement handling of this event
+    private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9;
+
+    /**
+     * Sent when this VcnGatewayConnection has entered safe mode.
+     *
+     * <p>A VcnGatewayConnection enters safe mode when it takes over {@link
+     * #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}.
+     *
+     * <p>When a VcnGatewayConnection enters safe mode, it will fire {@link
+     * VcnGatewayStatusCallback#onEnteredSafeMode()} to notify its Vcn. The Vcn will then shut down
+     * its VcnGatewayConnectin(s).
+     *
+     * <p>Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not
+     * validated yet), and RetryTimeoutState.
+     *
+     * @param arg1 The "all" token; this signal is always honored.
+     */
+    private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10;
+
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     @NonNull
     final DisconnectedState mDisconnectedState = new DisconnectedState();
@@ -379,16 +459,34 @@
     @NonNull
     final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
 
+    @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
+
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
     @NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
+    @NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
     @NonNull private final Dependencies mDeps;
-
     @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
 
     @NonNull private final IpSecManager mIpSecManager;
-    @NonNull private final IpSecTunnelInterface mTunnelIface;
+
+    @Nullable private IpSecTunnelInterface mTunnelIface = null;
+
+    /**
+     * WakeLock to be held when processing messages on the Handler queue.
+     *
+     * <p>Used to prevent the device from going to sleep while there are VCN-related events to
+     * process for this VcnGatewayConnection.
+     *
+     * <p>Obtain a WakeLock when enquing messages onto the Handler queue. Once all messages in the
+     * Handler queue have been processed, the WakeLock can be released and cleared.
+     *
+     * <p>This WakeLock is also used for handling delayed messages by using WakeupMessages to send
+     * delayed messages to the Handler. When the WakeupMessage fires, it will obtain the WakeLock
+     * before enquing the delayed event to the Handler.
+     */
+    @NonNull private final VcnWakeLock mWakeLock;
 
     /** Running state of this VcnGatewayConnection. */
     private boolean mIsRunning = true;
@@ -444,7 +542,7 @@
      * <p>Set in Connected and Migrating states, always @NonNull in Connected, Migrating
      * states, @Nullable otherwise.
      */
-    private ChildSessionConfiguration mChildConfig;
+    private VcnChildSessionConfiguration mChildConfig;
 
     /**
      * The active network agent.
@@ -452,51 +550,61 @@
      * <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
      * otherwise.
      */
-    private NetworkAgent mNetworkAgent;
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    NetworkAgent mNetworkAgent;
+
+    @Nullable private WakeupMessage mTeardownTimeoutAlarm;
+    @Nullable private WakeupMessage mDisconnectRequestAlarm;
+    @Nullable private WakeupMessage mRetryTimeoutAlarm;
+    @Nullable private WakeupMessage mSafeModeTimeoutAlarm;
 
     public VcnGatewayConnection(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
-            @NonNull VcnGatewayConnectionConfig connectionConfig) {
-        this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
+            @NonNull TelephonySubscriptionSnapshot snapshot,
+            @NonNull VcnGatewayConnectionConfig connectionConfig,
+            @NonNull VcnGatewayStatusCallback gatewayStatusCallback) {
+        this(
+                vcnContext,
+                subscriptionGroup,
+                snapshot,
+                connectionConfig,
+                gatewayStatusCallback,
+                new Dependencies());
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     VcnGatewayConnection(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
             @NonNull VcnGatewayConnectionConfig connectionConfig,
+            @NonNull VcnGatewayStatusCallback gatewayStatusCallback,
             @NonNull Dependencies deps) {
         super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
         mVcnContext = vcnContext;
         mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
         mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
+        mGatewayStatusCallback =
+                Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
         mDeps = Objects.requireNonNull(deps, "Missing deps");
 
+        mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
+
         mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback();
 
+        mWakeLock =
+                mDeps.newWakeLock(mVcnContext.getContext(), PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
         mUnderlyingNetworkTracker =
                 mDeps.newUnderlyingNetworkTracker(
                         mVcnContext,
                         subscriptionGroup,
+                        mLastSnapshot,
                         mConnectionConfig.getAllUnderlyingCapabilities(),
                         mUnderlyingNetworkTrackerCallback);
         mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
 
-        IpSecTunnelInterface iface;
-        try {
-            iface =
-                    mIpSecManager.createIpSecTunnelInterface(
-                            DUMMY_ADDR, DUMMY_ADDR, new Network(-1));
-        } catch (IOException | ResourceUnavailableException e) {
-            teardownAsynchronously();
-            mTunnelIface = null;
-
-            return;
-        }
-
-        mTunnelIface = iface;
-
         addState(mDisconnectedState);
         addState(mDisconnectingState);
         addState(mConnectingState);
@@ -514,7 +622,7 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
-        sendMessage(
+        sendMessageAndAcquireWakeLock(
                 EVENT_DISCONNECT_REQUESTED,
                 TOKEN_ALL,
                 new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
@@ -530,77 +638,400 @@
             mTunnelIface.close();
         }
 
+        releaseWakeLock();
+
+        cancelTeardownTimeoutAlarm();
+        cancelDisconnectRequestAlarm();
+        cancelRetryTimeoutAlarm();
+        cancelSafeModeAlarm();
+
         mUnderlyingNetworkTracker.teardown();
     }
 
+    /**
+     * Notify this Gateway that subscriptions have changed.
+     *
+     * <p>This snapshot should be used to update any keepalive requests necessary for potential
+     * underlying Networks in this Gateway's subscription group.
+     */
+    public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
+        Objects.requireNonNull(snapshot, "Missing snapshot");
+        mVcnContext.ensureRunningOnLooperThread();
+
+        mLastSnapshot = snapshot;
+        mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot);
+
+        sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL);
+    }
+
     private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
         @Override
         public void onSelectedUnderlyingNetworkChanged(
                 @Nullable UnderlyingNetworkRecord underlying) {
+            // TODO(b/180132994): explore safely removing this Thread check
+            mVcnContext.ensureRunningOnLooperThread();
+
+            // TODO(b/179091925): Move the delayed-message handling to BaseState
+
             // If underlying is null, all underlying networks have been lost. Disconnect VCN after a
             // timeout.
             if (underlying == null) {
-                sendMessageDelayed(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST),
-                        TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
-            } else if (getHandler() != null) {
-                // Cancel any existing disconnect due to loss of underlying network
-                // getHandler() can return null if the state machine has already quit. Since this is
-                // called from other classes, this condition must be verified.
-
-                getHandler()
-                        .removeEqualMessages(
-                                EVENT_DISCONNECT_REQUESTED,
-                                new EventDisconnectRequestedInfo(
-                                        DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+                setDisconnectRequestAlarm();
+            } else {
+                // Received a new Network so any previous alarm is irrelevant - cancel + clear it,
+                // and cancel any queued EVENT_DISCONNECT_REQUEST messages
+                cancelDisconnectRequestAlarm();
             }
 
-            sendMessage(
+            sendMessageAndAcquireWakeLock(
                     EVENT_UNDERLYING_NETWORK_CHANGED,
                     TOKEN_ALL,
                     new EventUnderlyingNetworkChangedInfo(underlying));
         }
     }
 
-    private void sendMessage(int what, int token, EventInfo data) {
+    private void acquireWakeLock() {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (mIsRunning) {
+            mWakeLock.acquire();
+        }
+    }
+
+    private void releaseWakeLock() {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        mWakeLock.release();
+    }
+
+    /**
+     * Attempt to release mWakeLock - this can only be done if the Handler is null (meaning the
+     * StateMachine has been shutdown and thus has no business keeping the WakeLock) or if there are
+     * no more messags left to process in the Handler queue (at which point the WakeLock can be
+     * released until more messages must be processed).
+     */
+    private void maybeReleaseWakeLock() {
+        final Handler handler = getHandler();
+        if (handler == null || !handler.hasMessagesOrCallbacks()) {
+            releaseWakeLock();
+        }
+    }
+
+    @Override
+    public void sendMessage(int what) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(what);
+    }
+
+    @Override
+    public void sendMessage(int what, Object obj) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(what, obj);
+    }
+
+    @Override
+    public void sendMessage(int what, int arg1) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(what, arg1);
+    }
+
+    @Override
+    public void sendMessage(int what, int arg1, int arg2) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(what, arg1, arg2);
+    }
+
+    @Override
+    public void sendMessage(int what, int arg1, int arg2, Object obj) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(what, arg1, arg2, obj);
+    }
+
+    @Override
+    public void sendMessage(Message msg) {
+        Slog.wtf(
+                TAG,
+                "sendMessage should not be used in VcnGatewayConnection. See"
+                        + " sendMessageAndAcquireWakeLock()");
+        super.sendMessage(msg);
+    }
+
+    // TODO(b/180146061): also override and Log.wtf() other Message handling methods
+    // In mind are sendMessageDelayed(), sendMessageAtFrontOfQueue, removeMessages, and
+    // removeDeferredMessages
+
+    /**
+     * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
+     * go to sleep before processing the sent message.
+     */
+    private void sendMessageAndAcquireWakeLock(int what, int token) {
+        acquireWakeLock();
+        super.sendMessage(what, token);
+    }
+
+    /**
+     * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
+     * go to sleep before processing the sent message.
+     */
+    private void sendMessageAndAcquireWakeLock(int what, int token, EventInfo data) {
+        acquireWakeLock();
         super.sendMessage(what, token, ARG_NOT_PRESENT, data);
     }
 
-    private void sendMessage(int what, int token, int arg2, EventInfo data) {
+    /**
+     * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
+     * go to sleep before processing the sent message.
+     */
+    private void sendMessageAndAcquireWakeLock(int what, int token, int arg2, EventInfo data) {
+        acquireWakeLock();
         super.sendMessage(what, token, arg2, data);
     }
 
-    private void sendMessageDelayed(int what, int token, EventInfo data, long timeout) {
-        super.sendMessageDelayed(what, token, ARG_NOT_PRESENT, data, timeout);
+    /**
+     * WakeLock-based alternative to {@link #sendMessage}. Use to guarantee that the device will not
+     * go to sleep before processing the sent message.
+     */
+    private void sendMessageAndAcquireWakeLock(Message msg) {
+        acquireWakeLock();
+        super.sendMessage(msg);
     }
 
-    private void sendMessageDelayed(int what, int token, int arg2, EventInfo data, long timeout) {
-        super.sendMessageDelayed(what, token, arg2, data, timeout);
+    /**
+     * Removes all messages matching the given parameters, and attempts to release mWakeLock if the
+     * Handler is empty.
+     *
+     * @param what the Message.what value to be removed
+     */
+    private void removeEqualMessages(int what) {
+        removeEqualMessages(what, null /* obj */);
+    }
+
+    /**
+     * Removes all messages matching the given parameters, and attempts to release mWakeLock if the
+     * Handler is empty.
+     *
+     * @param what the Message.what value to be removed
+     * @param obj the Message.obj to to be removed, or null if all messages matching Message.what
+     *     should be removed
+     */
+    private void removeEqualMessages(int what, @Nullable Object obj) {
+        final Handler handler = getHandler();
+        if (handler != null) {
+            handler.removeEqualMessages(what, obj);
+        }
+
+        maybeReleaseWakeLock();
+    }
+
+    private WakeupMessage createScheduledAlarm(
+            @NonNull String cmdName, Message delayedMessage, long delay) {
+        // WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable
+        // at the scheduled time. dispatchMessage() immediately executes and there may be queued
+        // events that resolve the scheduled alarm pending in the queue. So, use the Runnable to
+        // place the alarm event at the end of the queue with sendMessageAndAcquireWakeLock (which
+        // guarantees the device will stay awake).
+        final WakeupMessage alarm =
+                mDeps.newWakeupMessage(
+                        mVcnContext,
+                        getHandler(),
+                        cmdName,
+                        () -> sendMessageAndAcquireWakeLock(delayedMessage));
+        alarm.schedule(mDeps.getElapsedRealTime() + delay);
+        return alarm;
+    }
+
+    private void setTeardownTimeoutAlarm() {
+        // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
+        // either case, there is nothing to cancel.
+        if (mTeardownTimeoutAlarm != null) {
+            Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set");
+        }
+
+        final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken);
+        mTeardownTimeoutAlarm =
+                createScheduledAlarm(
+                        TEARDOWN_TIMEOUT_ALARM,
+                        delayedMessage,
+                        TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
+    }
+
+    private void cancelTeardownTimeoutAlarm() {
+        if (mTeardownTimeoutAlarm != null) {
+            mTeardownTimeoutAlarm.cancel();
+            mTeardownTimeoutAlarm = null;
+        }
+
+        // Cancel any existing teardown timeouts
+        removeEqualMessages(EVENT_TEARDOWN_TIMEOUT_EXPIRED);
+    }
+
+    private void setDisconnectRequestAlarm() {
+        // Only schedule a NEW alarm if none is already set.
+        if (mDisconnectRequestAlarm != null) {
+            return;
+        }
+
+        final Message delayedMessage =
+                obtainMessage(
+                        EVENT_DISCONNECT_REQUESTED,
+                        TOKEN_ALL,
+                        0 /* arg2 */,
+                        new EventDisconnectRequestedInfo(
+                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+        mDisconnectRequestAlarm =
+                createScheduledAlarm(
+                        DISCONNECT_REQUEST_ALARM,
+                        delayedMessage,
+                        TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
+    }
+
+    private void cancelDisconnectRequestAlarm() {
+        if (mDisconnectRequestAlarm != null) {
+            mDisconnectRequestAlarm.cancel();
+            mDisconnectRequestAlarm = null;
+        }
+
+        // Cancel any existing disconnect due to previous loss of underlying network
+        removeEqualMessages(
+                EVENT_DISCONNECT_REQUESTED,
+                new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+    }
+
+    private void setRetryTimeoutAlarm(long delay) {
+        // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
+        // either case, there is nothing to cancel.
+        if (mRetryTimeoutAlarm != null) {
+            Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set");
+        }
+
+        final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken);
+        mRetryTimeoutAlarm = createScheduledAlarm(RETRY_TIMEOUT_ALARM, delayedMessage, delay);
+    }
+
+    private void cancelRetryTimeoutAlarm() {
+        if (mRetryTimeoutAlarm != null) {
+            mRetryTimeoutAlarm.cancel();
+            mRetryTimeoutAlarm = null;
+        }
+
+        removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setSafeModeAlarm() {
+        // Only schedule a NEW alarm if none is already set.
+        if (mSafeModeTimeoutAlarm != null) {
+            return;
+        }
+
+        final Message delayedMessage = obtainMessage(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED, TOKEN_ALL);
+        mSafeModeTimeoutAlarm =
+                createScheduledAlarm(
+                        SAFEMODE_TIMEOUT_ALARM,
+                        delayedMessage,
+                        TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+    }
+
+    private void cancelSafeModeAlarm() {
+        if (mSafeModeTimeoutAlarm != null) {
+            mSafeModeTimeoutAlarm.cancel();
+            mSafeModeTimeoutAlarm = null;
+        }
+
+        removeEqualMessages(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED);
+    }
+
+    private void sessionLostWithoutCallback(int token, @Nullable Exception exception) {
+        sendMessageAndAcquireWakeLock(
+                EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception));
     }
 
     private void sessionLost(int token, @Nullable Exception exception) {
-        sendMessage(EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception));
+        // Only notify mGatewayStatusCallback if the session was lost with an error. All
+        // authentication and DNS failures are sent through
+        // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed()
+        if (exception != null) {
+            mGatewayStatusCallback.onGatewayConnectionError(
+                    mConnectionConfig.getRequiredUnderlyingCapabilities(),
+                    VCN_ERROR_CODE_INTERNAL_ERROR,
+                    RuntimeException.class.getName(),
+                    "Received "
+                            + exception.getClass().getSimpleName()
+                            + " with message: "
+                            + exception.getMessage());
+        }
+
+        sessionLostWithoutCallback(token, exception);
+    }
+
+    private void notifyStatusCallbackForSessionClosed(@NonNull Exception exception) {
+        final int errorCode;
+        final String exceptionClass;
+        final String exceptionMessage;
+
+        if (exception instanceof AuthenticationFailedException) {
+            errorCode = VCN_ERROR_CODE_CONFIG_ERROR;
+            exceptionClass = exception.getClass().getName();
+            exceptionMessage = exception.getMessage();
+        } else if (exception instanceof IkeInternalException
+                && exception.getCause() instanceof IOException) {
+            errorCode = VCN_ERROR_CODE_NETWORK_ERROR;
+            exceptionClass = IOException.class.getName();
+            exceptionMessage = exception.getCause().getMessage();
+        } else {
+            errorCode = VCN_ERROR_CODE_INTERNAL_ERROR;
+            exceptionClass = RuntimeException.class.getName();
+            exceptionMessage =
+                    "Received "
+                            + exception.getClass().getSimpleName()
+                            + " with message: "
+                            + exception.getMessage();
+        }
+
+        mGatewayStatusCallback.onGatewayConnectionError(
+                mConnectionConfig.getRequiredUnderlyingCapabilities(),
+                errorCode,
+                exceptionClass,
+                exceptionMessage);
     }
 
     private void sessionClosed(int token, @Nullable Exception exception) {
+        if (exception != null) {
+            notifyStatusCallbackForSessionClosed(exception);
+        }
+
         // SESSION_LOST MUST be sent before SESSION_CLOSED to ensure that the SM moves to the
         // Disconnecting state.
-        sessionLost(token, exception);
-        sendMessage(EVENT_SESSION_CLOSED, token);
+        sessionLostWithoutCallback(token, exception);
+        sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token);
     }
 
     private void childTransformCreated(
             int token, @NonNull IpSecTransform transform, int direction) {
-        sendMessage(
+        sendMessageAndAcquireWakeLock(
                 EVENT_TRANSFORM_CREATED,
                 token,
                 new EventTransformCreatedInfo(direction, transform));
     }
 
-    private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
-        sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig));
+    private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) {
+        sendMessageAndAcquireWakeLock(
+                EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig));
     }
 
     private abstract class BaseState extends State {
@@ -610,7 +1041,7 @@
                 enterState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessage(
+                sendMessageAndAcquireWakeLock(
                         EVENT_DISCONNECT_REQUESTED,
                         TOKEN_ALL,
                         new EventDisconnectRequestedInfo(
@@ -621,22 +1052,47 @@
         protected void enterState() throws Exception {}
 
         /**
+         * Returns whether the given token is valid.
+         *
+         * <p>By default, States consider any and all token to be 'valid'.
+         *
+         * <p>States should override this method if they want to restrict message handling to
+         * specific tokens.
+         */
+        protected boolean isValidToken(int token) {
+            return true;
+        }
+
+        /**
          * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng
          * builds.
+         *
+         * <p>Here be dragons: processMessage() is final to ensure that mWakeLock is released once
+         * the Handler queue is empty. Future changes (or overrides) to processMessage() to MUST
+         * ensure that mWakeLock is correctly released.
          */
         @Override
-        public boolean processMessage(Message msg) {
+        public final boolean processMessage(Message msg) {
+            final int token = msg.arg1;
+            if (!isValidToken(token)) {
+                Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+                return HANDLED;
+            }
+
             try {
                 processStateMsg(msg);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessage(
+                sendMessageAndAcquireWakeLock(
                         EVENT_DISCONNECT_REQUESTED,
                         TOKEN_ALL,
                         new EventDisconnectRequestedInfo(
                                 DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
             }
 
+            // Attempt to release the WakeLock - only possible if the Handler queue is empty
+            maybeReleaseWakeLock();
+
             return HANDLED;
         }
 
@@ -648,7 +1104,7 @@
                 exitState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessage(
+                sendMessageAndAcquireWakeLock(
                         EVENT_DISCONNECT_REQUESTED,
                         TOKEN_ALL,
                         new EventDisconnectRequestedInfo(
@@ -668,7 +1124,8 @@
                 case EVENT_TRANSFORM_CREATED: // Fallthrough
                 case EVENT_SETUP_COMPLETED: // Fallthrough
                 case EVENT_DISCONNECT_REQUESTED: // Fallthrough
-                case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
+                case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough
+                case EVENT_SUBSCRIPTIONS_CHANGED:
                     logUnexpectedEvent(msg.what);
                     break;
                 default:
@@ -685,6 +1142,8 @@
         }
 
         protected void handleDisconnectRequested(String msg) {
+            // TODO(b/180526152): notify VcnStatusCallback for Network loss
+
             Slog.v(TAG, "Tearing down. Cause: " + msg);
             mIsRunning = false;
 
@@ -725,6 +1184,8 @@
             if (mIkeSession != null || mNetworkAgent != null) {
                 Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
             }
+
+            cancelSafeModeAlarm();
         }
 
         @Override
@@ -748,27 +1209,16 @@
                     break;
             }
         }
+
+        @Override
+        protected void exitState() {
+            // Safe to blindly set up, as it is cancelled and cleared on entering this state
+            setSafeModeAlarm();
+        }
     }
 
     private abstract class ActiveBaseState extends BaseState {
-        /**
-         * Handles all incoming messages, discarding messages for previous networks.
-         *
-         * <p>States that handle mobility events may need to override this method to receive
-         * messages for all underlying networks.
-         */
         @Override
-        public boolean processMessage(Message msg) {
-            final int token = msg.arg1;
-            // Only process if a valid token is presented.
-            if (isValidToken(token)) {
-                return super.processMessage(msg);
-            }
-
-            Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
-            return HANDLED;
-        }
-
         protected boolean isValidToken(int token) {
             return (token == TOKEN_ALL || token == mCurrentToken);
         }
@@ -799,7 +1249,7 @@
         protected void enterState() throws Exception {
             if (mIkeSession == null) {
                 Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state.");
-                sendMessage(EVENT_SESSION_CLOSED, mCurrentToken);
+                sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken);
                 return;
             }
 
@@ -811,10 +1261,9 @@
             }
 
             mIkeSession.close();
-            sendMessageDelayed(
-                    EVENT_TEARDOWN_TIMEOUT_EXPIRED,
-                    mCurrentToken,
-                    TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
+
+            // Safe to blindly set up, as it is cancelled and cleared on exiting this state
+            setTeardownTimeoutAlarm();
         }
 
         @Override
@@ -839,6 +1288,8 @@
 
                     String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
                     if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
+                        // TODO(b/180526152): notify VcnStatusCallback for Network loss
+
                         // Will trigger EVENT_SESSION_CLOSED immediately.
                         mIkeSession.kill();
                         break;
@@ -856,6 +1307,10 @@
                         transitionTo(mDisconnectedState);
                     }
                     break;
+                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
+                    mGatewayStatusCallback.onEnteredSafeMode();
+                    mSafeModeTimeoutAlarm = null;
+                    break;
                 default:
                     logUnhandledMessage(msg);
                     break;
@@ -865,6 +1320,8 @@
         @Override
         protected void exitState() throws Exception {
             mSkipRetryTimeout = false;
+
+            cancelTeardownTimeoutAlarm();
         }
     }
 
@@ -921,6 +1378,8 @@
                     transitionTo(mDisconnectingState);
                     break;
                 case EVENT_SESSION_CLOSED:
+                    // Disconnecting state waits for EVENT_SESSION_CLOSED to shutdown, and this
+                    // message may not be posted again. Defer to ensure immediate shutdown.
                     deferMessage(msg);
 
                     transitionTo(mDisconnectingState);
@@ -934,6 +1393,10 @@
                 case EVENT_DISCONNECT_REQUESTED:
                     handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
                     break;
+                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
+                    mGatewayStatusCallback.onEnteredSafeMode();
+                    mSafeModeTimeoutAlarm = null;
+                    break;
                 default:
                     logUnhandledMessage(msg);
                     break;
@@ -941,7 +1404,124 @@
         }
     }
 
-    private abstract class ConnectedStateBase extends ActiveBaseState {}
+    private abstract class ConnectedStateBase extends ActiveBaseState {
+        protected void updateNetworkAgent(
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull NetworkAgent agent,
+                @NonNull VcnChildSessionConfiguration childConfig) {
+            final NetworkCapabilities caps =
+                    buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+            final LinkProperties lp =
+                    buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+
+            agent.sendNetworkCapabilities(caps);
+            agent.sendLinkProperties(lp);
+        }
+
+        protected NetworkAgent buildNetworkAgent(
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull VcnChildSessionConfiguration childConfig) {
+            final NetworkCapabilities caps =
+                    buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+            final LinkProperties lp =
+                    buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+
+            final NetworkAgent agent =
+                    new NetworkAgent(
+                            mVcnContext.getContext(),
+                            mVcnContext.getLooper(),
+                            TAG,
+                            caps,
+                            lp,
+                            Vcn.getNetworkScore(),
+                            new NetworkAgentConfig(),
+                            mVcnContext.getVcnNetworkProvider()) {
+                        @Override
+                        public void unwanted() {
+                            teardownAsynchronously();
+                        }
+
+                        @Override
+                        public void onValidationStatus(
+                                @ValidationStatus int status, @Nullable Uri redirectUri) {
+                            if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+                                clearFailedAttemptCounterAndSafeModeAlarm();
+                            }
+                        }
+                    };
+
+            agent.register();
+            agent.markConnected();
+
+            return agent;
+        }
+
+        protected void clearFailedAttemptCounterAndSafeModeAlarm() {
+            mVcnContext.ensureRunningOnLooperThread();
+
+            // Validated connection, clear failed attempt counter
+            mFailedAttempts = 0;
+            cancelSafeModeAlarm();
+        }
+
+        protected void applyTransform(
+                int token,
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull Network underlyingNetwork,
+                @NonNull IpSecTransform transform,
+                int direction) {
+            try {
+                // TODO(b/180163196): Set underlying network of tunnel interface
+
+                // Transforms do not need to be persisted; the IkeSession will keep them alive
+                mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
+            } catch (IOException e) {
+                Slog.d(TAG, "Transform application failed for network " + token, e);
+                sessionLost(token, e);
+            }
+        }
+
+        protected void setupInterface(
+                int token,
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull VcnChildSessionConfiguration childConfig) {
+            setupInterface(token, tunnelIface, childConfig, null);
+        }
+
+        protected void setupInterface(
+                int token,
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull VcnChildSessionConfiguration childConfig,
+                @Nullable VcnChildSessionConfiguration oldChildConfig) {
+            try {
+                final Set<LinkAddress> newAddrs =
+                        new ArraySet<>(childConfig.getInternalAddresses());
+                final Set<LinkAddress> existingAddrs = new ArraySet<>();
+                if (oldChildConfig != null) {
+                    existingAddrs.addAll(oldChildConfig.getInternalAddresses());
+                }
+
+                final Set<LinkAddress> toAdd = new ArraySet<>();
+                toAdd.addAll(newAddrs);
+                toAdd.removeAll(existingAddrs);
+
+                final Set<LinkAddress> toRemove = new ArraySet<>();
+                toRemove.addAll(existingAddrs);
+                toRemove.removeAll(newAddrs);
+
+                for (LinkAddress address : toAdd) {
+                    tunnelIface.addAddress(address.getAddress(), address.getPrefixLength());
+                }
+
+                for (LinkAddress address : toRemove) {
+                    tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength());
+                }
+            } catch (IOException e) {
+                Slog.d(TAG, "Adding address to tunnel failed for token " + token, e);
+                sessionLost(token, e);
+            }
+        }
+    }
 
     /**
      * Stable state representing a VCN that has a functioning connection to the mobility anchor.
@@ -951,7 +1531,113 @@
      */
     class ConnectedState extends ConnectedStateBase {
         @Override
-        protected void processStateMsg(Message msg) {}
+        protected void enterState() throws Exception {
+            if (mTunnelIface == null) {
+                try {
+                    // Requires a real Network object in order to be created; doing this any earlier
+                    // means not having a real Network object, or picking an incorrect Network.
+                    mTunnelIface =
+                            mIpSecManager.createIpSecTunnelInterface(
+                                    DUMMY_ADDR, DUMMY_ADDR, mUnderlying.network);
+                } catch (IOException | ResourceUnavailableException e) {
+                    teardownAsynchronously();
+                }
+            }
+        }
+
+        @Override
+        protected void processStateMsg(Message msg) {
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED:
+                    handleUnderlyingNetworkChanged(msg);
+                    break;
+                case EVENT_SESSION_CLOSED:
+                    // Disconnecting state waits for EVENT_SESSION_CLOSED to shutdown, and this
+                    // message may not be posted again. Defer to ensure immediate shutdown.
+                    deferMessage(msg);
+                    transitionTo(mDisconnectingState);
+                    break;
+                case EVENT_SESSION_LOST:
+                    transitionTo(mDisconnectingState);
+                    break;
+                case EVENT_TRANSFORM_CREATED:
+                    final EventTransformCreatedInfo transformCreatedInfo =
+                            (EventTransformCreatedInfo) msg.obj;
+
+                    applyTransform(
+                            mCurrentToken,
+                            mTunnelIface,
+                            mUnderlying.network,
+                            transformCreatedInfo.transform,
+                            transformCreatedInfo.direction);
+                    break;
+                case EVENT_SETUP_COMPLETED:
+                    mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
+
+                    setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
+                    break;
+                case EVENT_DISCONNECT_REQUESTED:
+                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    break;
+                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
+                    mGatewayStatusCallback.onEnteredSafeMode();
+                    mSafeModeTimeoutAlarm = null;
+                    break;
+                default:
+                    logUnhandledMessage(msg);
+                    break;
+            }
+        }
+
+        private void handleUnderlyingNetworkChanged(@NonNull Message msg) {
+            final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+            mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+            if (mUnderlying == null) {
+                // Ignored for now; a new network may be coming up. If none does, the delayed
+                // NETWORK_LOST disconnect will be fired, and tear down the session + network.
+                return;
+            }
+
+            // mUnderlying assumed non-null, given check above.
+            // If network changed, migrate. Otherwise, update any existing networkAgent.
+            if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) {
+                Slog.v(TAG, "Migrating to new network: " + mUnderlying.network);
+                mIkeSession.setNetwork(mUnderlying.network);
+            } else {
+                // oldUnderlying is non-null & underlying network itself has not changed
+                // (only network properties were changed).
+
+                // Network not yet set up, or child not yet connected.
+                if (mNetworkAgent != null && mChildConfig != null) {
+                    // If only network properties changed and agent is active, update properties
+                    updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig);
+                }
+            }
+        }
+
+        protected void setupInterfaceAndNetworkAgent(
+                int token,
+                @NonNull IpSecTunnelInterface tunnelIface,
+                @NonNull VcnChildSessionConfiguration childConfig) {
+            setupInterface(token, tunnelIface, childConfig);
+
+            if (mNetworkAgent == null) {
+                mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
+            } else {
+                updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig);
+
+                // mNetworkAgent not null, so the VCN Network has already been established. Clear
+                // the failed attempt counter and safe mode alarm since this transition is complete.
+                clearFailedAttemptCounterAndSafeModeAlarm();
+            }
+        }
+
+        @Override
+        protected void exitState() {
+            // Will only set a new alarm if no safe mode alarm is currently scheduled.
+            setSafeModeAlarm();
+        }
     }
 
     /**
@@ -961,12 +1647,75 @@
      */
     class RetryTimeoutState extends ActiveBaseState {
         @Override
-        protected void processStateMsg(Message msg) {}
+        protected void enterState() throws Exception {
+            // Reset upon entry to ConnectedState
+            mFailedAttempts++;
+
+            if (mUnderlying == null) {
+                Slog.wtf(TAG, "Underlying network was null in retry state");
+                transitionTo(mDisconnectedState);
+            } else {
+                // Safe to blindly set up, as it is cancelled and cleared on exiting this state
+                setRetryTimeoutAlarm(getNextRetryIntervalsMs());
+            }
+        }
+
+        @Override
+        protected void processStateMsg(Message msg) {
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED:
+                    final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+                    mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+                    // If new underlying is null, all networks were lost; go back to disconnected.
+                    if (mUnderlying == null) {
+                        transitionTo(mDisconnectedState);
+                        return;
+                    } else if (oldUnderlying != null
+                            && mUnderlying.network.equals(oldUnderlying.network)) {
+                        // If the network has not changed, do nothing.
+                        return;
+                    }
+
+                    // Fallthrough
+                case EVENT_RETRY_TIMEOUT_EXPIRED:
+                    transitionTo(mConnectingState);
+                    break;
+                case EVENT_DISCONNECT_REQUESTED:
+                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    break;
+                case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
+                    mGatewayStatusCallback.onEnteredSafeMode();
+                    mSafeModeTimeoutAlarm = null;
+                    break;
+                default:
+                    logUnhandledMessage(msg);
+                    break;
+            }
+        }
+
+        @Override
+        public void exitState() {
+            cancelRetryTimeoutAlarm();
+        }
+
+        private long getNextRetryIntervalsMs() {
+            final int retryDelayIndex = mFailedAttempts - 1;
+            final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs();
+
+            // Repeatedly use last item in retry timeout list.
+            if (retryDelayIndex >= retryIntervalsMs.length) {
+                return retryIntervalsMs[retryIntervalsMs.length - 1];
+            }
+
+            return retryIntervalsMs[retryDelayIndex];
+        }
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static NetworkCapabilities buildNetworkCapabilities(
-            @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
+            @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
+            @Nullable UnderlyingNetworkRecord underlying) {
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
 
         builder.addTransportType(TRANSPORT_CELLULAR);
@@ -978,13 +1727,57 @@
             builder.addCapability(cap);
         }
 
+        if (underlying != null) {
+            final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
+
+            // Mirror merged capabilities.
+            for (int cap : MERGED_CAPABILITIES) {
+                if (underlyingCaps.hasCapability(cap)) {
+                    builder.addCapability(cap);
+                }
+            }
+
+            // Set admin UIDs for ConnectivityDiagnostics use.
+            final int[] underlyingAdminUids = underlyingCaps.getAdministratorUids();
+            Arrays.sort(underlyingAdminUids); // Sort to allow contains check below.
+
+            final int[] adminUids;
+            if (underlyingCaps.getOwnerUid() > 0 // No owner UID specified
+                    && 0 > Arrays.binarySearch(// Owner UID not found in admin UID list.
+                            underlyingAdminUids, underlyingCaps.getOwnerUid())) {
+                adminUids = Arrays.copyOf(underlyingAdminUids, underlyingAdminUids.length + 1);
+                adminUids[adminUids.length - 1] = underlyingCaps.getOwnerUid();
+                Arrays.sort(adminUids);
+            } else {
+                adminUids = underlyingAdminUids;
+            }
+            builder.setAdministratorUids(adminUids);
+
+            // Set TransportInfo for SysUI use (never parcelled out of SystemServer).
+            if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
+                    && underlyingCaps.getTransportInfo() instanceof WifiInfo) {
+                final WifiInfo wifiInfo = (WifiInfo) underlyingCaps.getTransportInfo();
+                builder.setTransportInfo(new VcnTransportInfo(wifiInfo));
+            } else if (underlyingCaps.hasTransport(TRANSPORT_CELLULAR)
+                    && underlyingCaps.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
+                final TelephonyNetworkSpecifier telNetSpecifier =
+                        (TelephonyNetworkSpecifier) underlyingCaps.getNetworkSpecifier();
+                builder.setTransportInfo(new VcnTransportInfo(telNetSpecifier.getSubscriptionId()));
+            } else {
+                Slog.wtf(
+                        TAG,
+                        "Unknown transport type or missing TransportInfo/NetworkSpecifier for"
+                                + " non-null underlying network");
+            }
+        }
+
         return builder.build();
     }
 
     private static LinkProperties buildConnectedLinkProperties(
             @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
             @NonNull IpSecTunnelInterface tunnelIface,
-            @NonNull ChildSessionConfiguration childConfig) {
+            @NonNull VcnChildSessionConfiguration childConfig) {
         final LinkProperties lp = new LinkProperties();
 
         lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1035,17 +1828,25 @@
         }
     }
 
-    private class ChildSessionCallbackImpl implements ChildSessionCallback {
+    /** Implementation of ChildSessionCallback, exposed for testing. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public class VcnChildSessionCallback implements ChildSessionCallback {
         private final int mToken;
 
-        ChildSessionCallbackImpl(int token) {
+        VcnChildSessionCallback(int token) {
             mToken = token;
         }
 
+        /** Internal proxy method for injecting of mocked ChildSessionConfiguration */
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
+            Slog.v(TAG, "ChildOpened for token " + mToken);
+            childOpened(mToken, childConfig);
+        }
+
         @Override
         public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
-            Slog.v(TAG, "ChildOpened for token " + mToken);
-            childOpened(mToken, childConfig);
+            onOpened(new VcnChildSessionConfiguration(childConfig));
         }
 
         @Override
@@ -1067,6 +1868,15 @@
         }
 
         @Override
+        public void onIpSecTransformsMigrated(
+                @NonNull IpSecTransform inIpSecTransform,
+                @NonNull IpSecTransform outIpSecTransform) {
+            Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
+            onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN);
+            onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT);
+        }
+
+        @Override
         public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
             // Nothing to be done; no references to the IpSecTransform are held, and this transform
             // will be closed by the IKE library.
@@ -1075,6 +1885,11 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setTunnelInterface(IpSecTunnelInterface tunnelIface) {
+        mTunnelIface = tunnelIface;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
     UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
         return mUnderlyingNetworkTrackerCallback;
     }
@@ -1128,7 +1943,7 @@
                 buildIkeParams(),
                 buildChildParams(),
                 new IkeSessionCallbackImpl(token),
-                new ChildSessionCallbackImpl(token));
+                new VcnChildSessionCallback(token));
     }
 
     /** External dependencies used by VcnGatewayConnection, for injection in tests */
@@ -1138,10 +1953,15 @@
         public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
                 VcnContext vcnContext,
                 ParcelUuid subscriptionGroup,
+                TelephonySubscriptionSnapshot snapshot,
                 Set<Integer> requiredUnderlyingNetworkCapabilities,
                 UnderlyingNetworkTrackerCallback callback) {
             return new UnderlyingNetworkTracker(
-                    vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback);
+                    vcnContext,
+                    subscriptionGroup,
+                    snapshot,
+                    requiredUnderlyingNetworkCapabilities,
+                    callback);
         }
 
         /** Builds a new IkeSession. */
@@ -1158,6 +1978,55 @@
                     ikeSessionCallback,
                     childSessionCallback);
         }
+
+        /** Builds a new WakeLock. */
+        public VcnWakeLock newWakeLock(
+                @NonNull Context context, int wakeLockFlag, @NonNull String wakeLockTag) {
+            return new VcnWakeLock(context, wakeLockFlag, wakeLockTag);
+        }
+
+        /** Builds a new WakeupMessage. */
+        public WakeupMessage newWakeupMessage(
+                @NonNull VcnContext vcnContext,
+                @NonNull Handler handler,
+                @NonNull String tag,
+                @NonNull Runnable runnable) {
+            return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
+        }
+
+        /** Gets the elapsed real time since boot, in millis. */
+        public long getElapsedRealTime() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
+
+    /**
+     * Proxy implementation of Child Session Configuration, used for testing.
+     *
+     * <p>This wrapper allows mocking of the final, parcelable ChildSessionConfiguration object for
+     * testing purposes. This is the unfortunate result of mockito-inline (for mocking final
+     * classes) not working properly with system services & associated classes.
+     *
+     * <p>This class MUST EXCLUSIVELY be a passthrough, proxying calls directly to the actual
+     * ChildSessionConfiguration.
+     */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class VcnChildSessionConfiguration {
+        private final ChildSessionConfiguration mChildConfig;
+
+        public VcnChildSessionConfiguration(ChildSessionConfiguration childConfig) {
+            mChildConfig = childConfig;
+        }
+
+        /** Retrieves the addresses to be used inside the tunnel. */
+        public List<LinkAddress> getInternalAddresses() {
+            return mChildConfig.getInternalAddresses();
+        }
+
+        /** Retrieves the DNS servers to be used inside the tunnel. */
+        public List<InetAddress> getInternalDnsServers() {
+            return mChildConfig.getInternalDnsServers();
+        }
     }
 
     /** Proxy implementation of IKE session, used for testing. */
@@ -1208,4 +2077,34 @@
             mImpl.setNetwork(network);
         }
     }
+
+    /** Proxy Implementation of WakeLock, used for testing. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class VcnWakeLock {
+        private final WakeLock mImpl;
+
+        public VcnWakeLock(@NonNull Context context, int flags, @NonNull String tag) {
+            final PowerManager powerManager = context.getSystemService(PowerManager.class);
+            mImpl = powerManager.newWakeLock(flags, tag);
+            mImpl.setReferenceCounted(false /* isReferenceCounted */);
+        }
+
+        /**
+         * Acquire this WakeLock.
+         *
+         * <p>Synchronize this action to minimize locking around WakeLock use.
+         */
+        public synchronized void acquire() {
+            mImpl.acquire();
+        }
+
+        /**
+         * Release this Wakelock.
+         *
+         * <p>Synchronize this action to minimize locking around WakeLock use.
+         */
+        public synchronized void release() {
+            mImpl.release();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index b9babae..bfeec01 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.server.vcn;
 
+import static com.android.server.VcnManagementService.VDBG;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.net.NetworkProvider;
@@ -25,6 +27,9 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
 import java.util.Objects;
 import java.util.Set;
 
@@ -52,8 +57,13 @@
         super(context, looper, VcnNetworkProvider.class.getSimpleName());
     }
 
-    // Package-private
-    void registerListener(@NonNull NetworkRequestListener listener) {
+    /**
+     * Registers a NetworkRequestListener with this NetworkProvider.
+     *
+     * <p>Upon registering, the provided listener will receive all cached requests.
+     */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public void registerListener(@NonNull NetworkRequestListener listener) {
         mListeners.add(listener);
 
         // Send listener all cached requests
@@ -62,8 +72,9 @@
         }
     }
 
-    // Package-private
-    void unregisterListener(@NonNull NetworkRequestListener listener) {
+    /** Unregisters the specified listener from receiving future NetworkRequests. */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public void unregisterListener(@NonNull NetworkRequestListener listener) {
         mListeners.remove(listener);
     }
 
@@ -74,11 +85,16 @@
 
     @Override
     public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
-        Slog.v(
-                TAG,
-                String.format(
-                        "Network requested: Request = %s, score = %d, providerId = %d",
-                        request, score, providerId));
+        if (VDBG) {
+            Slog.v(
+                    TAG,
+                    "Network requested: Request = "
+                            + request
+                            + ", score = "
+                            + score
+                            + ", providerId = "
+                            + providerId);
+        }
 
         final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 7af237b..fd8fa82 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2023,13 +2023,6 @@
             final ActivityRecord top = targetTask.performClearTaskForReuseLocked(mStartActivity,
                     mLaunchFlags);
 
-            // The above code can remove {@code reusedActivity} from the task, leading to the
-            // {@code ActivityRecord} removing its reference to the {@code Task}. The task
-            // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
-            if (targetTaskTop.getTask() == null) {
-                targetTask.addChild(targetTaskTop);
-            }
-
             if (top != null) {
                 if (top.isRootOfTask()) {
                     // Activity aliases may mean we use different intents for the top activity,
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index e0db93a..ea47a27 100644
--- a/services/core/jni/Android.bp
+++ b/services/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_static {
     name: "libservices.core",
     defaults: ["libservices.core-libs"],
@@ -28,6 +37,7 @@
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_ConsumerIrService.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
+        "com_android_server_connectivity_Vpn.cpp",
         "com_android_server_gpu_GpuService.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
         "com_android_server_input_InputManagerService.cpp",
@@ -147,11 +157,11 @@
         "android.hardware.light@2.0",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
         "android.hardware.power.stats@1.0",
         "android.hardware.thermal@1.0",
         "android.hardware.tv.input@1.0",
-        "android.hardware.vibrator-cpp",
+        "android.hardware.vibrator-V1-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
@@ -160,7 +170,7 @@
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
         "android.frameworks.stats@1.0",
-        "android.system.suspend.control-cpp",
+        "android.system.suspend.control-V1-cpp",
         "android.system.suspend.control.internal-cpp",
         "android.system.suspend@1.0",
         "service.incremental",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 389d07a..bbcc2c1 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -11,6 +11,9 @@
 per-file com_android_server_HardwarePropertiesManagerService.cpp = michaelwr@google.com, santoscordon@google.com
 per-file com_android_server_power_PowerManagerService.* = michaelwr@google.com, santoscordon@google.com
 
+# BatteryStats
+per-file com_android_server_am_BatteryStatsService.cpp = file:/BATTERY_STATS_OWNERS
+
 per-file Android.bp = file:platform/build/soong:/OWNERS
 per-file com_android_server_Usb* = file:/services/usb/OWNERS
 per-file com_android_server_Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/packages/Connectivity/service/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
similarity index 100%
rename from packages/Connectivity/service/jni/com_android_server_connectivity_Vpn.cpp
rename to services/core/jni/com_android_server_connectivity_Vpn.cpp
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ccf685c..1e6f053 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -40,6 +40,7 @@
 int register_android_server_vr_VrManagerService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
+int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
 int register_android_server_tv_TvUinputBridge(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -91,6 +92,7 @@
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GnssLocationProvider(env);
+    register_android_server_connectivity_Vpn(env);
     register_android_server_devicepolicy_CryptoTestHelper(env);
     register_android_server_ConsumerIrService(env);
     register_android_server_BatteryStatsService(env);
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 3690afc..a9b85e6 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/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"],
+}
+
 xsd_config {
     name: "default-permissions",
     srcs: ["default-permissions.xsd"],
diff --git a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
index e27e1b8..1406dbb 100644
--- a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
+++ b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
@@ -27,6 +27,13 @@
         <xs:attribute type="xs:boolean" name="enabled" use="required" />
     </xs:complexType>
 
+    <xs:complexType name="raw-override-value">
+        <xs:attribute type="xs:string" name="packageName" use="required" />
+        <xs:attribute type="xs:long" name="minVersionCode" />
+        <xs:attribute type="xs:long" name="maxVersionCode" />
+        <xs:attribute type="xs:boolean" name="enabled" use="required" />
+    </xs:complexType>
+
     <xs:complexType name="change-overrides">
         <xs:attribute type="xs:long" name="changeId" use="required"/>
         <xs:element name="validated">
@@ -43,6 +50,13 @@
                 </xs:sequence>
             </xs:complexType>
         </xs:element>
+        <xs:element name="raw">
+            <xs:complexType>
+                <xs:sequence>
+                    <xs:element name="raw-override-value" type="raw-override-value" maxOccurs="unbounded" minOccurs="0" />
+                </xs:sequence>
+            </xs:complexType>
+        </xs:element>
     </xs:complexType>
 
     <xs:element name="overrides">
diff --git a/services/core/xsd/platform-compat/overrides/schema/current.txt b/services/core/xsd/platform-compat/overrides/schema/current.txt
index 08b8207..a5ccffc 100644
--- a/services/core/xsd/platform-compat/overrides/schema/current.txt
+++ b/services/core/xsd/platform-compat/overrides/schema/current.txt
@@ -5,9 +5,11 @@
     ctor public ChangeOverrides();
     method public long getChangeId();
     method public com.android.server.compat.overrides.ChangeOverrides.Deferred getDeferred();
+    method public com.android.server.compat.overrides.ChangeOverrides.Raw getRaw();
     method public com.android.server.compat.overrides.ChangeOverrides.Validated getValidated();
     method public void setChangeId(long);
     method public void setDeferred(com.android.server.compat.overrides.ChangeOverrides.Deferred);
+    method public void setRaw(com.android.server.compat.overrides.ChangeOverrides.Raw);
     method public void setValidated(com.android.server.compat.overrides.ChangeOverrides.Validated);
   }
 
@@ -16,6 +18,11 @@
     method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
   }
 
+  public static class ChangeOverrides.Raw {
+    ctor public ChangeOverrides.Raw();
+    method public java.util.List<com.android.server.compat.overrides.RawOverrideValue> getRawOverrideValue();
+  }
+
   public static class ChangeOverrides.Validated {
     ctor public ChangeOverrides.Validated();
     method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
@@ -34,6 +41,18 @@
     method public java.util.List<com.android.server.compat.overrides.ChangeOverrides> getChangeOverrides();
   }
 
+  public class RawOverrideValue {
+    ctor public RawOverrideValue();
+    method public boolean getEnabled();
+    method public long getMaxVersionCode();
+    method public long getMinVersionCode();
+    method public String getPackageName();
+    method public void setEnabled(boolean);
+    method public void setMaxVersionCode(long);
+    method public void setMinVersionCode(long);
+    method public void setPackageName(String);
+  }
+
   public class XmlParser {
     ctor public XmlParser();
     method public static com.android.server.compat.overrides.Overrides read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/xsd/vts/Android.bp b/services/core/xsd/vts/Android.bp
index a942108..4d3c79e 100644
--- a/services/core/xsd/vts/Android.bp
+++ b/services/core/xsd/vts/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_test {
     name: "vts_defaultPermissions_validate_test",
     srcs: [
diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp
index df054b0..0d31673 100644
--- a/services/coverage/Android.bp
+++ b/services/coverage/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"],
+}
+
 filegroup {
     name: "services.coverage-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 7a80fb1..2e8a0a8 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/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"],
+}
+
 filegroup {
     name: "services.devicepolicy-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 43537d0..9caef13 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -197,6 +197,7 @@
 import android.net.IIpConnectivityMetrics;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.net.VpnManager;
 import android.net.metrics.IpConnectivityLog;
 import android.net.wifi.WifiManager;
 import android.os.Binder;
@@ -2245,6 +2246,10 @@
             return mContext.getSystemService(ConnectivityManager.class);
         }
 
+        VpnManager getVpnManager() {
+            return mContext.getSystemService(VpnManager.class);
+        }
+
         LocationManager getLocationManager() {
             return mContext.getSystemService(LocationManager.class);
         }
@@ -7090,7 +7095,7 @@
                 }
             }
             // If some package is uninstalled after the check above, it will be ignored by CM.
-            if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser(
+            if (!mInjector.getVpnManager().setAlwaysOnVpnPackageForUser(
                     userId, vpnPackage, lockdown, lockdownAllowlist)) {
                 throw new UnsupportedOperationException();
             }
@@ -7121,7 +7126,7 @@
 
         final int userId = mInjector.userHandleGetCallingUserId();
         return mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId));
+                () -> mInjector.getVpnManager().getAlwaysOnVpnPackageForUser(userId));
     }
 
     @Override
@@ -7139,7 +7144,7 @@
 
         final int userId = mInjector.userHandleGetCallingUserId();
         return mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(userId));
+                () -> mInjector.getVpnManager().isVpnLockdownEnabled(userId));
     }
 
     @Override
@@ -7158,7 +7163,7 @@
 
         final int userId = mInjector.userHandleGetCallingUserId();
         return mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId));
+                () -> mInjector.getVpnManager().getVpnLockdownAllowlist(userId));
     }
 
     private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index e978ed4..7e1e99f 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/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"],
+}
+
 cc_defaults {
     name: "service.incremental-proto-defaults",
 
@@ -51,9 +60,9 @@
     static_libs: [
         "libbase",
         "libext2_uuid",
-        "libdataloader_aidl-unstable-cpp",
-        "libincremental_aidl-unstable-cpp",
-        "libincremental_manager_aidl-unstable-cpp",
+        "libdataloader_aidl-cpp",
+        "libincremental_aidl-cpp",
+        "libincremental_manager_aidl-cpp",
         "libprotobuf-cpp-lite",
         "service.incremental.proto",
         "libutils",
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0ae10b6..a3cadf3 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -88,7 +88,6 @@
     }
     sp<ProcessState> ps(ProcessState::self());
     ps->startThreadPool();
-    ps->giveThreadPoolName();
     // sm->addService increments the reference count, and now we're OK with returning the pointer.
     return self.get();
 }
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index 1801f3b..a2768c6 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -21,6 +21,10 @@
 import android.Manifest;
 import android.content.Context;
 import android.os.ISystemConfig;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -64,6 +68,22 @@
             return SystemConfig.getInstance()
                     .getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
         }
+
+        @Override
+        public int[] getSystemPermissionUids(String permissionName) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS,
+                    "getSystemPermissionUids requires GET_RUNTIME_PERMISSIONS");
+            final List<Integer> uids = new ArrayList<>();
+            final SparseArray<ArraySet<String>> systemPermissions =
+                    SystemConfig.getInstance().getSystemPermissions();
+            for (int i = 0; i < systemPermissions.size(); i++) {
+                final ArraySet<String> permissions = systemPermissions.valueAt(i);
+                if (permissions != null && permissions.contains(permissionName)) {
+                    uids.add(systemPermissions.keyAt(i));
+                }
+            }
+            return ArrayUtils.convertToIntArray(uids);
+        }
     };
 
     public SystemConfigService(Context context) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 203de9d..18c7e12 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,7 +97,6 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
-import com.android.server.apphibernation.AppHibernationService;
 import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.AuthService;
@@ -139,6 +138,7 @@
 import com.android.server.om.OverlayManagerService;
 import com.android.server.os.BugreportManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
+import com.android.server.os.NativeTombstoneManagerService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.people.PeopleService;
 import com.android.server.pm.BackgroundDexOptService;
@@ -174,6 +174,7 @@
 import com.android.server.testharness.TestHarnessModeService;
 import com.android.server.textclassifier.TextClassificationManagerService;
 import com.android.server.textservices.TextServicesManagerService;
+import com.android.server.tracing.TracingServiceProxy;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.tv.TvRemoteService;
@@ -1072,6 +1073,11 @@
         mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
+        // Tracks native tombstones.
+        t.traceBegin("StartNativeTombstoneManagerService");
+        mSystemServiceManager.startService(NativeTombstoneManagerService.class);
+        t.traceEnd();
+
         // Service to capture bugreports.
         t.traceBegin("StartBugreportManagerService");
         mSystemServiceManager.startService(BugreportManagerService.class);
@@ -1097,6 +1103,7 @@
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
         IpSecService ipSecService = null;
+        VpnManagerService vpnManager = null;
         VcnManagementService vcnManagement = null;
         NetworkStatsService networkStats = null;
         NetworkPolicyManagerService networkPolicy = null;
@@ -1526,7 +1533,7 @@
 
             t.traceBegin("StartIpSecService");
             try {
-                ipSecService = IpSecService.create(context, networkManagement);
+                ipSecService = IpSecService.create(context);
                 ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
             } catch (Throwable e) {
                 reportWtf("starting IpSec Service", e);
@@ -1630,6 +1637,15 @@
             networkPolicy.bindConnectivityManager(connectivity);
             t.traceEnd();
 
+            t.traceBegin("StartVpnManagerService");
+            try {
+                vpnManager = VpnManagerService.create(context);
+                ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
+            } catch (Throwable e) {
+                reportWtf("starting VPN Manager Service", e);
+            }
+            t.traceEnd();
+
             t.traceBegin("StartVcnManagementService");
             try {
                 vcnManagement = VcnManagementService.create(context);
@@ -1866,11 +1882,9 @@
             mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
             t.traceEnd();
 
-            if (AppHibernationService.isAppHibernationEnabled()) {
-                t.traceBegin("StartAppHibernationService");
-                mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
-                t.traceEnd();
-            }
+            t.traceBegin("StartAppHibernationService");
+            mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
+            t.traceEnd();
 
             if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
                 t.traceBegin("StartGestureLauncher");
@@ -2201,6 +2215,11 @@
         mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
         t.traceEnd();
 
+        // Perfetto TracingServiceProxy
+        t.traceBegin("startTracingServiceProxy");
+        mSystemServiceManager.startService(TracingServiceProxy.class);
+        t.traceEnd();
+
         // It is now time to start up the app processes...
 
         t.traceBegin("MakeVibratorServiceReady");
@@ -2326,6 +2345,7 @@
         final MediaRouterService mediaRouterF = mediaRouter;
         final MmsServiceBroker mmsServiceF = mmsService;
         final IpSecService ipSecServiceF = ipSecService;
+        final VpnManagerService vpnManagerF = vpnManager;
         final VcnManagementService vcnManagementF = vcnManagement;
         final WindowManagerService windowManagerF = wm;
         final ConnectivityManager connectivityF = (ConnectivityManager)
@@ -2433,6 +2453,15 @@
                 reportWtf("making Connectivity Service ready", e);
             }
             t.traceEnd();
+            t.traceBegin("MakeVpnManagerServiceReady");
+            try {
+                if (vpnManagerF != null) {
+                    vpnManagerF.systemReady();
+                }
+            } catch (Throwable e) {
+                reportWtf("making VpnManagerService ready", e);
+            }
+            t.traceEnd();
             t.traceBegin("MakeVcnManagementServiceReady");
             try {
                 if (vcnManagementF != null) {
diff --git a/services/midi/Android.bp b/services/midi/Android.bp
index 6bce5b5..cbb36a8 100644
--- a/services/midi/Android.bp
+++ b/services/midi/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"],
+}
+
 filegroup {
     name: "services.midi-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/net/Android.bp b/services/net/Android.bp
index e0bb67a..93aa461 100644
--- a/services/net/Android.bp
+++ b/services/net/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"],
+}
+
 filegroup {
     name: "services.net-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/people/Android.bp b/services/people/Android.bp
index c863f1f..b2327b5 100644
--- a/services/people/Android.bp
+++ b/services/people/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_static {
     name: "services.people",
     defaults: ["services_defaults"],
diff --git a/services/print/Android.bp b/services/print/Android.bp
index 93b5ef0..feaeeed 100644
--- a/services/print/Android.bp
+++ b/services/print/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"],
+}
+
 filegroup {
     name: "services.print-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/profcollect/Android.bp b/services/profcollect/Android.bp
index 68fba55..a636d67 100644
--- a/services/profcollect/Android.bp
+++ b/services/profcollect/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"],
+}
+
 filegroup {
   name: "services.profcollect-javasources",
   srcs: ["src/**/*.java"],
diff --git a/services/restrictions/Android.bp b/services/restrictions/Android.bp
index 2883095..9fd97f1 100644
--- a/services/restrictions/Android.bp
+++ b/services/restrictions/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"],
+}
+
 filegroup {
     name: "services.restrictions-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
index 1ae2aec..52eae21 100644
--- a/services/robotests/Android.bp
+++ b/services/robotests/Android.bp
@@ -16,6 +16,15 @@
 // FrameworksServicesLib app just for Robolectric test target      #
 //##################################################################
 
+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_app {
     name: "FrameworksServicesLib",
     platform_apis: true,
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index 32587ac..506e156 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -15,6 +15,15 @@
 //##################################################################
 // BackupFrameworksServicesLib app just for Robolectric test target      #
 //##################################################################
+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_app {
     name: "BackupFrameworksServicesLib",
     platform_apis: true,
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
index 46a81aae..a7ae578 100644
--- a/services/startop/Android.bp
+++ b/services/startop/Android.bp
@@ -14,6 +14,17 @@
  * 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library_static {
     name: "services.startop",
     defaults: ["services_defaults"],
diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp
index 54968c0..7ac44ce 100644
--- a/services/systemcaptions/Android.bp
+++ b/services/systemcaptions/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"],
+}
+
 filegroup {
     name: "services.systemcaptions-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp
index a2668a1..19fdf60 100644
--- a/services/tests/PackageManagerComponentOverrideTests/Android.bp
+++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp
@@ -17,6 +17,15 @@
 // NOTE: This test is separate from service tests since it relies on same vs different calling UID,
 // and this is more representative of a real caller. It also uses Mockito extended, and this
 // prevents converting the entire services test module.
+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: "PackageManagerComponentOverrideTests",
     srcs: [
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 41dfade..cf745c2 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/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"],
+}
+
 java_test_host {
     name: "PackageManagerServiceHostTests",
     srcs: ["src/**/*.kt"],
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
index c9b2927..626b113 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/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: "PackageManagerDummyAppVersion1",
     manifest: "AndroidManifestVersion1.xml"
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index b4e0f10..9202f67 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/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: "FrameworksMockingServicesTests",
 
diff --git a/services/tests/rescueparty/Android.bp b/services/tests/rescueparty/Android.bp
index 6733af4..ed7de96 100644
--- a/services/tests/rescueparty/Android.bp
+++ b/services/tests/rescueparty/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"],
+}
+
 cc_test {
     name: "log_rescueparty_reset_event_reported",
     srcs: ["log_rescueparty_reset_event_reported.cpp"],
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 979f4e1..08e2def 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -2,6 +2,15 @@
 // Build FrameworksServicesTests package
 //########################################################################
 
+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: "FrameworksServicesTests",
 
@@ -82,7 +91,7 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V5-cpp",
     ],
 
     dxflags: ["--multi-dex"],
diff --git a/services/tests/servicestests/aidl/Android.bp b/services/tests/servicestests/aidl/Android.bp
index d4e53dd..6780531 100644
--- a/services/tests/servicestests/aidl/Android.bp
+++ b/services/tests/servicestests/aidl/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"],
+}
+
 java_library {
     name: "servicestests-aidl",
     sdk_version: "current",
diff --git a/services/tests/servicestests/apks/Android.bp b/services/tests/servicestests/apks/Android.bp
index 3e11604..6c91806 100644
--- a/services/tests/servicestests/apks/Android.bp
+++ b/services/tests/servicestests/apks/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_defaults {
     name: "FrameworksServicesTests_apks_defaults",
     sdk_version: "current",
diff --git a/services/tests/servicestests/apks/install-split-base/Android.bp b/services/tests/servicestests/apks/install-split-base/Android.bp
index 1b62aa2..39992f6 100644
--- a/services/tests/servicestests/apks/install-split-base/Android.bp
+++ b/services/tests/servicestests/apks/install-split-base/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_helper_app {
     name: "FrameworksServicesTests_install_split_base",
     defaults: ["FrameworksServicesTests_apks_defaults"],
diff --git a/services/tests/servicestests/apks/install-split-feature-a/Android.bp b/services/tests/servicestests/apks/install-split-feature-a/Android.bp
index 45d8917..ca7295e 100644
--- a/services/tests/servicestests/apks/install-split-feature-a/Android.bp
+++ b/services/tests/servicestests/apks/install-split-feature-a/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_helper_app {
     name: "FrameworksServicesTests_install_split_feature_a",
     defaults: ["FrameworksServicesTests_apks_defaults"],
diff --git a/services/tests/servicestests/apks/install_intent_filters/Android.bp b/services/tests/servicestests/apks/install_intent_filters/Android.bp
index 59c8524..643824d 100644
--- a/services/tests/servicestests/apks/install_intent_filters/Android.bp
+++ b/services/tests/servicestests/apks/install_intent_filters/Android.bp
@@ -1,7 +1,15 @@
+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: "FrameworksServicesTests_install_intent_filters",
     defaults: ["FrameworksServicesTests_apks_defaults"],
 
     srcs: ["**/*.java"],
 }
-
diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
index c24aa2b..feb152c 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/Android.bp
+++ b/services/tests/servicestests/apks/install_uses_sdk/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_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_r0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
index 50e7a03..58d6dae 100644
--- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
+++ b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
@@ -34,7 +34,7 @@
         assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
 
         // The constructor has the side effect of writing to file
-        new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath(), "/dev/null");
+        new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath());
 
         assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
     }
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 45bca68..07f6732 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -16,16 +16,18 @@
 
 package com.android.server.apphibernation;
 
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+
 import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.returnsArgAt;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
-import static org.mockito.internal.verification.VerificationModeFactory.times;
 
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
@@ -48,6 +50,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
@@ -76,18 +79,21 @@
     private IActivityManager mIActivityManager;
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private HibernationStateDiskStore<UserLevelState> mHibernationStateDiskStore;
     @Captor
     private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
 
     @Before
     public void setUp() throws RemoteException {
+        // Share class loader to allow access to package-private classes
+        System.setProperty("dexmaker.share_classloader", "true");
         MockitoAnnotations.initMocks(this);
         doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
 
-        mAppHibernationService = new AppHibernationService(mContext, mIPackageManager,
-                mIActivityManager, mUserManager);
+        mAppHibernationService = new AppHibernationService(new MockInjector(mContext));
 
-        verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
+        verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
         mBroadcastReceiver = mReceiverCaptor.getValue();
 
         doReturn(mUserInfos).when(mUserManager).getUsers();
@@ -95,12 +101,21 @@
         doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
                 anyInt(), anyBoolean(), anyBoolean(), any(), any());
 
-        addUser(USER_ID_1);
+        List<PackageInfo> packages = new ArrayList<>();
+        packages.add(makePackageInfo(PACKAGE_NAME_1));
+        doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
+                intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
         mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+        UserInfo userInfo = addUser(USER_ID_1);
+        mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
+        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
+
+        mAppHibernationService.mIsServiceEnabled = true;
     }
 
     @Test
-    public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException {
+    public void testSetHibernatingForUser_packageIsHibernating() {
         // WHEN we hibernate a package for a user
         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
@@ -109,8 +124,7 @@
     }
 
     @Test
-    public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating()
-            throws RemoteException {
+    public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating() {
         // WHEN a new package is added and it is hibernated
         Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
                 Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
@@ -124,17 +138,12 @@
     }
 
     @Test
-    public void testSetHibernatingForUser_newUserAdded_packageIsHibernating()
+    public void testSetHibernatingForUser_newUserUnlocked_packageIsHibernating()
             throws RemoteException {
         // WHEN a new user is added and a package from the user is hibernated
-        List<PackageInfo> userPackages = new ArrayList<>();
-        userPackages.add(makePackageInfo(PACKAGE_NAME_1));
-        doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
-                .getInstalledPackages(anyInt(), eq(USER_ID_2));
-        Intent intent = new Intent(Intent.ACTION_USER_ADDED);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
-        mBroadcastReceiver.onReceive(mContext, intent);
-
+        UserInfo user2 = addUser(USER_ID_2);
+        mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
+        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
 
         // THEN the new user's package is hibernated
@@ -142,8 +151,7 @@
     }
 
     @Test
-    public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()
-            throws RemoteException {
+    public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating() {
         // GIVEN a package is currently hibernated
         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
@@ -168,25 +176,25 @@
     }
 
     /**
-     * Add a mock user with one package. Must be called before
-     * {@link AppHibernationService#onBootPhase(int)} to work properly.
+     * Add a mock user with one package.
      */
-    private void addUser(int userId) throws RemoteException {
-        addUser(userId, new String[]{PACKAGE_NAME_1});
+    private UserInfo addUser(int userId) throws RemoteException {
+        return addUser(userId, new String[]{PACKAGE_NAME_1});
     }
 
     /**
-     * Add a mock user with the packages specified. Must be called before
-     * {@link AppHibernationService#onBootPhase(int)} to work properly
+     * Add a mock user with the packages specified.
      */
-    private void addUser(int userId, String[] packageNames) throws RemoteException {
-        mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */));
+    private UserInfo addUser(int userId, String[] packageNames) throws RemoteException {
+        UserInfo userInfo = new UserInfo(userId, "user_" + userId, 0 /* flags */);
+        mUserInfos.add(userInfo);
         List<PackageInfo> userPackages = new ArrayList<>();
         for (String pkgName : packageNames) {
             userPackages.add(makePackageInfo(pkgName));
         }
         doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
-                .getInstalledPackages(anyInt(), eq(userId));
+                .getInstalledPackages(intThat(arg -> (arg & MATCH_ANY_USER) == 0), eq(userId));
+        return userInfo;
     }
 
     private static PackageInfo makePackageInfo(String packageName) {
@@ -194,4 +202,42 @@
         pkg.packageName = packageName;
         return pkg;
     }
+
+    private class MockInjector implements AppHibernationService.Injector {
+        private final Context mContext;
+
+        MockInjector(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public IActivityManager getActivityManager() {
+            return mIActivityManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        public IPackageManager getPackageManager() {
+            return mIPackageManager;
+        }
+
+        @Override
+        public UserManager getUserManager() {
+            return mUserManager;
+        }
+
+        @Override
+        public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
+            return Mockito.mock(HibernationStateDiskStore.class);
+        }
+
+        @Override
+        public HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId) {
+            return Mockito.mock(HibernationStateDiskStore.class);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java
new file mode 100644
index 0000000..59f3c35
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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 com.android.server.apphibernation;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.FileUtils;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+@SmallTest
+public class HibernationStateDiskStoreTest {
+    private static final String STATES_FILE_NAME = "states";
+    private final MockScheduledExecutorService mMockScheduledExecutorService =
+            new MockScheduledExecutorService();
+
+    private File mFile;
+    private HibernationStateDiskStore<String> mHibernationStateDiskStore;
+
+
+    @Before
+    public void setUp() {
+        mFile = new File(InstrumentationRegistry.getContext().getCacheDir(), "test");
+        mHibernationStateDiskStore = new HibernationStateDiskStore<>(mFile,
+                new MockProtoReadWriter(), mMockScheduledExecutorService, STATES_FILE_NAME);
+    }
+
+    @After
+    public void tearDown() {
+        FileUtils.deleteContentsAndDir(mFile);
+    }
+
+    @Test
+    public void testScheduleWriteHibernationStates_writesDataThatCanBeRead() {
+        // GIVEN some data to be written
+        List<String> toWrite = new ArrayList<>(Arrays.asList("A", "B"));
+
+        // WHEN the data is written
+        mHibernationStateDiskStore.scheduleWriteHibernationStates(toWrite);
+        mMockScheduledExecutorService.executeScheduledTask();
+
+        // THEN the read data is equal to what was written
+        List<String> storedStrings = mHibernationStateDiskStore.readHibernationStates();
+        for (int i = 0; i < toWrite.size(); i++) {
+            assertEquals(toWrite.get(i), storedStrings.get(i));
+        }
+    }
+
+    @Test
+    public void testScheduleWriteHibernationStates_laterWritesOverwritePrevious() {
+        // GIVEN store has some data it is scheduled to write
+        mHibernationStateDiskStore.scheduleWriteHibernationStates(
+                new ArrayList<>(Arrays.asList("C", "D")));
+
+        // WHEN a write is scheduled with new data
+        List<String> toWrite = new ArrayList<>(Arrays.asList("A", "B"));
+        mHibernationStateDiskStore.scheduleWriteHibernationStates(toWrite);
+        mMockScheduledExecutorService.executeScheduledTask();
+
+        // THEN the written data is the last scheduled data
+        List<String> storedStrings = mHibernationStateDiskStore.readHibernationStates();
+        for (int i = 0; i < toWrite.size(); i++) {
+            assertEquals(toWrite.get(i), storedStrings.get(i));
+        }
+    }
+
+    /**
+     * Mock proto read / writer that just writes and reads a list of String data.
+     */
+    private final class MockProtoReadWriter implements ProtoReadWriter<List<String>> {
+        private static final long FIELD_ID = 1;
+
+        @Override
+        public void writeToProto(@NonNull ProtoOutputStream stream,
+                @NonNull List<String> data) {
+            for (int i = 0, size = data.size(); i < size; i++) {
+                stream.write(FIELD_ID, data.get(i));
+            }
+        }
+
+        @Nullable
+        @Override
+        public List<String> readFromProto(@NonNull ProtoInputStream stream)
+                throws IOException {
+            ArrayList<String> list = new ArrayList<>();
+            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                list.add(stream.readString(FIELD_ID));
+            }
+            return list;
+        }
+    }
+
+    /**
+     * Mock scheduled executor service that has minimum implementation and can synchronously
+     * execute scheduled tasks.
+     */
+    private final class MockScheduledExecutorService implements ScheduledExecutorService {
+
+        Runnable mScheduledRunnable = null;
+
+        @Override
+        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+            mScheduledRunnable = command;
+            return Mockito.mock(ScheduledFuture.class);
+        }
+
+        @Override
+        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
+                long period, TimeUnit unit) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
+                long delay, TimeUnit unit) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void shutdown() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return false;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return false;
+        }
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> Future<T> submit(Callable<T> task) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> Future<T> submit(Runnable task, T result) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Future<?> submit(Runnable task) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+                throws InterruptedException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
+                TimeUnit unit) throws InterruptedException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+                throws InterruptedException, ExecutionException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException, TimeoutException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            throw new UnsupportedOperationException();
+        }
+
+        void executeScheduledTask() {
+            mScheduledRunnable.run();
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
index d0767cc..c165c66 100644
--- a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -22,6 +22,7 @@
     private boolean mIsDebuggable;
     private int mTargetSdk;
     private String mPackageName;
+    private long mVersionCode;
 
     private ApplicationInfoBuilder() {
         mTargetSdk = -1;
@@ -46,6 +47,11 @@
         return this;
     }
 
+    ApplicationInfoBuilder withVersionCode(Long versionCode) {
+        mVersionCode = versionCode;
+        return this;
+    }
+
     ApplicationInfo build() {
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         if (mIsDebuggable) {
@@ -53,6 +59,7 @@
         }
         applicationInfo.packageName = mPackageName;
         applicationInfo.targetSdkVersion = mTargetSdk;
+        applicationInfo.longVersionCode = mVersionCode;
         return applicationInfo;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index a53ff9b..8b0e948 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -25,6 +26,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.app.compat.ChangeIdStateCache;
+import android.app.compat.PackageOverride;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -33,6 +35,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.CompatibilityOverrideConfig;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,6 +49,7 @@
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.util.Collections;
 import java.util.UUID;
 
 @RunWith(AndroidJUnit4.class)
@@ -83,6 +87,8 @@
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
         when(mBuildClassifier.isFinalBuild()).thenReturn(false);
         ChangeIdStateCache.disable();
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
+                .thenThrow(new NameNotFoundException());
     }
 
     @Test
@@ -163,6 +169,10 @@
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addDisabledChangeWithId(1234L)
                 .build();
+        ApplicationInfo info = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package").build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(info);
 
         compatConfig.addOverride(1234L, "com.some.package", true);
 
@@ -177,6 +187,10 @@
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addEnabledChangeWithId(1234L)
                 .build();
+        ApplicationInfo info = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package").build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(info);
 
         compatConfig.addOverride(1234L, "com.some.package", false);
 
@@ -191,6 +205,10 @@
         CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
         compatConfig.forceNonDebuggableFinalForTest(false);
 
+        ApplicationInfo info = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package").build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(info);
 
         compatConfig.addOverride(1234L, "com.some.package", false);
 
@@ -265,6 +283,71 @@
     }
 
     @Test
+    public void testOverrideWithAppVersion() throws Exception {
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.installed.foo")
+                .withVersionCode(100L)
+                .debuggable().build();
+        when(mPackageManager.getApplicationInfo(eq("com.installed.foo"), anyInt()))
+                .thenReturn(applicationInfo);
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1234L).build();
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        // Add override that doesn't include the installed app version
+        CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+                Collections.singletonMap(1234L,
+                        new PackageOverride.Builder()
+                                .setMaxVersionCode(99L)
+                                .setEnabled(true)
+                                .build()));
+        compatConfig.addOverrides(config, "com.installed.foo");
+        assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+        // Add override that does include the installed app version
+        config = new CompatibilityOverrideConfig(
+                Collections.singletonMap(1234L,
+                        new PackageOverride.Builder()
+                                .setMinVersionCode(100L)
+                                .setMaxVersionCode(100L)
+                                .setEnabled(true)
+                                .build()));
+        compatConfig.addOverrides(config, "com.installed.foo");
+        assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+    }
+
+    @Test
+    public void testApplyDeferredOverridesAfterInstallingAppVersion() throws Exception {
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.notinstalled.foo")
+                .withVersionCode(100L)
+                .debuggable().build();
+        when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1234L).build();
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+        // Add override before the app is available.
+        CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+                Collections.singletonMap(1234L, new PackageOverride.Builder()
+                        .setMaxVersionCode(99L)
+                        .setEnabled(true)
+                        .build()));
+        compatConfig.addOverrides(config, "com.notinstalled.foo");
+        assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+        // Pretend the app is now installed.
+        when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
+                .thenReturn(applicationInfo);
+
+        compatConfig.recheckOverrides("com.notinstalled.foo");
+        assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+    }
+
+    @Test
     public void testApplyDeferredOverrideClearsOverrideAfterUninstall() throws Exception {
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("com.installedapp.foo")
@@ -384,6 +467,8 @@
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("com.some.package")
                 .build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(applicationInfo);
 
         assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
         assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
@@ -404,6 +489,8 @@
                 .withPackageName("foo.bar")
                 .withTargetSdk(2)
                 .build();
+        when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+                .thenReturn(applicationInfo);
 
         assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
         assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
@@ -425,7 +512,8 @@
                 .withPackageName("foo.bar")
                 .withTargetSdk(2)
                 .build();
-
+        when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+                .thenReturn(applicationInfo);
         assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
         assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
         assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
@@ -533,22 +621,114 @@
                 + "            <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
                 + "            </override-value>\n"
                 + "        </validated>\n"
-                + "        <deferred>\n"
-                + "        </deferred>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
                 + "    </change-overrides>\n"
                 + "    <change-overrides changeId=\"2\">\n"
                 + "        <validated>\n"
                 + "        </validated>\n"
-                + "        <deferred>\n"
-                + "            <override-value packageName=\"bar.baz\" enabled=\"false\">\n"
-                + "            </override-value>\n"
-                + "        </deferred>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
                 + "    </change-overrides>\n"
                 + "</overrides>\n");
     }
 
     @Test
-    public void testLoadOverrides() throws Exception {
+    public void testSaveOverridesWithRanges() throws Exception {
+        File overridesFile = new File(createTempDir(), "overrides.xml");
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1L)
+                .addEnableSinceSdkChangeWithId(2, 2L)
+                .build();
+        compatConfig.forceNonDebuggableFinalForTest(true);
+        compatConfig.initOverrides(overridesFile);
+
+        compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
+                new PackageOverride.Builder()
+                        .setMinVersionCode(99L)
+                        .setMaxVersionCode(101L)
+                        .setEnabled(true)
+                        .build())), "foo.bar");
+
+        assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+                + "<overrides>\n"
+                + "    <change-overrides changeId=\"1\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"99\" maxVersionCode=\"101\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "</overrides>\n");
+    }
+
+    @Test
+    public void testLoadOverridesRaw() throws Exception {
+        File tempDir = createTempDir();
+        File overridesFile = new File(tempDir, "overrides.xml");
+        // Change 1 is enabled for foo.bar (validated)
+        // Change 2 is disabled for bar.baz (deferred)
+        String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<overrides>\n"
+                + "    <change-overrides changeId=\"1\">\n"
+                + "        <validated>\n"
+                + "            <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
+                + "            </override-value>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "    <change-overrides changeId=\"2\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "</overrides>\n";
+        writeToFile(tempDir, "overrides.xml", xmlData);
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1L)
+                .addEnableSinceSdkChangeWithId(2, 2L)
+                .build();
+        compatConfig.forceNonDebuggableFinalForTest(true);
+        compatConfig.initOverrides(overridesFile);
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("foo.bar")
+                .withVersionCode(100L)
+                .debuggable()
+                .build();
+        when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+                .thenReturn(applicationInfo);
+        when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+
+        assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+        assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+
+        compatConfig.recheckOverrides("foo.bar");
+        assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+    }
+
+    @Test
+    public void testLoadOverridesDeferred() throws Exception {
         File tempDir = createTempDir();
         File overridesFile = new File(tempDir, "overrides.xml");
         // Change 1 is enabled for foo.bar (validated)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index a1b2dc8..799b067 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -196,6 +196,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -208,6 +211,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -219,6 +225,9 @@
     public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
         mPlatformCompat.registerListener(1, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -244,6 +253,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -252,9 +264,12 @@
     }
 
     @Test
-    public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
+    public void testListenerCalledOnSetOverridesForTestTwoListeners() throws Exception {
         mPlatformCompat.registerListener(1, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -280,6 +295,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener2);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).build(),
                 PACKAGE_NAME);
@@ -299,6 +317,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener2);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
                 PACKAGE_NAME);
@@ -318,6 +339,9 @@
         mPlatformCompat.registerListener(1, mListener1);
         mPlatformCompat.registerListener(2, mListener2);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.setOverrides(
                 CompatibilityChangeConfigBuilder.create().enable(1L).build(),
                 PACKAGE_NAME);
@@ -336,6 +360,9 @@
     public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
         mPlatformCompat.registerListener(1, mListener1);
 
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
         mPlatformCompat.clearOverride(1, PACKAGE_NAME);
         // Listener not called when a non existing override is removed.
         verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index 2205694..336bbae 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -42,6 +42,7 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Process;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.platform.test.annotations.Presubmit;
@@ -86,7 +87,8 @@
         MockitoAnnotations.initMocks(this);
         final Context context = InstrumentationRegistry.getTargetContext();
         mUserId = ActivityManager.getCurrentUser();
-        mCommand = new LockSettingsShellCommand(mLockPatternUtils);
+        mCommand = new LockSettingsShellCommand(mLockPatternUtils, context, 0,
+                Process.SHELL_UID);
         when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
index 32445fd..2eedc32 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
@@ -19,19 +19,17 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.security.GeneralSecurityException;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
 
-import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
 
 /**
  * atest FrameworksServicesTests:RebootEscrowDataTest
@@ -41,22 +39,18 @@
     private RebootEscrowKey mKey;
     private SecretKey mKeyStoreEncryptionKey;
 
-    private SecretKey generateNewRebootEscrowEncryptionKey() throws GeneralSecurityException {
-        KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
-        generator.init(new KeyGenParameterSpec.Builder(
-                "reboot_escrow_data_test_key",
-                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
-                .setKeySize(256)
-                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
-                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
-                .build());
-        return generator.generateKey();
-    }
+    // Hex encoding of a randomly generated AES key for test.
+    private static final byte[] TEST_AES_KEY = new byte[] {
+            0x44, 0x74, 0x61, 0x54, 0x29, 0x74, 0x37, 0x61,
+            0x48, 0x19, 0x12, 0x54, 0x13, 0x13, 0x52, 0x31,
+            0x70, 0x70, 0x75, 0x25, 0x27, 0x31, 0x49, 0x09,
+            0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
+    };
 
     @Before
     public void generateKey() throws Exception {
         mKey = RebootEscrowKey.generate();
-        mKeyStoreEncryptionKey = generateNewRebootEscrowEncryptionKey();
+        mKeyStoreEncryptionKey = new SecretKeySpec(TEST_AES_KEY, "AES");
     }
 
     private static byte[] getTestSp() {
@@ -114,4 +108,23 @@
         assertThat(decrypted, is(testSp));
     }
 
+    @Test
+    public void fromEncryptedData_legacyVersion_success() throws Exception {
+        byte[] testSp = getTestSp();
+        byte[] ksEncryptedBlob = AesEncryptionUtil.encrypt(mKey.getKey(), testSp);
+
+        // Write a legacy blob encrypted only by k_s.
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        DataOutputStream dos = new DataOutputStream(bos);
+        dos.writeInt(1);
+        dos.writeByte(3);
+        dos.write(ksEncryptedBlob);
+        byte[] legacyBlob = bos.toByteArray();
+
+        RebootEscrowData actual = RebootEscrowData.fromEncryptedData(mKey, legacyBlob, null);
+
+        assertThat(actual.getSpVersion(), is((byte) 3));
+        assertThat(actual.getKey().getKeyBytes(), is(mKey.getKeyBytes()));
+        assertThat(actual.getSyntheticPassword(), is(testSp));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index a4ba4c8..a896f1b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -43,6 +43,7 @@
 import android.content.ContextWrapper;
 import android.content.pm.UserInfo;
 import android.hardware.rebootescrow.IRebootEscrow;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserManager;
@@ -155,6 +156,11 @@
         }
 
         @Override
+        void post(Handler handler, Runnable runnable) {
+            runnable.run();
+        }
+
+        @Override
         public UserManager getUserManager() {
             return mUserManager;
         }
@@ -369,7 +375,7 @@
 
     @Test
     public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception {
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
     }
 
     @Test
@@ -401,7 +407,7 @@
         doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
         when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
 
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mRebootEscrow).retrieveKey();
         assertTrue(metricsSuccessCaptor.getValue());
         verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -435,7 +441,7 @@
 
         when(mServiceConnection.unwrap(any(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mServiceConnection).unwrap(any(), anyLong());
         assertTrue(metricsSuccessCaptor.getValue());
         verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -466,7 +472,7 @@
         when(mInjected.getBootCount()).thenReturn(10);
         when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
 
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mRebootEscrow).retrieveKey();
         verify(mInjected, never()).reportMetric(anyBoolean());
     }
@@ -493,7 +499,7 @@
         when(mInjected.getBootCount()).thenReturn(10);
         when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
 
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mInjected, never()).reportMetric(anyBoolean());
     }
 
@@ -527,7 +533,7 @@
         when(mInjected.getBootCount()).thenReturn(10);
         when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
 
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mInjected).reportMetric(eq(true));
     }
 
@@ -557,7 +563,7 @@
         ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
         doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
         when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
-        mService.loadRebootEscrowDataIfAvailable();
+        mService.loadRebootEscrowDataIfAvailable(null);
         verify(mRebootEscrow).retrieveKey();
         assertFalse(metricsSuccessCaptor.getValue());
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
index bc1e025..28b737b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
@@ -30,6 +30,7 @@
 
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
@@ -42,7 +43,6 @@
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
-import java.io.IOException;
 
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -130,7 +130,7 @@
     @Test
     public void getAndClearRebootEscrowKey_ServiceConnectionException_failure() throws Exception {
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
-        doThrow(IOException.class).when(mServiceConnection).unwrap(any(), anyLong());
+        doThrow(RemoteException.class).when(mServiceConnection).unwrap(any(), anyLong());
 
         assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
         mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index df19aeb..7d7af03 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -19,11 +19,13 @@
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.INetd.FIREWALL_RULE_ALLOW;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -112,8 +114,6 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkState;
@@ -1829,11 +1829,11 @@
     }
 
     /**
-     * Exhaustively test isUidNetworkingBlocked to output the expected results based on external
+     * Exhaustively test checkUidNetworkingBlocked to output the expected results based on external
      * conditions.
      */
     @Test
-    public void testIsUidNetworkingBlocked() {
+    public void testCheckUidNetworkingBlocked() {
         final ArrayList<Pair<Boolean, Integer>> expectedBlockedStates = new ArrayList<>();
 
         // Metered network. Data saver on.
@@ -1877,17 +1877,16 @@
 
     private void verifyNetworkBlockedState(boolean metered, boolean backgroundRestricted,
             ArrayList<Pair<Boolean, Integer>> expectedBlockedStateForRules) {
-        final NetworkPolicyManagerInternal npmi = LocalServices
-                .getService(NetworkPolicyManagerInternal.class);
 
         for (Pair<Boolean, Integer> pair : expectedBlockedStateForRules) {
             final boolean expectedResult = pair.first;
             final int rule = pair.second;
             assertEquals(formatBlockedStateError(UID_A, rule, metered, backgroundRestricted),
-                    expectedResult,
-                    npmi.isUidNetworkingBlocked(UID_A, rule, metered, backgroundRestricted));
+                    expectedResult, mService.checkUidNetworkingBlocked(UID_A, rule,
+                            metered, backgroundRestricted));
             assertFalse(formatBlockedStateError(SYSTEM_UID, rule, metered, backgroundRestricted),
-                    npmi.isUidNetworkingBlocked(SYSTEM_UID, rule, metered, backgroundRestricted));
+                    mService.checkUidNetworkingBlocked(SYSTEM_UID, rule, metered,
+                            backgroundRestricted));
         }
     }
 
@@ -1986,13 +1985,6 @@
         return users;
     }
 
-    private NetworkInfo buildNetworkInfo() {
-        final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
-                TelephonyManager.NETWORK_TYPE_LTE, null, null);
-        ni.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
-        return ni;
-    }
-
     private LinkProperties buildLinkProperties(String iface) {
         final LinkProperties lp = new LinkProperties();
         lp.setInterfaceName(iface);
@@ -2046,13 +2038,12 @@
     }
 
     private static NetworkState buildWifi() {
-        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        networkCapabilities.addTransportType(TRANSPORT_WIFI);
         networkCapabilities.setSSID(TEST_SSID);
-        return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
+        return new NetworkState(TYPE_WIFI, prop, networkCapabilities, null, null);
     }
 
     private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
@@ -2073,10 +2064,10 @@
         when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
                 .thenReturn(mCarrierConfig);
         when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
-                new NetworkState(buildNetworkInfo(),
+                new NetworkState(TYPE_MOBILE,
                         buildLinkProperties(TEST_IFACE),
                         buildNetworkCapabilities(TEST_SUB_ID, roaming),
-                        new Network(TEST_NET_ID), TEST_IMSI, null)
+                        new Network(TEST_NET_ID), TEST_IMSI)
         });
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index ff43da6..ee0a16a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -86,6 +86,7 @@
     private TestData mBarUser0DelegateLastClassLoader;
 
     private TestData mSystemServerJar;
+    private TestData mSystemServerJarUpdatedContext;
     private TestData mSystemServerJarInvalid;
 
     private int mUser0;
@@ -113,6 +114,8 @@
 
         mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
         mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+        mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0,
+                DELEGATE_LAST_CLASS_LOADER_NAME);
 
         mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null,
                 mInstaller, mInstallLock);
@@ -522,6 +525,24 @@
     }
 
     @Test
+    public void testSystemServerOverwritesContext() {
+        // Record bar secondaries with the default PathClassLoader.
+        List<String> secondaries = mSystemServerJar.getSecondaryDexPaths();
+
+        notifyDexLoad(mSystemServerJar, secondaries, mUser0);
+        PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
+        assertSecondaryUse(mSystemServerJar, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
+
+        // Record bar secondaries again with a different class loader. This will change the context.
+        notifyDexLoad(mSystemServerJarUpdatedContext, secondaries, mUser0);
+
+        pui = getPackageUseInfo(mSystemServerJar);
+        // We expect that all the contexts to be updated according to the last notify.
+        assertSecondaryUse(mSystemServerJarUpdatedContext, pui, secondaries,
+                /*isUsedByOtherApps*/false, mUser0);
+    }
+
+    @Test
     public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
         List<String> secondaries = mBarUser0.getSecondaryDexPaths();
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index caa8ae5..59e87d4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -41,6 +41,7 @@
 
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.parsing.TestPackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 
@@ -57,6 +58,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -66,6 +69,9 @@
 public class DexMetadataHelperTest {
     private static final String APK_FILE_EXTENSION = ".apk";
     private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
+    private static final String DEX_METADATA_PACKAGE_NAME =
+            "com.android.frameworks.servicestests.install_split";
+    private static long DEX_METADATA_VERSION_CODE = 30;
 
     @Rule
     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -78,12 +84,46 @@
     }
 
     private File createDexMetadataFile(String apkFileName) throws IOException {
+        return createDexMetadataFile(apkFileName, /*validManifest=*/true);
+    }
+
+    private File createDexMetadataFile(String apkFileName, boolean validManifest) throws IOException
+            {
+        return createDexMetadataFile(apkFileName,DEX_METADATA_PACKAGE_NAME,
+                DEX_METADATA_VERSION_CODE, /*emptyManifest=*/false, validManifest);
+    }
+
+    private File createDexMetadataFile(String apkFileName, String packageName, Long versionCode,
+            boolean emptyManifest, boolean validManifest) throws IOException {
         File dmFile = new File(mTmpDir, apkFileName.replace(APK_FILE_EXTENSION,
                 DEX_METADATA_FILE_EXTENSION));
         try (FileOutputStream fos = new FileOutputStream(dmFile)) {
             try (ZipOutputStream zipOs = new ZipOutputStream(fos)) {
                 zipOs.putNextEntry(new ZipEntry("primary.prof"));
                 zipOs.closeEntry();
+
+                if (validManifest) {
+                    zipOs.putNextEntry(new ZipEntry("manifest.json"));
+                    if (!emptyManifest) {
+                      String manifestStr = "{";
+
+                      if (packageName != null) {
+                          manifestStr += "\"packageName\": " + "\"" + packageName + "\"";
+
+                          if (versionCode != null) {
+                            manifestStr += ", ";
+                          }
+                      }
+                      if (versionCode != null) {
+                        manifestStr += " \"versionCode\": " + versionCode;
+                      }
+
+                      manifestStr += "}";
+                      byte[] bytes = manifestStr.getBytes(StandardCharsets.UTF_8);
+                      zipOs.write(bytes, /*off=*/0, /*len=*/bytes.length);
+                    }
+                    zipOs.closeEntry();
+                }
             }
         }
         return dmFile;
@@ -98,17 +138,38 @@
         return outFile;
     }
 
+    private static void validatePackageDexMetadata(AndroidPackage pkg, boolean requireManifest)
+            throws PackageParserException {
+        Collection<String> apkToDexMetadataList =
+                AndroidPackageUtils.getPackageDexMetadata(pkg).values();
+        String packageName = pkg.getPackageName();
+        long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
+        for (String dexMetadata : apkToDexMetadataList) {
+            DexMetadataHelper.validateDexMetadataFile(
+                    dexMetadata, packageName, versionCode, requireManifest);
+        }
+    }
+
+    private static void validatePackageDexMetatadataVaryingRequireManifest(ParsedPackage pkg)
+            throws PackageParserException {
+        validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+        validatePackageDexMetadata(pkg, /*requireManifest=*/false);
+    }
+
     @Test
     public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         createDexMetadataFile("install_split_base.apk");
-        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
 
         Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
         String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
         assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
+
+        // Should throw no exceptions.
+        validatePackageDexMetatadataVaryingRequireManifest(pkg);
     }
 
     @Test
@@ -118,7 +179,7 @@
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_base.apk");
         createDexMetadataFile("install_split_feature_a.apk");
-        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
 
         Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(2, packageDexMetadata.size());
@@ -129,6 +190,9 @@
         String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
         assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
+
+        // Should throw no exceptions.
+        validatePackageDexMetatadataVaryingRequireManifest(pkg);
     }
 
     @Test
@@ -137,7 +201,7 @@
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_feature_a.apk");
-        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
+        ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
 
         Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
@@ -145,6 +209,9 @@
         String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
         assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
+
+        // Should throw no exceptions.
+        validatePackageDexMetatadataVaryingRequireManifest(pkg);
     }
 
     @Test
@@ -153,9 +220,17 @@
         File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
         Files.createFile(invalidDmFile.toPath());
         try {
-            ParsedPackage pkg = new TestPackageParser2()
-                    .parsePackage(mTmpDir, 0 /* flags */, false);
-            AndroidPackageUtils.validatePackageDexMetadata(pkg);
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: empty .dm file");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/false);
+            fail("Should fail validation: empty .dm file");
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
         }
@@ -171,9 +246,112 @@
         Files.createFile(invalidDmFile.toPath());
 
         try {
-            ParsedPackage pkg = new TestPackageParser2()
-                    .parsePackage(mTmpDir, 0 /* flags */, false);
-            AndroidPackageUtils.validatePackageDexMetadata(pkg);
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: empty .dm file");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/false);
+            fail("Should fail validation: empty .dm file");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileInvalidManifest()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", /*validManifest=*/false);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: missing manifest.json in the .dm archive");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileEmptyManifest()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", /*packageName=*/"doesn't matter",
+                /*versionCode=*/-12345L, /*emptyManifest=*/true, /*validManifest=*/true);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: empty manifest.json in the .dm archive");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileBadPackageName()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", /*packageName=*/"bad package name",
+                DEX_METADATA_VERSION_CODE, /*emptyManifest=*/false, /*validManifest=*/true);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: bad package name in the .dm archive");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileBadVersionCode()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", DEX_METADATA_PACKAGE_NAME,
+                /*versionCode=*/12345L, /*emptyManifest=*/false, /*validManifest=*/true);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: bad version code in the .dm archive");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileMissingPackageName()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", /*packageName=*/null,
+                DEX_METADATA_VERSION_CODE, /*emptyManifest=*/false, /*validManifest=*/true);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: missing package name in the .dm archive");
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageWithDmFileMissingVersionCode()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk", DEX_METADATA_PACKAGE_NAME,
+                /*versionCode=*/null, /*emptyManifest=*/false, /*validManifest=*/true);
+
+        try {
+            ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
+            validatePackageDexMetadata(pkg, /*requireManifest=*/true);
+            fail("Should fail validation: missing version code in the .dm archive");
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
         }
@@ -186,7 +364,7 @@
 
         try {
             DexMetadataHelper.validateDexPaths(mTmpDir.list());
-            fail("Should fail validation");
+            fail("Should fail validation: split .dm filename unmatched against .apk");
         } catch (IllegalStateException e) {
             // expected.
         }
@@ -202,7 +380,7 @@
 
         try {
             DexMetadataHelper.validateDexPaths(mTmpDir.list());
-            fail("Should fail validation");
+            fail("Should fail validation: .dm filename has no match against .apk");
         } catch (IllegalStateException e) {
             // expected.
         }
@@ -214,7 +392,7 @@
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         File dm = createDexMetadataFile("install_split_base.apk");
         ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
-                ParseTypeImpl.forDefaultParsing().reset(), mTmpDir, 0 /* flags */);
+                ParseTypeImpl.forDefaultParsing().reset(), mTmpDir, /*flags=*/0);
         if (result.isError()) {
             throw new IllegalStateException(result.getErrorMessage(), result.getException());
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index 22020ad..bc84e35 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -96,7 +96,7 @@
 
         int[] reasons = new int[] {
                 PackageManagerService.REASON_FIRST_BOOT,
-                PackageManagerService.REASON_BOOT,
+                PackageManagerService.REASON_POST_BOOT,
                 PackageManagerService.REASON_INSTALL,
                 PackageManagerService.REASON_BACKGROUND_DEXOPT,
                 PackageManagerService.REASON_AB_OTA,
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS
new file mode 100644
index 0000000..66ef75d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/dex/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index adf4551..3450710 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -451,7 +451,7 @@
                 "PCL[new_context.dex]");
         assertTrue(record(fooSecondary1User0NewContext));
 
-        // Not check that the context was switch to variable.
+        // Now check that the context was switch to variable.
         TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext(
                 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
 
@@ -461,6 +461,22 @@
     }
 
     @Test
+    public void testRecordClassLoaderContextOverwritten() {
+        // Record a secondary dex file.
+        assertTrue(record(mFooSecondary1User0));
+        // Now update its context.
+        TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext(
+                "PCL[new_context.dex]", true);
+        assertTrue(record(fooSecondary1User0NewContext));
+
+        // Now check that the context was overwritten.
+        TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext(
+                "PCL[new_context.dex]", true);
+
+        assertPackageDexUsage(null, expectedContext);
+    }
+
+    @Test
     public void testDexUsageClassLoaderContext() {
         final boolean isUsedByOtherApps = false;
         final int userId = 0;
@@ -642,8 +658,9 @@
 
     private boolean record(TestData testData) {
         return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile,
-               testData.mOwnerUserId, testData.mLoaderIsa,
-               testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext);
+                testData.mOwnerUserId, testData.mLoaderIsa,
+                testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext,
+                testData.mOverwriteCLC);
     }
 
     private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) {
@@ -651,7 +668,8 @@
         for (String user : users) {
             result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile,
                     testData.mOwnerUserId, testData.mLoaderIsa,
-                    testData.mPrimaryOrSplit, user, testData.mClassLoaderContext);
+                    testData.mPrimaryOrSplit, user, testData.mClassLoaderContext,
+                    testData.mOverwriteCLC);
         }
         return result;
     }
@@ -682,15 +700,16 @@
         private final boolean mPrimaryOrSplit;
         private final String mUsedBy;
         private final String mClassLoaderContext;
+        private final boolean mOverwriteCLC;
 
         private TestData(String packageName, String dexFile, int ownerUserId,
                 String loaderIsa, boolean primaryOrSplit, String usedBy) {
             this(packageName, dexFile, ownerUserId, loaderIsa, primaryOrSplit,
-                    usedBy, "PCL[" + dexFile + "]");
+                    usedBy, "PCL[" + dexFile + "]", false);
         }
         private TestData(String packageName, String dexFile, int ownerUserId,
                 String loaderIsa, boolean primaryOrSplit, String usedBy,
-                String classLoaderContext) {
+                String classLoaderContext, boolean overwriteCLC) {
             mPackageName = packageName;
             mDexFile = dexFile;
             mOwnerUserId = ownerUserId;
@@ -698,16 +717,21 @@
             mPrimaryOrSplit = primaryOrSplit;
             mUsedBy = usedBy;
             mClassLoaderContext = classLoaderContext;
+            mOverwriteCLC = overwriteCLC;
         }
 
         private TestData updateClassLoaderContext(String newContext) {
+            return updateClassLoaderContext(newContext, mOverwriteCLC);
+        }
+
+        private TestData updateClassLoaderContext(String newContext, boolean overwriteCLC) {
             return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa,
-                    mPrimaryOrSplit, mUsedBy, newContext);
+                    mPrimaryOrSplit, mUsedBy, newContext, overwriteCLC);
         }
 
         private TestData updateUsedBy(String newUsedBy) {
             return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa,
-                mPrimaryOrSplit, newUsedBy, mClassLoaderContext);
+                mPrimaryOrSplit, newUsedBy, mClassLoaderContext, mOverwriteCLC);
         }
 
         private boolean isUsedByOtherApps() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
new file mode 100644
index 0000000..70d85b6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 com.android.server.pm.parsing.library;
+
+import android.os.Build;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidNetIpSecIkeUpdater}
+ */
+@Presubmit
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidNetIpSecIkeUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    @Test
+    public void otherUsesLibraries() {
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary("other")
+                .addUsesOptionalLibrary("optional")
+                .addUsesLibrary("android.net.ipsec.ike")
+                .hideAsParsed());
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary("other")
+                .addUsesOptionalLibrary("optional")
+                .hideAsParsed())
+                .hideAsFinal();
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary("android.net.ipsec.ike")
+                .hideAsParsed());
+
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed())
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary("android.net.ipsec.ike")
+                .hideAsParsed());
+
+        AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed())
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidNetIpSecIkeUpdater::new);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index 09c8142..9768f17 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -165,6 +165,23 @@
         checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
     }
 
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses a
+     * {@link AndroidNetIpSecIkeUpdater}.
+     */
+    @Test
+    public void android_net_ipsec_ike_in_usesLibraries() {
+        ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary("android.net.ipsec.ike")
+                .hideAsParsed());
+
+        ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
+
+        checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
+    }
+
     private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
         checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
     }
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.bp b/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
index 13e6644..0731e2c 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/ConnTestApp/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: "ConnTestApp",
 
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/OWNERS b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.bp b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
index b29e187..6458bcd 100644
--- a/services/tests/servicestests/test-apps/JobTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/JobTestApp/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: "JobTestApp",
 
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
index c409438..0fd3de8 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
+++ b/services/tests/servicestests/test-apps/PackageParserApp/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: "PackageParserTestApp1",
     sdk_version: "current",
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp b/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp
index 5cbd39c..50b89d4 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/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: "SimpleServiceTestApp",
 
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp b/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp
index 7257275..5e77498 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/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: "SuspendTestApp",
 
diff --git a/services/tests/shortcutmanagerutils/Android.bp b/services/tests/shortcutmanagerutils/Android.bp
index c2cb6881..b33230e 100644
--- a/services/tests/shortcutmanagerutils/Android.bp
+++ b/services/tests/shortcutmanagerutils/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"],
+}
+
 java_library {
     name: "ShortcutManagerTestUtils",
 
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 4439f99..541fc63 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -2,6 +2,15 @@
 // Build FrameworksUiServicesTests package
 //########################################################################
 
+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: "FrameworksUiServicesTests",
 
@@ -57,6 +66,6 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V5-cpp",
     ],
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index a118e0d..bbb25cd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -28,8 +28,8 @@
 import static android.app.NotificationManager.IMPORTANCE_MAX;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
 import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 3c7206f..69e4190 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -33,8 +33,8 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.os.AtomsProto.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER;
 import static com.android.os.AtomsProto.DNDModeProto.ENABLED_FIELD_NUMBER;
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index e2821f4..6d0953a 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -2,6 +2,15 @@
 // Build WmTests package
 //########################################################################
 
+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: "WmTests",
 
diff --git a/services/usage/Android.bp b/services/usage/Android.bp
index 463673f..350da87 100644
--- a/services/usage/Android.bp
+++ b/services/usage/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"],
+}
+
 filegroup {
     name: "services.usage-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 4e98409..efca1a1 100644
--- a/services/usb/Android.bp
+++ b/services/usb/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"],
+}
+
 filegroup {
     name: "services.usb-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 8ee72b5..60172a3 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,6 +1,5 @@
 badhri@google.com
 elaurent@google.com
-moltmann@google.com
 albertccwang@google.com
 jameswei@google.com
 howardyen@google.com
\ No newline at end of file
diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp
index 47129ad..cfccc17 100644
--- a/services/voiceinteraction/Android.bp
+++ b/services/voiceinteraction/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"],
+}
+
 filegroup {
     name: "services.voiceinteraction-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
index 3975fd2..62d5372 100644
--- a/services/wifi/Android.bp
+++ b/services/wifi/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"],
+}
+
 filegroup {
     name: "services.wifi-sources",
     srcs: ["java/**/*.java"],
diff --git a/startop/apps/test/Android.bp b/startop/apps/test/Android.bp
index f42c755..98b9b64e 100644
--- a/startop/apps/test/Android.bp
+++ b/startop/apps/test/Android.bp
@@ -14,6 +14,15 @@
 // 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_app {
     name: "startop_test_app",
     srcs: [
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index 993d1e1..4fdf34c 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/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"],
+}
+
 filegroup {
   name: "services.startop.iorap-javasources",
   srcs: ["src/**/*.java"],
diff --git a/startop/iorap/functional_tests/Android.bp b/startop/iorap/functional_tests/Android.bp
index 8a5bd34..43c6155 100644
--- a/startop/iorap/functional_tests/Android.bp
+++ b/startop/iorap/functional_tests/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: "iorap-functional-tests",
     srcs: ["src/**/*.java"],
@@ -39,4 +48,3 @@
     certificate: "platform",
     platform_apis: true,
 }
-
diff --git a/startop/iorap/stress/Android.bp b/startop/iorap/stress/Android.bp
index f9f251bd..6e8725d 100644
--- a/startop/iorap/stress/Android.bp
+++ b/startop/iorap/stress/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_binary {
   name: "iorap.stress.memory",
   srcs: ["main_memory.cc"],
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 3e60ad4..ad3d001 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // TODO: once b/80095087 is fixed, rewrite this back to android_test
+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: "libiorap-java-test-lib",
     srcs: ["src/**/*.kt"],
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 7cc233b..9023921 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 cc_defaults {
     name: "viewcompiler_defaults",
     header_libs: [
@@ -84,7 +93,6 @@
     static_libs: [
         "libviewcompiler",
     ],
-    test_suites: ["general-tests"],
 }
 
 cc_binary_host {
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
index 5f7d3f9..791e471 100644
--- a/startop/view_compiler/TEST_MAPPING
+++ b/startop/view_compiler/TEST_MAPPING
@@ -10,10 +10,6 @@
           "include-filter": "android.view.cts.PrecompiledLayoutTest"
         }
       ]
-    },
-    {
-      "name": "view-compiler-tests",
-      "host": true
     }
   ]
 }
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
index f783aa6..2048964 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 genrule {
     name: "generate_compiled_layout1",
     tools: [":viewcompiler"],
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index b73ef9b..be5fae4 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.net.Uri;
@@ -67,7 +68,8 @@
          * Sets the participants for the resulting {@link ConnectionRequest}
          * @param participants The participants to which the {@link Connection} is to connect.
          */
-        public @NonNull Builder setParticipants(@Nullable List<Uri> participants) {
+        public @NonNull Builder setParticipants(
+                @SuppressLint("NullableCollection") @Nullable List<Uri> participants) {
             this.mParticipants = participants;
             return this;
         }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a4ecb72..580513c 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1992,7 +1992,7 @@
         boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
                 TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
         boolean addSelfManaged = request.getExtras() != null && request.getExtras().getBoolean(
-                PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false);
+                PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
         Log.i(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, "
                         + "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b, "
                         + " addSelfManaged: %b", callManagerAccount, callId, request, isIncoming,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a42e364..9861973b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3937,6 +3937,20 @@
         public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL =
                 KEY_PREFIX + "enable_presence_group_subscribe_bool";
 
+        /**
+         * An integer key associated with the period of time in seconds the non-rcs capability
+         * information of each contact is cached on the device.
+         * <p>
+         * The rcs capability cache expiration sec is managed by
+         * {@code android.telephony.ims.ProvisioningManager} but non-rcs capability is managed by
+         * {@link CarrierConfigManager} since non-rcs capability will be provided via ACS or carrier
+         * config.
+         * <p>
+         * The default value is 2592000 secs (30 days), see RCC.07 Annex A.1.9.
+         */
+        public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT =
+                KEY_PREFIX + "non_rcs_capabilities_cache_expiration_sec_int";
+
         private Ims() {}
 
         private static PersistableBundle getDefaults() {
@@ -3947,6 +3961,7 @@
             defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
+            defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60);
             return defaults;
         }
     }
@@ -3984,8 +3999,9 @@
             "mmi_two_digit_number_pattern_string_array";
 
     /**
-     * Holds the list of carrier certificate hashes.
-     * Note that each carrier has its own certificates.
+     * Holds the list of carrier certificate hashes, followed by optional package names.
+     * Format: "sha1/256" or "sha1/256:package1,package2,package3..."
+     * Note that each carrier has its own hashes.
      */
     public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY =
             "carrier_certificate_string_array";
@@ -4131,6 +4147,16 @@
     public static final String KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL =
             "network_temp_not_metered_supported_bool";
 
+    /**
+     * Indicates the allowed APN types that can be used for LTE initial attach. The order of APN
+     * types in the configuration is the order of APN types that will be used for initial attach.
+     * Empty list indicates that no APN types are allowed for initial attach.
+     *
+     * @hide
+     */
+    public static final String KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY =
+            "allowed_initial_attach_apn_types_string_array";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -4682,6 +4708,8 @@
         sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
         sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, false);
         sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
+        sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY,
+                new String[]{"ia", "default", "ims", "mms", "dun", "emergency"});
     }
 
     /**
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 8507d85..706e3cb 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -344,6 +344,7 @@
             // TODO: Instead of doing this, we should create a formal way for cloning cell identity.
             // Cell identity is not an immutable object so we have to deep copy it.
             mCellIdentity = CellIdentity.CREATOR.createFromParcel(p);
+            p.recycle();
         }
 
         if (nri.mVoiceSpecificInfo != null) {
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index 0059ad6..ae7d209 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -402,29 +402,27 @@
          * @see #getThresholds() for more details on signal strength thresholds
          */
         public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
-            Objects.requireNonNull(thresholds, "thresholds must not be null");
-            if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
-                    || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
-                throw new IllegalArgumentException(
-                        "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
-                                + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
-            }
-            mThresholds = thresholds.clone();
-            Arrays.sort(mThresholds);
-            return this;
+            return setThresholds(thresholds, false /*isSystem*/);
         }
 
         /**
-         * Set the signal strength thresholds for the corresponding signal measurement type without
-         * the length limitation.
+         * Set the signal strength thresholds for the corresponding signal measurement type.
          *
          * @param thresholds array of integer as the signal threshold values
+         * @param isSystem true is the caller is system which does not have restrictions on
+         *        the length of thresholds array.
          * @return the builder to facilitate the chaining
          *
          * @hide
          */
-        public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+        public @NonNull Builder setThresholds(@NonNull int[] thresholds, boolean isSystem) {
             Objects.requireNonNull(thresholds, "thresholds must not be null");
+            if (!isSystem && (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                    || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED)) {
+                throw new IllegalArgumentException(
+                        "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                                + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+            }
             mThresholds = thresholds.clone();
             Arrays.sort(mThresholds);
             return this;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 904232b..4e481b3 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2589,14 +2589,45 @@
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
-     *             outlined above.
+     *            outlined above.
      */
     public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
             @DurationMillisLong long timeoutMillis) {
+        setSubscriptionOverrideUnmetered(subId, overrideUnmetered,
+                TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+    }
 
+    /**
+     * Temporarily override the billing relationship plan between a carrier and
+     * a specific subscriber to be considered unmetered. This will be reflected
+     * to apps via {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}.
+     * <p>
+     * This method is only accessible to the following narrow set of apps:
+     * <ul>
+     * <li>The carrier app for this subscriberId, as determined by
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
+     * <li>The carrier app explicitly delegated access through
+     * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+     * </ul>
+     *
+     * @param subId the subscriber this override applies to.
+     * @param overrideUnmetered set if the billing relationship should be
+     *            considered unmetered.
+     * @param networkTypes the network types this override applies to.
+     *            {@see TelephonyManager#getAllNetworkTypes()}
+     * @param timeoutMillis the timeout after which the requested override will
+     *            be automatically cleared, or {@code 0} to leave in the
+     *            requested state until explicitly cleared, or the next reboot,
+     *            whichever happens first.
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *            outlined above.
+     */
+    public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
+            @NonNull @Annotation.NetworkType int[] networkTypes,
+            @DurationMillisLong long timeoutMillis) {
         final int overrideValue = overrideUnmetered ? SUBSCRIPTION_OVERRIDE_UNMETERED : 0;
         getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_UNMETERED,
-                overrideValue, timeoutMillis, mContext.getOpPackageName());
+                overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
     }
 
     /**
@@ -2621,13 +2652,46 @@
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
-     *             outlined above.
+     *            outlined above.
      */
     public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
             @DurationMillisLong long timeoutMillis) {
+        setSubscriptionOverrideCongested(subId, overrideCongested,
+                TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+    }
+
+    /**
+     * Temporarily override the billing relationship plan between a carrier and
+     * a specific subscriber to be considered congested. This will cause the
+     * device to delay certain network requests when possible, such as developer
+     * jobs that are willing to run in a flexible time window.
+     * <p>
+     * This method is only accessible to the following narrow set of apps:
+     * <ul>
+     * <li>The carrier app for this subscriberId, as determined by
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
+     * <li>The carrier app explicitly delegated access through
+     * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+     * </ul>
+     *
+     * @param subId the subscriber this override applies to.
+     * @param overrideCongested set if the subscription should be considered
+     *            congested.
+     * @param networkTypes the network types this override applies to.
+     *            {@see TelephonyManager#getAllNetworkTypes()}
+     * @param timeoutMillis the timeout after which the requested override will
+     *            be automatically cleared, or {@code 0} to leave in the
+     *            requested state until explicitly cleared, or the next reboot,
+     *            whichever happens first.
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *            outlined above.
+     */
+    public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
+            @NonNull @Annotation.NetworkType int[] networkTypes,
+            @DurationMillisLong long timeoutMillis) {
         final int overrideValue = overrideCongested ? SUBSCRIPTION_OVERRIDE_CONGESTED : 0;
         getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_CONGESTED,
-                overrideValue, timeoutMillis, mContext.getOpPackageName());
+                overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
     }
 
     /**
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 12bb366..2765349 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -35,6 +35,7 @@
 import java.io.IOException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -52,6 +53,16 @@
 
     private static final int ENCODING_VERSION = 1;
 
+    /**
+     * Delimiter used to decode {@link CarrierConfigManager#KEY_CARRIER_CERTIFICATE_STRING_ARRAY}.
+     */
+    private static final String DELIMITER_CERTIFICATE_HASH_PACKAGE_NAMES = ":";
+
+    /**
+     * Delimiter used to decode {@link CarrierConfigManager#KEY_CARRIER_CERTIFICATE_STRING_ARRAY}.
+     */
+    private static final String DELIMITER_INDIVIDUAL_PACKAGE_NAMES = ",";
+
     public static final @android.annotation.NonNull Creator<UiccAccessRule> CREATOR = new Creator<UiccAccessRule>() {
         @Override
         public UiccAccessRule createFromParcel(Parcel in) {
@@ -98,6 +109,36 @@
     }
 
     /**
+     * Decodes {@link CarrierConfigManager#KEY_CARRIER_CERTIFICATE_STRING_ARRAY} values.
+     * @hide
+     */
+    @Nullable
+    public static UiccAccessRule[] decodeRulesFromCarrierConfig(@Nullable String[] certs) {
+        if (certs == null) {
+            return null;
+        }
+        List<UiccAccessRule> carrierConfigAccessRulesArray = new ArrayList();
+        for (String cert : certs) {
+            String[] splitStr = cert.split(DELIMITER_CERTIFICATE_HASH_PACKAGE_NAMES);
+            byte[] certificateHash = IccUtils.hexStringToBytes(splitStr[0]);
+            if (splitStr.length == 1) {
+                // The value is a certificate hash, without any package name
+                carrierConfigAccessRulesArray.add(new UiccAccessRule(certificateHash, null, 0));
+            } else {
+                // The value is composed of the certificate hash followed by at least one
+                // package name
+                String[] packageNames = splitStr[1].split(DELIMITER_INDIVIDUAL_PACKAGE_NAMES);
+                for (String packageName : packageNames) {
+                    carrierConfigAccessRulesArray.add(
+                            new UiccAccessRule(certificateHash, packageName, 0));
+                }
+            }
+        }
+        return carrierConfigAccessRulesArray.toArray(
+            new UiccAccessRule[carrierConfigAccessRulesArray.size()]);
+    }
+
+    /**
      * Decodes a byte array generated with {@link #encodeRules}.
      * @hide
      */
@@ -214,6 +255,14 @@
         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
     }
 
+    /**
+     * Returns true if the given certificate and package name match this rule's values.
+     * @hide
+     */
+    public boolean matches(@Nullable String certHash, @Nullable String packageName) {
+        return matches(IccUtils.hexStringToBytes(certHash), packageName);
+    }
+
     private boolean matches(byte[] certHash, String packageName) {
         return certHash != null && Arrays.equals(this.mCertificateHash, certHash) &&
                 (TextUtils.isEmpty(this.mPackageName) || this.mPackageName.equals(packageName));
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 46ec4a3..46940dc 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.LinkAddress;
+import android.net.LinkProperties;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.DataFailureCause;
@@ -274,9 +275,11 @@
     }
 
     /**
-     * @return The network suggested data retry duration in milliseconds. {@code Long.MAX_VALUE}
-     * indicates data retry should not occur. {@link #RETRY_DURATION_UNDEFINED} indicates network
-     * did not suggest any retry duration.
+     * @return The network suggested data retry duration in milliseconds as specified in
+     * 3GPP TS 24.302 section 8.2.9.1.  The APN associated to this data call will be throttled for
+     * the specified duration unless {@link DataServiceCallback#onApnUnthrottled} is called.
+     * {@code Long.MAX_VALUE} indicates data retry should not occur.
+     * {@link #RETRY_DURATION_UNDEFINED} indicates network did not suggest any retry duration.
      */
     public long getRetryDurationMillis() {
         return mSuggestedRetryTime;
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 52bf15f..f56c19b 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -250,7 +250,11 @@
     }
 
     /**
-     * Indicates that the specified APN is no longer throttled.
+     * The APN is throttled for the duration specified in
+     * {@link DataCallResponse#getRetryDurationMillis}.  Calling this method unthrottles that
+     * APN.
+     * <p/>
+     * see: {@link DataCallResponse#getRetryDurationMillis}
      *
      * @param apn Access Point Name defined by the carrier.
      */
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
index 2904082..ba2b62d 100644
--- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
@@ -17,7 +17,7 @@
 package android.telephony.data;
 
 import android.telephony.data.IQualifiedNetworksServiceCallback;
-import android.telephony.data.ApnThrottleStatus;
+import android.telephony.data.ThrottleStatus;
 
 /**
  * {@hide}
@@ -26,5 +26,5 @@
 {
     oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback);
     oneway void removeNetworkAvailabilityProvider(int slotId);
-    oneway void reportApnThrottleStatusChanged(int slotId, in List<ApnThrottleStatus> statuses);
+    oneway void reportThrottleStatusChanged(int slotId, in List<ThrottleStatus> statuses);
 }
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 4af63b4..4e85d89 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -168,8 +168,8 @@
          *
          * @param statuses the statuses that have changed
          */
-        public void reportApnThrottleStatusChanged(@NonNull List<ApnThrottleStatus> statuses) {
-            Log.d(TAG, "reportApnThrottleStatusChanged: statuses size=" + statuses.size());
+        public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
+            Log.d(TAG, "reportThrottleStatusChanged: statuses size=" + statuses.size());
         }
 
         /**
@@ -212,8 +212,8 @@
                     break;
                 case QNS_APN_THROTTLE_STATUS_CHANGED:
                     if (provider != null) {
-                        List<ApnThrottleStatus> statuses = (List<ApnThrottleStatus>) message.obj;
-                        provider.reportApnThrottleStatusChanged(statuses);
+                        List<ThrottleStatus> statuses = (List<ThrottleStatus>) message.obj;
+                        provider.reportThrottleStatusChanged(statuses);
                     }
                     break;
 
@@ -307,8 +307,8 @@
         }
 
         @Override
-        public void reportApnThrottleStatusChanged(int slotIndex,
-                List<ApnThrottleStatus> statuses) {
+        public void reportThrottleStatusChanged(int slotIndex,
+                List<ThrottleStatus> statuses) {
             mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
                     .sendToTarget();
         }
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/telephony/java/android/telephony/data/ThrottleStatus.aidl
similarity index 95%
rename from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
rename to telephony/java/android/telephony/data/ThrottleStatus.aidl
index 46bc4ab..f75f3570 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/telephony/java/android/telephony/data/ThrottleStatus.aidl
@@ -17,4 +17,4 @@
 /** @hide */
 package android.telephony.data;
 
-parcelable ApnThrottleStatus;
+parcelable ThrottleStatus;
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.java b/telephony/java/android/telephony/data/ThrottleStatus.java
similarity index 86%
rename from telephony/java/android/telephony/data/ApnThrottleStatus.java
rename to telephony/java/android/telephony/data/ThrottleStatus.java
index 51461d1..0335c68 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.java
+++ b/telephony/java/android/telephony/data/ThrottleStatus.java
@@ -35,7 +35,7 @@
  * @hide
  */
 @SystemApi
-public final class ApnThrottleStatus implements Parcelable {
+public final class ThrottleStatus implements Parcelable {
     /**
      * The APN type is not throttled.
      */
@@ -43,14 +43,14 @@
 
     /**
      * The APN type is throttled until {@link android.os.SystemClock#elapsedRealtime()}
-     * has reached {@link ApnThrottleStatus#getThrottleExpiryTimeMillis}
+     * has reached {@link ThrottleStatus#getThrottleExpiryTimeMillis}
      */
     public static final int THROTTLE_TYPE_ELAPSED_TIME = 2;
 
     /** {@hide} */
     @IntDef(flag = true, prefix = {"THROTTLE_TYPE_"}, value = {
-            ApnThrottleStatus.THROTTLE_TYPE_NONE,
-            ApnThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
+            ThrottleStatus.THROTTLE_TYPE_NONE,
+            ThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
     })
     public @interface ThrottleType {
     }
@@ -72,9 +72,9 @@
 
     /** {@hide} */
     @IntDef(flag = true, prefix = {"RETRY_TYPE_"}, value = {
-            ApnThrottleStatus.RETRY_TYPE_NONE,
-            ApnThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
-            ApnThrottleStatus.RETRY_TYPE_HANDOVER,
+            ThrottleStatus.RETRY_TYPE_NONE,
+            ThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
+            ThrottleStatus.RETRY_TYPE_HANDOVER,
     })
     public @interface RetryType {
     }
@@ -141,7 +141,7 @@
      * {@link SystemClock#elapsedRealtime}.
      *
      * This value only applies when the throttle type is set to
-     * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+     * {@link ThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
      *
      * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
      *
@@ -152,7 +152,7 @@
         return mThrottleExpiryTimeMillis;
     }
 
-    private ApnThrottleStatus(int slotIndex,
+    private ThrottleStatus(int slotIndex,
             @AccessNetworkConstants.TransportType int transportType,
             @Annotation.ApnType int apnTypes,
             @ThrottleType int throttleType,
@@ -166,7 +166,7 @@
         mRetryType = retryType;
     }
 
-    private ApnThrottleStatus(@NonNull Parcel source) {
+    private ThrottleStatus(@NonNull Parcel source) {
         mSlotIndex = source.readInt();
         mTransportType = source.readInt();
         mApnType = source.readInt();
@@ -185,16 +185,16 @@
         dest.writeInt(mThrottleType);
     }
 
-    public static final @NonNull Parcelable.Creator<ApnThrottleStatus> CREATOR =
-            new Parcelable.Creator<ApnThrottleStatus>() {
+    public static final @NonNull Parcelable.Creator<ThrottleStatus> CREATOR =
+            new Parcelable.Creator<ThrottleStatus>() {
                 @Override
-                public ApnThrottleStatus createFromParcel(@NonNull Parcel source) {
-                    return new ApnThrottleStatus(source);
+                public ThrottleStatus createFromParcel(@NonNull Parcel source) {
+                    return new ThrottleStatus(source);
                 }
 
                 @Override
-                public ApnThrottleStatus[] newArray(int size) {
-                    return new ApnThrottleStatus[size];
+                public ThrottleStatus[] newArray(int size) {
+                    return new ThrottleStatus[size];
                 }
             };
 
@@ -213,8 +213,8 @@
     public boolean equals(Object obj) {
         if (obj == null) {
             return false;
-        } else if (obj instanceof ApnThrottleStatus) {
-            ApnThrottleStatus other = (ApnThrottleStatus) obj;
+        } else if (obj instanceof ThrottleStatus) {
+            ThrottleStatus other = (ThrottleStatus) obj;
             return this.mSlotIndex == other.mSlotIndex
                     && this.mApnType == other.mApnType
                     && this.mRetryType == other.mRetryType
@@ -228,7 +228,7 @@
 
     @Override
     public String toString() {
-        return "ApnThrottleStatus{"
+        return "ThrottleStatus{"
                 + "mSlotIndex=" + mSlotIndex
                 + ", mTransportType=" + mTransportType
                 + ", mApnType=" + ApnSetting.getApnTypeString(mApnType)
@@ -239,18 +239,18 @@
     }
 
     /**
-     * Provides a convenient way to set the fields of an {@link ApnThrottleStatus} when creating a
+     * Provides a convenient way to set the fields of an {@link ThrottleStatus} when creating a
      * new instance.
      *
-     * <p>The example below shows how you might create a new {@code ApnThrottleStatus}:
+     * <p>The example below shows how you might create a new {@code ThrottleStatus}:
      *
      * <pre><code>
      *
-     * DataCallResponseApnThrottleStatus = new ApnThrottleStatus.Builder()
+     * ThrottleStatus = new ThrottleStatus.Builder()
      *     .setSlotIndex(1)
      *     .setApnType({@link ApnSetting#TYPE_EMERGENCY})
      *     .setNoThrottle()
-     *     .setRetryType({@link ApnThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
+     *     .setRetryType({@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
      *     .build();
      * </code></pre>
      */
@@ -261,6 +261,10 @@
         private long mThrottleExpiryTimeMillis;
         private @RetryType int mRetryType;
         private @ThrottleType int mThrottleType;
+
+        /**
+         * @hide
+         */
         public static final long NO_THROTTLE_EXPIRY_TIME =
                 DataCallResponse.RETRY_DURATION_UNDEFINED;
 
@@ -312,7 +316,7 @@
          * {@link SystemClock#elapsedRealtime}.
          *
          * When setting this value, the throttle type is set to
-         * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+         * {@link ThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
          *
          * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
          *
@@ -338,7 +342,7 @@
          * Sets the status of the APN type as not being throttled.
          *
          * When setting this value, the throttle type is set to
-         * {@link ApnThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
+         * {@link ThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
          * {@link Builder#NO_THROTTLE_EXPIRY_TIME}.
          *
          * @return The same instance of the builder.
@@ -365,13 +369,13 @@
         }
 
         /**
-         * Build the {@link ApnThrottleStatus}
+         * Build the {@link ThrottleStatus}
          *
-         * @return the {@link ApnThrottleStatus} object
+         * @return the {@link ThrottleStatus} object
          */
         @NonNull
-        public ApnThrottleStatus build() {
-            return new ApnThrottleStatus(
+        public ThrottleStatus build() {
+            return new ThrottleStatus(
                     mSlotIndex,
                     mTransportType,
                     mApnType,
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
index fb65949..6bf992e 100644
--- a/telephony/java/android/telephony/ims/DelegateStateCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.telephony.ims.stub.SipDelegate;
 import android.telephony.ims.stub.SipTransportImplBase;
@@ -52,7 +53,9 @@
      *    implementing this feature elsewhere. If all features of this {@link SipDelegate} are
      *    denied, this method should still be called.
      */
-    void onCreated(@NonNull SipDelegate delegate, @Nullable Set<FeatureTagState> deniedTags);
+    void onCreated(@NonNull SipDelegate delegate,
+            @SuppressLint("NullableCollection")  // TODO(b/154763999): Mark deniedTags @Nonnull
+            @Nullable Set<FeatureTagState> deniedTags);
 
     /**
      * This must be called by the ImsService after the framework calls
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index bd623e0..5f4e1e6 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
@@ -39,6 +40,8 @@
 
 import com.android.internal.telephony.IIntegerConsumer;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -77,55 +80,13 @@
             "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
 
     /**
-     * Receives RCS Feature availability status updates from the ImsService.
-     *
-     * @see #isAvailable(int)
-     * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
-     * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+     * An application can use {@link #addOnAvailabilityChangedListener} to register a
+     * {@link OnAvailabilityChangedListener}, which will notify the user when the RCS feature
+     * availability status updates from the ImsService.
      * @hide
      */
-    public static class AvailabilityCallback {
-
-        private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
-
-            private final AvailabilityCallback mLocalCallback;
-            private Executor mExecutor;
-
-            CapabilityBinder(AvailabilityCallback c) {
-                mLocalCallback = c;
-            }
-
-            @Override
-            public void onCapabilitiesStatusChanged(int config) {
-                if (mLocalCallback == null) return;
-
-                long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(config));
-                } finally {
-                    restoreCallingIdentity(callingIdentity);
-                }
-            }
-
-            @Override
-            public void onQueryCapabilityConfiguration(int capability, int radioTech,
-                    boolean isEnabled) {
-                // This is not used for public interfaces.
-            }
-
-            @Override
-            public void onChangeCapabilityConfigurationError(int capability, int radioTech,
-                    @ImsFeature.ImsCapabilityError int reason) {
-                // This is not used for public interfaces
-            }
-
-            private void setExecutor(Executor executor) {
-                mExecutor = executor;
-            }
-        }
-
-        private final CapabilityBinder mBinder = new CapabilityBinder(this);
-
+    @SystemApi
+    public interface OnAvailabilityChangedListener {
         /**
          * The availability of the feature's capabilities has changed to either available or
          * unavailable.
@@ -136,22 +97,68 @@
          *
          * @param capabilities The new availability of the capabilities.
          */
-        public void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+        void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities);
+    }
+
+    /**
+     * Receive the availability status changed from the ImsService and pass the status change to
+     * the associated {@link OnAvailabilityChangedListener}
+     */
+    private static class AvailabilityCallbackAdapter {
+
+        private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+            private final OnAvailabilityChangedListener mOnAvailabilityChangedListener;
+            private final Executor mExecutor;
+
+            CapabilityBinder(OnAvailabilityChangedListener listener, Executor executor) {
+                mExecutor = executor;
+                mOnAvailabilityChangedListener = listener;
+            }
+
+            @Override
+            public void onCapabilitiesStatusChanged(int config) {
+                if (mOnAvailabilityChangedListener == null) return;
+
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() ->
+                            mOnAvailabilityChangedListener.onAvailabilityChanged(config));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
+            }
+
+            @Override
+            public void onQueryCapabilityConfiguration(int capability, int radioTech,
+                    boolean isEnabled) {
+                // This is not used.
+            }
+
+            @Override
+            public void onChangeCapabilityConfigurationError(int capability, int radioTech,
+                    @ImsFeature.ImsCapabilityError int reason) {
+                // This is not used.
+            }
+        }
+
+        private final CapabilityBinder mBinder;
+
+        AvailabilityCallbackAdapter(@NonNull Executor executor,
+                @NonNull OnAvailabilityChangedListener listener) {
+            mBinder = new CapabilityBinder(listener, executor);
         }
 
         /**@hide*/
         public final IImsCapabilityCallback getBinder() {
             return mBinder;
         }
-
-        private void setExecutor(Executor executor) {
-            mBinder.setExecutor(executor);
-        }
     }
 
     private final int mSubId;
     private final Context mContext;
     private final BinderCacheManager<IImsRcsController> mBinderCache;
+    private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
+            mAvailabilityChangedCallbacks;
 
     /**
      * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
@@ -162,6 +169,7 @@
         mSubId = subId;
         mContext = context;
         mBinderCache = binderCache;
+        mAvailabilityChangedCallbacks = new HashMap<>();
     }
 
     /**
@@ -174,10 +182,23 @@
     }
 
     /**
-     * @hide
+     * Registers a {@link RegistrationManager.RegistrationCallback} with the system. When the
+     * callback is registered, it will initiate the callback c to be called with the current
+     * registration state.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+     * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @param executor The executor the callback events should be run on.
+     * @param c The {@link RegistrationManager.RegistrationCallback} to be added.
+     * @see #unregisterImsRegistrationCallback(RegistrationManager.RegistrationCallback)
+     * @throws ImsException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+     * reason.
      */
-    // @Override add back to RegistrationManager interface once public.
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void registerImsRegistrationCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull RegistrationManager.RegistrationCallback c)
@@ -191,7 +212,7 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Register registration callback: IImsRcsController is null");
+            Log.w(TAG, "Register registration callback: IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -207,10 +228,21 @@
     }
 
     /**
-     * @hide
+     * Removes an existing {@link RegistrationManager.RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+     * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @param c The {@link RegistrationManager.RegistrationCallback} to be removed.
+     * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
+     * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
      */
-    // @Override add back to RegistrationManager interface once public.
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void unregisterImsRegistrationCallback(
             @NonNull RegistrationManager.RegistrationCallback c) {
         if (c == null) {
@@ -219,7 +251,7 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Unregister registration callback: IImsRcsController is null");
+            Log.w(TAG, "Unregister registration callback: IImsRcsController is null");
             throw new IllegalStateException("Cannot find remote IMS service");
         }
 
@@ -231,10 +263,21 @@
     }
 
     /**
-     * @hide
+     * Gets the registration state of the IMS service.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+     * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @param executor The {@link Executor} that will be used to call the IMS registration state
+     * callback.
+     * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+     * registration state of the IMS service, which will be one of the
+     * following: {@link RegistrationManager#REGISTRATION_STATE_NOT_REGISTERED},
+     * {@link RegistrationManager#REGISTRATION_STATE_REGISTERING}, or
+     * {@link RegistrationManager#REGISTRATION_STATE_REGISTERED}.
      */
-    // @Override add back to RegistrationManager interface once public.
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
             @NonNull @RegistrationManager.ImsRegistrationState Consumer<Integer> stateCallback) {
         if (stateCallback == null) {
@@ -246,7 +289,7 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Get registration state error: IImsRcsController is null");
+            Log.w(TAG, "Get registration state error: IImsRcsController is null");
             throw new IllegalStateException("Cannot find remote IMS service");
         }
 
@@ -263,9 +306,20 @@
     }
 
     /**
-     * @hide
+     * Gets the Transport Type associated with the current IMS registration.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+     * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+     * @param transportTypeCallback The transport type associated with the current IMS registration,
+     * which will be one of following:
+     * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+     * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+     * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
      */
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
             @NonNull @AccessNetworkConstants.TransportType
                     Consumer<Integer> transportTypeCallback) {
@@ -278,7 +332,7 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Get registration transport type error: IImsRcsController is null");
+            Log.w(TAG, "Get registration transport type error: IImsRcsController is null");
             throw new IllegalStateException("Cannot find remote IMS service");
         }
 
@@ -296,31 +350,33 @@
     }
 
     /**
-     * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
+     * Add an {@link OnAvailabilityChangedListener} with the system, which will provide RCS
      * availability updates for the subscription specified.
      *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a
-     * subscription is removed.
+     * {@link #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)} to clean up
+     * after a subscription is removed.
      * <p>
-     * When the callback is registered, it will initiate the callback c to be called with the
-     * current capabilities.
+     * When the listener is registered, it will initiate the callback listener to be called with
+     * the current capabilities.
      *
      * @param executor The executor the callback events should be run on.
-     * @param c The RCS {@link AvailabilityCallback} to be registered.
-     * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+     * @param listener The RCS {@link OnAvailabilityChangedListener} to be registered.
+     * @see #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)
      * @throws ImsException if the subscription associated with this instance of
      * {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not
      * available. This can happen if the ImsService has crashed, for example, or if the subscription
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void registerRcsAvailabilityCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull AvailabilityCallback c) throws ImsException {
-        if (c == null) {
-            throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+    public void addOnAvailabilityChangedListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnAvailabilityChangedListener listener) throws ImsException {
+        if (listener == null) {
+            throw new IllegalArgumentException("Must include a non-null"
+                    + "OnAvailabilityChangedListener.");
         }
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
@@ -328,56 +384,61 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Register availability callback: IImsRcsController is null");
+            Log.w(TAG, "Add availability changed listener: IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
 
-        c.setExecutor(executor);
+        AvailabilityCallbackAdapter adapter =
+                addAvailabilityChangedListenerToCollection(executor, listener);
         try {
-            imsRcsController.registerRcsAvailabilityCallback(mSubId, c.getBinder());
-
+            imsRcsController.registerRcsAvailabilityCallback(mSubId, adapter.getBinder());
         } catch (ServiceSpecificException e) {
             throw new ImsException(e.toString(), e.errorCode);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
+            Log.w(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
             throw new ImsException("Remote IMS Service is not available",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
-    /**
-     * Removes an existing RCS {@link AvailabilityCallback}.
+     /**
+     * Removes an existing RCS {@link OnAvailabilityChangedListener}.
      * <p>
      * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
      * etc...), this callback will automatically be unregistered. If this method is called for an
      * inactive subscription, it will result in a no-op.
-     * @param c The RCS {@link AvailabilityCallback} to be removed.
-     * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+     * @param listener The RCS {@link OnAvailabilityChangedListener} to be removed.
+     * @see #addOnAvailabilityChangedListener(Executor, OnAvailabilityChangedListener)
      * @throws ImsException if the IMS service is not available when calling this method.
      * See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c)
-            throws ImsException {
-        if (c == null) {
-            throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+    public void removeOnAvailabilityChangedListener(
+            @NonNull OnAvailabilityChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Must include a non-null"
+                    + "OnAvailabilityChangedListener.");
         }
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "Unregister availability callback: IImsRcsController is null");
-            throw new ImsException("Cannot find remote IMS service",
-                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+            Log.w(TAG, "Remove availability changed listener: IImsRcsController is null");
+            return;
+        }
+
+        AvailabilityCallbackAdapter callback =
+                removeAvailabilityChangedListenerFromCollection(listener);
+        if (callback == null) {
+            return;
         }
 
         try {
-            imsRcsController.unregisterRcsAvailabilityCallback(mSubId, c.getBinder());
+            imsRcsController.unregisterRcsAvailabilityCallback(mSubId, callback.getBinder());
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
-            throw new ImsException("Remote IMS Service is not available",
-                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+            Log.w(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
         }
     }
 
@@ -388,25 +449,24 @@
      * RCS capabilities provided over-the-top by applications.
      *
      * @param capability The RCS capability to query.
-     * @param radioTech The radio tech that this capability failed for, defined as
-     * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
-     * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}.
+     * @param radioTech The radio technology type that we are querying.
      * @return true if the RCS capability is capable for this subscription, false otherwise. This
      * does not necessarily mean that we are registered for IMS and the capability is available, but
      * rather the subscription is capable of this service over IMS.
-     * @see #isAvailable(int)
+     * @see #isAvailable(int, int)
      * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
      * @see android.telephony.CarrierConfigManager.Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL
      * @throws ImsException if the IMS service is not available when calling this method.
      * See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "isCapable: IImsRcsController is null");
+            Log.w(TAG, "isCapable: IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -414,7 +474,7 @@
         try {
             return imsRcsController.isCapable(mSubId, capability, radioTech);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#isCapable", e);
+            Log.w(TAG, "Error calling IImsRcsController#isCapable", e);
             throw new ImsException("Remote IMS Service is not available",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -427,6 +487,7 @@
      * RCS capabilities provided by over-the-top by applications.
      *
      * @param capability the RCS capability to query.
+     * @param radioTech The radio technology type that we are querying.
      * @return true if the RCS capability is currently available for the associated subscription,
      * false otherwise. If the capability is available, IMS is registered and the service is
      * currently available over IMS.
@@ -435,25 +496,57 @@
      * See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability)
+    public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)
             throws ImsException {
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "isAvailable: IImsRcsController is null");
+            Log.w(TAG, "isAvailable: IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
 
         try {
-            return imsRcsController.isAvailable(mSubId, capability);
+            return imsRcsController.isAvailable(mSubId, capability, radioTech);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#isAvailable", e);
+            Log.w(TAG, "Error calling IImsRcsController#isAvailable", e);
             throw new ImsException("Remote IMS Service is not available",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
+    /**
+     * Add the {@link OnAvailabilityChangedListener} to collection for tracking.
+     * @param executor The executor that will be used when the publish state is changed and the
+     * {@link OnAvailabilityChangedListener} is called.
+     * @param listener The {@link OnAvailabilityChangedListener} to call the publish state changed.
+     * @return The {@link AvailabilityCallbackAdapter} to wrapper the
+     * {@link OnAvailabilityChangedListener}
+     */
+    private AvailabilityCallbackAdapter addAvailabilityChangedListenerToCollection(
+            @NonNull Executor executor, @NonNull OnAvailabilityChangedListener listener) {
+        AvailabilityCallbackAdapter adapter = new AvailabilityCallbackAdapter(executor, listener);
+        synchronized (mAvailabilityChangedCallbacks) {
+            mAvailabilityChangedCallbacks.put(listener, adapter);
+        }
+        return adapter;
+    }
+
+    /**
+     * Remove the existing {@link OnAvailabilityChangedListener} from the collection.
+     * @param listener The {@link OnAvailabilityChangedListener} to remove from the collection.
+     * @return The wrapper class {@link AvailabilityCallbackAdapter} associated with the
+     * {@link OnAvailabilityChangedListener}.
+     */
+    private AvailabilityCallbackAdapter removeAvailabilityChangedListenerFromCollection(
+            @NonNull OnAvailabilityChangedListener listener) {
+        synchronized (mAvailabilityChangedCallbacks) {
+            return mAvailabilityChangedCallbacks.remove(listener);
+        }
+    }
+
     private IImsRcsController getIImsRcsController() {
         IBinder binder = TelephonyFrameworkInitializer
                 .getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/ApnThrottleStatus.aidl
copy to telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl
index 46bc4ab..0830ff2 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.telephony.ims;
 
-parcelable ApnThrottleStatus;
+parcelable ImsRegistrationAttributes;
diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
new file mode 100644
index 0000000..a36f549
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
@@ -0,0 +1,219 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains the attributes associated with the current IMS registration.
+ */
+public final class ImsRegistrationAttributes implements Parcelable {
+
+    /**
+     * Builder for creating {@link ImsRegistrationAttributes} instances.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private final int mRegistrationTech;
+        private Set<String> mFeatureTags = Collections.emptySet();
+
+        /**
+         * Build a new instance of {@link ImsRegistrationAttributes}.
+         *
+         * @param registrationTech The Radio Access Technology that IMS is registered on.
+         */
+        public Builder(@ImsRegistrationImplBase.ImsRegistrationTech int registrationTech) {
+            mRegistrationTech = registrationTech;
+        }
+
+        /**
+         * Optional IMS feature tags included in this IMS registration.
+         * @param tags A set of Strings containing the MMTEL and RCS feature tags associated with
+         *         the IMS registration. This information is used for services such as the UCE
+         *         service to ascertain the complete IMS registration state to ensure the SIP
+         *         PUBLISH is accurate. The format of the set of feature tags must be one feature
+         *         tag key and value per entry. Each feature tag will contain the feature tag name
+         *         and string value (if applicable), even if they have the same feature tag name.
+         *         For example,
+         *         {@code +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg,
+         *         urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session", +g.gsma.callcomposer} must
+         *         be split into three feature tag entries:
+         *         {@code {+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg",
+         *         +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session",
+         *         +g.gsma.callcomposer}}.
+         */
+        public @NonNull Builder setFeatureTags(@NonNull Set<String> tags) {
+            if (tags == null) {
+                throw new IllegalArgumentException("feature tag set must not be null");
+            }
+            mFeatureTags = new ArraySet<>(tags);
+            return this;
+        }
+
+        /**
+         * @return A new instance created from this builder.
+         */
+        public @NonNull ImsRegistrationAttributes build() {
+            return new ImsRegistrationAttributes(mRegistrationTech,
+                    RegistrationManager.getAccessType(mRegistrationTech),
+                    0 /* No attributes in AOSP */, mFeatureTags);
+        }
+
+    }
+
+    private final int mRegistrationTech;
+    private final int mTransportType;
+    private final int mImsAttributeFlags;
+    private final ArrayList<String> mFeatureTags;
+
+    /**
+     * Create a new {@link ImsRegistrationAttributes} instance.
+     *
+     * @param registrationTech The technology that IMS has been registered on.
+     * @param transportType The transport type that IMS has been registered on.
+     * @param imsAttributeFlags The attributes associated with the IMS registration.
+     * @param featureTags The feature tags included in the IMS registration.
+     * @see Builder
+     * @hide
+     */
+    public ImsRegistrationAttributes(
+            @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech,
+            @AccessNetworkConstants.TransportType int transportType,
+            int imsAttributeFlags,
+            @Nullable Set<String> featureTags) {
+        mRegistrationTech = registrationTech;
+        mTransportType = transportType;
+        mImsAttributeFlags = imsAttributeFlags;
+        mFeatureTags = new ArrayList<>(featureTags);
+    }
+
+    /**@hide*/
+    public ImsRegistrationAttributes(Parcel source) {
+        mRegistrationTech = source.readInt();
+        mTransportType = source.readInt();
+        mImsAttributeFlags = source.readInt();
+        mFeatureTags = new ArrayList<>();
+        source.readList(mFeatureTags, null /*classloader*/);
+    }
+
+    /**
+     * @return The Radio Access Technology that the IMS registration has been registered over.
+     * @hide
+     */
+    @SystemApi
+    public @ImsRegistrationImplBase.ImsRegistrationTech int getRegistrationTechnology() {
+        return mRegistrationTech;
+    }
+
+    /**
+     * @return The access network transport type that IMS has been registered over.
+     */
+    public @AccessNetworkConstants.TransportType int  getTransportType() {
+        return mTransportType;
+    }
+
+    /**
+     * @return A bit-mask containing attributes associated with the IMS registration.
+     */
+    public int getAttributeFlags() {
+        return mImsAttributeFlags;
+    }
+
+    /**
+     * Gets the Set of feature tags associated with the current IMS registration, if the IMS
+     * service supports supplying this information.
+     * <p>
+     * The format of the set of feature tags will be one feature tag key and value per entry and
+     * will potentially contain MMTEL and RCS feature tags, depending the configuration of the IMS
+     * service associated with the registration indications. Each feature tag will contain the
+     * feature tag name and string value (if applicable), even if they have the same feature tag
+     * name. For example, {@code +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg,
+     * urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session", +g.gsma.callcomposer} will be split
+     * into three feature tag  entries:
+     * {@code {+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg",
+     * +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session",
+     * +g.gsma.callcomposer}}.
+     * @return The Set of feature tags associated with the current IMS registration.
+     */
+    public @NonNull Set<String> getFeatureTags() {
+        if (mFeatureTags == null) {
+            return Collections.emptySet();
+        }
+        return new ArraySet<>(mFeatureTags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mRegistrationTech);
+        dest.writeInt(mTransportType);
+        dest.writeInt(mImsAttributeFlags);
+        dest.writeList(mFeatureTags);
+    }
+
+    public static final @NonNull Creator<ImsRegistrationAttributes> CREATOR =
+            new Creator<ImsRegistrationAttributes>() {
+                @Override
+                public ImsRegistrationAttributes createFromParcel(Parcel source) {
+                    return new ImsRegistrationAttributes(source);
+                }
+
+                @Override
+                public ImsRegistrationAttributes[] newArray(int size) {
+                    return new ImsRegistrationAttributes[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ImsRegistrationAttributes that = (ImsRegistrationAttributes) o;
+        return mRegistrationTech == that.mRegistrationTech
+                && mTransportType == that.mTransportType
+                && mImsAttributeFlags == that.mImsAttributeFlags
+                && Objects.equals(mFeatureTags, that.mFeatureTags);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mRegistrationTech, mTransportType, mImsAttributeFlags, mFeatureTags);
+    }
+
+    @Override
+    public String toString() {
+        return "ImsRegistrationAttributes { transportType= " + mTransportType + ", attributeFlags="
+                + mImsAttributeFlags + ", featureTags=[" + mFeatureTags + "]}";
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index f3c38bc..08eec29d 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -25,6 +25,7 @@
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.WorkerThread;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -1325,7 +1326,7 @@
      * the RCS VoLTE single registration feature. Only default messaging application may receive
      * the intent.
      *
-     * <p>Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to specify the subscription index for which
+     * <p>Contains {@link #EXTRA_SUBSCRIPTION_ID} to specify the subscription index for which
      * the intent is valid. and {@link #EXTRA_STATUS} to specify RCS VoLTE single registration
      * status.
      */
@@ -1371,7 +1372,7 @@
      * provisioning is done using autoconfiguration, then these parameters shall be
      * sent in the HTTP get request to fetch the RCS provisioning. RCS client
      * configuration must be provided by the application before registering for the
-     * provisioning status events {@link #registerRcsProvisioningChangedCallback()}
+     * provisioning status events {@link #registerRcsProvisioningChangedCallback}
      * @param rcc RCS client configuration {@link RcsClientConfiguration}
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@@ -1387,13 +1388,15 @@
     }
 
     /**
-     * Returns a flag to indicate if the device software and the carrier
-     * have the capability to support RCS Volte single IMS registration.
-     * @return true if this single registration is capable, false otherwise
+     * Returns a flag to indicate whether or not the device supports IMS single registration for
+     * MMTEL and RCS features as well as if the carrier has provisioned the feature.
+     * @return true if IMS single registration is capable at this time, or false otherwise
      * @throws ImsException If the remote ImsService is not available for
      * any reason or the subscription associated with this instance is no
      * longer active. See {@link ImsException#getCode()} for more
      * information.
+     * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION for whether or not this
+     * device supports IMS single registration.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isRcsVolteSingleRegistrationCapable() throws ImsException {
@@ -1430,7 +1433,7 @@
      * available. This can happen if the service crashed, for example.
      * It shall also throw this exception when the RCS client parameters for the
      * application are not valid. In that case application must set the client
-     * params (See {@link #setRcsClientConfiguration()}) and re register the
+     * params (See {@link #setRcsClientConfiguration}) and re register the
      * callback.
      * See {@link ImsException#getCode()} for a more detailed reason.
      */
@@ -1458,9 +1461,9 @@
      * will result in a no-op.
      * @param callback The existing {@link RcsProvisioningCallback} to be
      * removed.
-     * @see #registerRcsProvisioningChangedCallback(RcsClientConfiguration,
-     * Executor, RcsProvisioningCallback) @throws IllegalArgumentException
-     * if the subscription associated with this callback is invalid.
+     * @see #registerRcsProvisioningChangedCallback
+     * @throws IllegalArgumentException if the subscription associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterRcsProvisioningChangedCallback(
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 2c75368..c49121f 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -71,7 +71,6 @@
      */
     int REGISTRATION_STATE_REGISTERED = 2;
 
-
     /**@hide*/
     // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
     // and WWAN are more accurate constants.
@@ -79,7 +78,8 @@
             new HashMap<Integer, Integer>() {{
                 // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
                 // case, since it is defined.
-                put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE,
+                        AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
                 put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
                 put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
@@ -103,6 +103,20 @@
     }
 
     /**
+     * @param regtech The registration technology.
+     * @return The Access Network type from registration technology.
+     * @hide
+     */
+    static int getAccessType(int regtech) {
+        if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regtech)) {
+            Log.w("RegistrationManager", "getAccessType - invalid regType returned: "
+                    + regtech);
+            return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+        }
+        return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regtech);
+    }
+
+    /**
      * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
@@ -119,26 +133,24 @@
             }
 
             @Override
-            public void onRegistered(int imsRadioTech) {
+            public void onRegistered(ImsRegistrationAttributes attr) {
                 if (mLocalCallback == null) return;
 
                 long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    mExecutor.execute(() ->
-                            mLocalCallback.onRegistered(getAccessType(imsRadioTech)));
+                    mExecutor.execute(() -> mLocalCallback.onRegistered(attr));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
             }
 
             @Override
-            public void onRegistering(int imsRadioTech) {
+            public void onRegistering(ImsRegistrationAttributes attr) {
                 if (mLocalCallback == null) return;
 
                 long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    mExecutor.execute(() ->
-                            mLocalCallback.onRegistering(getAccessType(imsRadioTech)));
+                    mExecutor.execute(() -> mLocalCallback.onRegistering(attr));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
@@ -183,15 +195,6 @@
             private void setExecutor(Executor executor) {
                 mExecutor = executor;
             }
-
-            private static int getAccessType(int regType) {
-                if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
-                    Log.w("RegistrationManager", "RegistrationBinder - invalid regType returned: "
-                            + regType);
-                    return -1;
-                }
-                return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
-            }
         }
 
         private final RegistrationBinder mBinder = new RegistrationBinder(this);
@@ -200,19 +203,42 @@
          * Notifies the framework when the IMS Provider is registered to the IMS network.
          *
          * @param imsTransportType the radio access technology.
+         * @deprecated Use {@link #onRegistered(ImsRegistrationAttributes)} instead.
          */
         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
         /**
+         * Notifies the framework when the IMS Provider is registered to the IMS network
+         * with corresponding attributes.
+         *
+         * @param attributes The attributes associated with this IMS registration.
+         */
+        public void onRegistered(@NonNull ImsRegistrationAttributes attributes) {
+            // Default impl to keep backwards compatibility with old implementations
+            onRegistered(attributes.getTransportType());
+        }
+
+        /**
          * Notifies the framework when the IMS Provider is trying to register the IMS network.
          *
          * @param imsTransportType the radio access technology.
+         * @deprecated Use {@link #onRegistering(ImsRegistrationAttributes)} instead.
          */
         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
         /**
+         * Notifies the framework when the IMS Provider is trying to register the IMS network.
+         *
+         * @param attributes The attributes associated with this IMS registration.
+         */
+        public void onRegistering(@NonNull ImsRegistrationAttributes attributes) {
+            // Default impl to keep backwards compatibility with old implementations
+            onRegistering(attributes.getTransportType());
+        }
+
+        /**
          * Notifies the framework when the IMS Provider is unregistered from the IMS network.
          *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
@@ -298,10 +324,10 @@
      * @param executor The {@link Executor} that will be used to call the IMS registration state
      *                 callback.
      * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
- *                      registration state of the IMS service, which will be one of the
- *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
- *                      {@link #REGISTRATION_STATE_REGISTERING}, or
- *                      {@link #REGISTRATION_STATE_REGISTERED}.
+     *                      registration state of the IMS service, which will be one of the
+     *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
+     *                      {@link #REGISTRATION_STATE_REGISTERING}, or
+     *                      {@link #REGISTRATION_STATE_REGISTERED}.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 2e9eb94..04421c9 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -24,6 +24,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.telephony.BinderCacheManager;
@@ -47,6 +48,9 @@
  * This allows multiple IMS applications to forward SIP messages to/from their application for the
  * purposes of providing a single IMS registration to the carrier's IMS network from potentially
  * many IMS stacks implementing a subset of the supported MMTEL/RCS features.
+ * <p>
+ * This API is only supported if the device supports the
+ * {@link PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION} feature.
  * @hide
  */
 @SystemApi
@@ -269,6 +273,7 @@
      * {@link ImsException#getCode()} for more information.
      *
      * @see CarrierConfigManager.Ims#KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL
+     * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isSupported() throws ImsException {
diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
index 4435640e..a217d13 100644
--- a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.stub.CapabilityExchangeEventListener;
 import android.util.Log;
@@ -47,7 +48,7 @@
      * Receives the request of publishing capabilities from the network and deliver this request
      * to the framework via the registered capability exchange event listener.
      */
-    public void onRequestPublishCapabilities(int publishTriggerType) {
+    public void onRequestPublishCapabilities(int publishTriggerType) throws ImsException {
         ICapabilityExchangeEventListener listener = mListenerBinder;
         if (listener == null) {
             return;
@@ -56,13 +57,15 @@
             listener.onRequestPublishCapabilities(publishTriggerType);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "request publish capabilities exception: " + e);
+            throw new ImsException("Remote is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
     /**
      * Receives the unpublish notification and deliver this callback to the framework.
      */
-    public void onUnpublish() {
+    public void onUnpublish() throws ImsException {
         ICapabilityExchangeEventListener listener = mListenerBinder;
         if (listener == null) {
             return;
@@ -71,6 +74,8 @@
             listener.onUnpublish();
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Unpublish exception: " + e);
+            throw new ImsException("Remote is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -79,7 +84,8 @@
      * request to the framework.
      */
     public void onRemoteCapabilityRequest(@NonNull Uri contactUri,
-            @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback) {
+            @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback)
+            throws ImsException {
         ICapabilityExchangeEventListener listener = mListenerBinder;
         if (listener == null) {
             return;
@@ -87,10 +93,11 @@
 
         IOptionsRequestCallback internalCallback = new IOptionsRequestCallback.Stub() {
             @Override
-            public void respondToCapabilityRequest(RcsContactUceCapability ownCapabilities) {
+            public void respondToCapabilityRequest(RcsContactUceCapability ownCapabilities,
+                    boolean isBlocked) {
                 final long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    callback.onRespondToCapabilityRequest(ownCapabilities);
+                    callback.onRespondToCapabilityRequest(ownCapabilities, isBlocked);
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
@@ -110,6 +117,8 @@
             listener.onRemoteCapabilityRequest(contactUri, remoteCapabilities, internalCallback);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Remote capability request exception: " + e);
+            throw new ImsException("Remote is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 7a6c28b..8931a78 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -47,7 +47,7 @@
     void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
     void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
     boolean isCapable(int subId, int capability, int radioTech);
-    boolean isAvailable(int subId, int capability);
+    boolean isAvailable(int subId, int capability, int radioTech);
 
     // ImsUceAdapter specific
     void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
index 749b191..179407c 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
@@ -21,6 +21,7 @@
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
 
 /**
  * See {@link ImsManager#RegistrationCallback} for more information.
@@ -28,8 +29,8 @@
  * {@hide}
  */
 oneway interface IImsRegistrationCallback {
-   void onRegistered(int imsRadioTech);
-   void onRegistering(int imsRadioTech);
+   void onRegistered(in ImsRegistrationAttributes attr);
+   void onRegistering(in ImsRegistrationAttributes attr);
    void onDeregistered(in ImsReasonInfo info);
    void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
    void onSubscriberAssociatedUriChanged(in Uri[] uris);
diff --git a/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl
index d4d5301..8eecbca 100644
--- a/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl
@@ -27,8 +27,9 @@
      * Respond to a remote capability request from the contact specified with the capabilities
      * of this device.
      * @param ownCapabilities The capabilities of this device.
+     * @param isBlocked True if the user has blocked the number sending this request.
      */
-    void respondToCapabilityRequest(in RcsContactUceCapability ownCapabilities);
+    void respondToCapabilityRequest(in RcsContactUceCapability ownCapabilities, boolean isBlocked);
 
     /**
      * Respond to a remote capability request from the contact specified with the
diff --git a/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
index 481e7f8..b99d8a7d 100644
--- a/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
@@ -26,4 +26,5 @@
 oneway interface IPublishResponseCallback {
     void onCommandError(int code);
     void onNetworkResponse(int code, String reason);
+    void onNetworkRespHeader(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
index a141993..8cc8020 100644
--- a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
@@ -30,6 +30,7 @@
 oneway interface ISubscribeResponseCallback {
     void onCommandError(int code);
     void onNetworkResponse(int code, in String reason);
+    void onNetworkRespHeader(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText);
     void onNotifyCapabilitiesUpdate(in List<String> pidfXmls);
     void onResourceTerminated(in List<RcsContactTerminatedReason> uriTerminatedReason);
     void onTerminated(in String reason, long retryAfterMilliseconds);
diff --git a/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java
index 22985d0..65415ea 100644
--- a/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java
@@ -34,10 +34,11 @@
     }
 
     @Override
-    public void onCommandError(int code) {
+    public void onCommandError(int code) throws ImsException {
         try {
             mResponseBinder.onCommandError(code);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -46,6 +47,18 @@
         try {
             mResponseBinder.onNetworkResponse(code, reason);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    @Override
+    public void onNetworkResponse(int code, String reasonPhrase, int reasonHeaderCause,
+            String reasonHeaderText) throws ImsException {
+        try {
+            mResponseBinder.onNetworkRespHeader(code, reasonPhrase, reasonHeaderCause,
+                    reasonHeaderText);
+        } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
index 1fb339c..11118c0 100644
--- a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
@@ -40,10 +40,11 @@
     }
 
     @Override
-    public void onCommandError(int code) {
+    public void onCommandError(int code) throws ImsException {
         try {
             mResponseBinder.onCommandError(code);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -52,6 +53,18 @@
         try {
             mResponseBinder.onNetworkResponse(code, reason);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    @Override
+    public void onNetworkResponse(int code, String reasonPhrase, int reasonHeaderCause,
+            String reasonHeaderText) throws ImsException {
+        try {
+            mResponseBinder.onNetworkRespHeader(code, reasonPhrase, reasonHeaderCause,
+                    reasonHeaderText);
+        } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -60,6 +73,7 @@
         try {
             mResponseBinder.onNotifyCapabilitiesUpdate(pidfXmls);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -69,6 +83,7 @@
         try {
             mResponseBinder.onResourceTerminated(getTerminatedReasonList(uriTerminatedReason));
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
@@ -90,6 +105,7 @@
         try {
             mResponseBinder.onTerminated(reason, retryAfterMilliseconds);
         } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 }
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 87a6873..47c56e1 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -36,12 +36,9 @@
 public final class CapabilityChangeRequest implements Parcelable {
 
     /**
-     * Contains a feature capability, defined as
-     * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
-     * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
-     * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
-     * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS},
-     * along with an associated technology, defined as
+     * Contains a MMTEL feature capability {@link MmTelFeature.MmTelCapabilities} and RCS feature
+     * capability {@link RcsFeature.RcsImsCapabilities}, along with an associated technology,
+     * defined as
      * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
      * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
      */
@@ -49,7 +46,7 @@
         private final int mCapability;
         private final int radioTech;
 
-        public CapabilityPair(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+        public CapabilityPair(int capability,
                 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
             this.mCapability = capability;
             this.radioTech = radioTech;
@@ -80,13 +77,10 @@
         }
 
         /**
-         * @return The stored capability, defined as
-         * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
-         * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
-         * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
-         * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+         * @return The stored capability, defined as {@link MmTelFeature.MmTelCapabilities} and
+         * {@link RcsFeature.RcsImsCapabilities}
          */
-        public @MmTelFeature.MmTelCapabilities.MmTelCapability int getCapability() {
+        public int getCapability() {
             return mCapability;
         }
 
@@ -123,12 +117,11 @@
      * Add one or many capabilities to the request to be enabled.
      *
      * @param capabilities A bitfield of capabilities to enable, valid values are defined in
-     *   {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+     *   {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
      * @param radioTech  the radio tech that these capabilities should be enabled for, valid
      *   values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
      */
-    public void addCapabilitiesToEnableForTech(
-            @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+    public void addCapabilitiesToEnableForTech(int capabilities,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
         addAllCapabilities(mCapabilitiesToEnable, capabilities, radioTech);
     }
@@ -136,12 +129,11 @@
     /**
      * Add one or many capabilities to the request to be disabled.
      * @param capabilities A bitfield of capabilities to diable, valid values are defined in
-     *   {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+     *   {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
      * @param radioTech the radio tech that these capabilities should be disabled for, valid
      *   values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
      */
-    public void addCapabilitiesToDisableForTech(
-            @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+    public void addCapabilitiesToDisableForTech(int capabilities,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
         addAllCapabilities(mCapabilitiesToDisable, capabilities, radioTech);
     }
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 22df921..85703f8 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -194,7 +194,6 @@
      * of the capability and notify the capability status as true using
      * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
      * framework that the capability is available for usage.
-     * @hide
      */
     public static class RcsImsCapabilities extends Capabilities {
         /** @hide*/
@@ -226,12 +225,21 @@
          */
         public static final int CAPABILITY_TYPE_PRESENCE_UCE =  1 << 1;
 
+        /**
+         * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+         * @param capabilities The capabilities that are supported for RCS in the form of a
+         * bitfield.
+         */
         public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
             super(capabilities);
         }
 
-        private RcsImsCapabilities(Capabilities c) {
-            super(c.getMask());
+        /**
+         * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+         * @param capabilities The capabilities instance that are supported for RCS
+         */
+        private RcsImsCapabilities(Capabilities capabilities) {
+            super(capabilities.getMask());
         }
 
         @Override
@@ -307,7 +315,7 @@
      * set, the {@link RcsFeature} has brought up the capability and is ready for framework
      * requests. To change the status of the capabilities
      * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
-     * @hide
+     * @return A copy of the current RcsFeature capability status.
      */
     @Override
     public @NonNull final RcsImsCapabilities queryCapabilityStatus() {
@@ -318,13 +326,13 @@
      * Notify the framework that the capabilities status has changed. If a capability is enabled,
      * this signals to the framework that the capability has been initialized and is ready.
      * Call {@link #queryCapabilityStatus()} to return the current capability status.
-     * @hide
+     * @param capabilities The current capability status of the RcsFeature.
      */
-    public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
-        if (c == null) {
+    public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) {
+        if (capabilities == null) {
             throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
         }
-        super.notifyCapabilitiesStatusChanged(c);
+        super.notifyCapabilitiesStatusChanged(capabilities);
     }
 
     /**
@@ -333,7 +341,9 @@
      * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to
      * enable or disable capability A, this method should return the correct configuration for
      * capability A afterwards (until it has changed).
-     * @hide
+     * @param capability The capability that we are querying the configuration for.
+     * @param radioTech The radio technology type that we are querying.
+     * @return true if the capability is enabled, false otherwise.
      */
     public boolean queryCapabilityConfiguration(
             @RcsUceAdapter.RcsImsCapabilityFlag int capability,
@@ -355,11 +365,12 @@
      * If for some reason one or more of these capabilities can not be enabled/disabled,
      * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should
      * be called for each capability change that resulted in an error.
-     * @hide
+     * @param request The request to change the capability.
+     * @param callback To notify the framework that the result of the capability changes.
      */
     @Override
     public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
-            @NonNull CapabilityCallbackProxy c) {
+            @NonNull CapabilityCallbackProxy callback) {
         // Base Implementation - Override to provide functionality
     }
 
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index d9734a7..4967e5d 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -16,32 +16,58 @@
 
 package android.telephony.ims.stub;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.net.Uri;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
+
+import java.util.List;
 
 /**
- * The interface of the capabilities event listener for ImsService to notify the framework of the
- * UCE request and status updated.
+ * The interface that is used by the framework to listen to events from the vendor RCS stack
+ * regarding capabilities exchange using presence server and OPTIONS.
  * @hide
  */
 @SystemApi
 public interface CapabilityExchangeEventListener {
     /**
      * Interface used by the framework to respond to OPTIONS requests.
-     * @hide
      */
     interface OptionsRequestCallback {
         /**
          * Respond to a remote capability request from the contact specified with the
          * capabilities of this device.
          * @param ownCapabilities The capabilities of this device.
+         * @hide
          */
-        void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities);
+        default void onRespondToCapabilityRequest(
+                @NonNull RcsContactUceCapability ownCapabilities) {}
+
+        /**
+         * Respond to a remote capability request from the contact specified with the
+         * capabilities of this device.
+         * @param ownCapabilities The capabilities of this device.
+         * @param isBlocked Whether or not the user has blocked the number requesting the
+         *         capabilities of this device. If true, the device should respond to the OPTIONS
+         *         request with a 200 OK response and no capabilities.
+         */
+        default void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities,
+                boolean isBlocked) {
+            Log.w("CapabilityExchangeEventListener", "implement "
+                    + "onRespondToCapabilityRequest(RcsContactUceCapability, boolean) instead!");
+            // Fall back to old implementation
+            if (isBlocked) {
+                onRespondToCapabilityRequestWithError(200, "OK");
+            } else {
+                onRespondToCapabilityRequest(ownCapabilities);
+            }
+        }
 
         /**
          * Respond to a remote capability request from the contact specified with the
@@ -49,7 +75,8 @@
          * @param code The SIP response code to respond with.
          * @param reason A non-null String containing the reason associated with the SIP code.
          */
-        void onRespondToCapabilityRequestWithError(int code, @NonNull String reason);
+        void onRespondToCapabilityRequestWithError(@IntRange(from = 100, to = 699) int code,
+                @NonNull String reason);
     }
 
     /**
@@ -59,8 +86,7 @@
      * This is typically used when trying to generate an initial PUBLISH for a new subscription to
      * the network. The device will cache all presence publications after boot until this method is
      * called the first time.
-     * @param publishTriggerType {@link RcsUceAdapter#StackPublishTriggerType} The reason for the
-     * capability update request.
+     * @param publishTriggerType The reason for the capability update request.
      * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not currently
      * connected to the framework. This can happen if the {@link RcsFeature} is not
      * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
@@ -81,4 +107,25 @@
      * Telephony stack has crashed.
      */
     void onUnpublish() throws ImsException;
+
+    /**
+     * Inform the framework of an OPTIONS query from a remote device for this device's UCE
+     * capabilities.
+     * <p>
+     * The framework will respond via the
+     * {@link OptionsRequestCallback#onRespondToCapabilityRequest} or
+     * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}.
+     * @param contactUri The URI associated with the remote contact that is
+     * requesting capabilities.
+     * @param remoteCapabilities The remote contact's capability information.
+     * @param callback The callback of this request which is sent from the remote user.
+     * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not
+     * currently connected to the framework. This can happen if the {@link RcsFeature} is not
+     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+     * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
+     * cases when the Telephony stack has crashed.
+     */
+    void onRemoteCapabilityRequest(@NonNull Uri contactUri,
+            @NonNull List<String> remoteCapabilities,
+            @NonNull OptionsRequestCallback callback) throws ImsException;
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 2e35d27..5f8e93d 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -44,8 +44,12 @@
         @Override
         public void setListener(IImsEcbmListener listener) {
             synchronized (mLock) {
-                if (mImsEcbm != null && listener != null && Objects.equals(
-                        mImsEcbm.asBinder(), listener.asBinder())) {
+                if (mListener != null && !mListener.asBinder().isBinderAlive()) {
+                    Log.w(TAG, "setListener: discarding dead Binder");
+                    mListener = null;
+                }
+                if (mListener != null && listener != null && Objects.equals(
+                        mListener.asBinder(), listener.asBinder())) {
                     return;
                 }
                 if (listener == null) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index 555a47e..8e961ac 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -48,6 +48,10 @@
         @Override
         public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
             synchronized (mLock) {
+                if (mListener != null && !mListener.asBinder().isBinderAlive()) {
+                    Log.w(TAG, "setListener: discarding dead Binder");
+                    mListener = null;
+                }
                 if (mListener != null && listener != null && Objects.equals(
                         mListener.asBinder(), listener.asBinder())) {
                     return;
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 088a7e2..23032f0 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -18,17 +18,18 @@
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
 import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.util.RemoteCallbackListExt;
 import com.android.internal.util.ArrayUtils;
 
@@ -83,7 +84,10 @@
 
         @Override
         public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
-            return getConnectionType();
+            synchronized (mLock) {
+                return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
+                        : mRegistrationAttributes.getRegistrationTechnology();
+            }
         }
 
         @Override
@@ -116,8 +120,7 @@
             new RemoteCallbackListExt<>();
     private final Object mLock = new Object();
     // Locked on mLock
-    private @ImsRegistrationTech
-    int mConnectionType = REGISTRATION_TECH_NONE;
+    private ImsRegistrationAttributes mRegistrationAttributes;
     // Locked on mLock
     private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
     // Locked on mLock, create unspecified disconnect cause.
@@ -195,17 +198,24 @@
     /**
      * Notify the framework that the device is connected to the IMS network.
      *
-     * @param imsRadioTech the radio access technology. Valid values are defined as
-     * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
+     * @param imsRadioTech the radio access technology.
      */
     public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+        onRegistered(new ImsRegistrationAttributes.Builder(imsRadioTech).build());
+    }
+
+    /**
+     * Notify the framework that the device is connected to the IMS network.
+     *
+     * @param attributes The attributes associated with the IMS registration.
+     */
+    public final void onRegistered(@NonNull ImsRegistrationAttributes attributes) {
+        updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         mCallbacks.broadcastAction((c) -> {
             try {
-                c.onRegistered(imsRadioTech);
+                c.onRegistered(attributes);
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " " + "onRegistrationConnected() - Skipping " +
-                        "callback.");
+                Log.w(LOG_TAG, e + "onRegistered(int, Set) - Skipping callback.");
             }
         });
     }
@@ -213,17 +223,24 @@
     /**
      * Notify the framework that the device is trying to connect the IMS network.
      *
-     * @param imsRadioTech the radio access technology. Valid values are defined as
-     * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
+     * @param imsRadioTech the radio access technology.
      */
     public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+        onRegistering(new ImsRegistrationAttributes.Builder(imsRadioTech).build());
+    }
+
+    /**
+     * Notify the framework that the device is trying to connect the IMS network.
+     *
+     * @param attributes The attributes associated with the IMS registration.
+     */
+    public final void onRegistering(@NonNull ImsRegistrationAttributes attributes) {
+        updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         mCallbacks.broadcastAction((c) -> {
             try {
-                c.onRegistering(imsRadioTech);
+                c.onRegistering(attributes);
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " " + "onRegistrationProcessing() - Skipping " +
-                        "callback.");
+                Log.w(LOG_TAG, e + "onRegistering(int, Set) - Skipping callback.");
             }
         });
     }
@@ -252,8 +269,7 @@
             try {
                 c.onDeregistered(reasonInfo);
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " +
-                        "callback.");
+                Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
             }
         });
     }
@@ -272,8 +288,7 @@
             try {
                 c.onTechnologyChangeFailed(imsRadioTech, reasonInfo);
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " +
-                        "callback.");
+                Log.w(LOG_TAG, e + "onTechnologyChangeFailed() - Skipping callback.");
             }
         });
     }
@@ -297,14 +312,13 @@
         try {
             callback.onSubscriberAssociatedUriChanged(uris);
         } catch (RemoteException e) {
-            Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping "
-                    + "callback.");
+            Log.w(LOG_TAG, e + "onSubscriberAssociatedUriChanged() - Skipping callback.");
         }
     }
 
-    private void updateToState(@ImsRegistrationTech int connType, int newState) {
+    private void updateToState(ImsRegistrationAttributes attributes, int newState) {
         synchronized (mLock) {
-            mConnectionType = connType;
+            mRegistrationAttributes = attributes;
             mRegistrationState = newState;
             mLastDisconnectCause = null;
         }
@@ -316,7 +330,7 @@
             mUrisSet = false;
             mUris = null;
 
-            updateToState(REGISTRATION_TECH_NONE,
+            updateToState(new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_NONE).build(),
                     RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
             if (info != null) {
                 mLastDisconnectCause = info;
@@ -328,29 +342,19 @@
     }
 
     /**
-     * @return the current registration connection type. Valid values are
-     * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}
-     * @hide
-     */
-    @VisibleForTesting
-    public final @ImsRegistrationTech int getConnectionType() {
-        synchronized (mLock) {
-            return mConnectionType;
-        }
-    }
-
-    /**
      * @param c the newly registered callback that will be updated with the current registration
      *         state.
      */
     private void updateNewCallbackWithState(IImsRegistrationCallback c)
             throws RemoteException {
         int state;
+        ImsRegistrationAttributes attributes;
         ImsReasonInfo disconnectInfo;
         boolean urisSet;
         Uri[] uris;
         synchronized (mLock) {
             state = mRegistrationState;
+            attributes = mRegistrationAttributes;
             disconnectInfo = mLastDisconnectCause;
             urisSet = mUrisSet;
             uris = mUris;
@@ -361,11 +365,11 @@
                 break;
             }
             case RegistrationManager.REGISTRATION_STATE_REGISTERING: {
-                c.onRegistering(getConnectionType());
+                c.onRegistering(attributes);
                 break;
             }
             case RegistrationManager.REGISTRATION_STATE_REGISTERED: {
-                c.onRegistered(getConnectionType());
+                c.onRegistered(attributes);
                 break;
             }
             case REGISTRATION_STATE_UNKNOWN: {
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index eef4fca..83b89aa 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.telephony.ims.ImsUtListener;
+import android.util.Log;
 
 import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsUtListener;
@@ -41,6 +42,7 @@
 // will break other implementations of ImsUt maintained by other ImsServices.
 @SystemApi
 public class ImsUtImplBase {
+    private static final String TAG = "ImsUtImplBase";
     /**
      * Bar all incoming calls. (See 3GPP TS 24.611)
      * @hide
@@ -207,6 +209,11 @@
         @Override
         public void setListener(IImsUtListener listener) throws RemoteException {
             synchronized (mLock) {
+                if (mUtListener != null
+                        && !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
+                    Log.w(TAG, "setListener: discarding dead Binder");
+                    mUtListener = null;
+                }
                 if (mUtListener != null && listener != null && Objects.equals(
                         mUtListener.getListenerInterface().asBinder(), listener.asBinder())) {
                     return;
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 7eba709..908869b 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.net.Uri;
@@ -140,6 +139,9 @@
          * Provide the framework with a subsequent network response update to
          * {@link #publishCapabilities(String, PublishResponseCallback)}.
          *
+         * If this network response also contains a “Reason” header, then the
+         * {@link #onNetworkResponse(int, String, int, String)} method should be used instead.
+         *
          * @param sipCode The SIP response code sent from the network for the operation
          * token specified.
          * @param reason The optional reason response from the network. If there is a reason header
@@ -154,11 +156,35 @@
          */
         void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
                 @NonNull String reason) throws ImsException;
+
+        /**
+         * Provide the framework with a subsequent network response update to
+         * {@link #publishCapabilities(String, PublishResponseCallback)} that also
+         * includes a reason provided in the “reason” header. See RFC3326 for more
+         * information.
+         *
+         * @param sipCode The SIP response code sent from the network.
+         * @param reasonPhrase The optional reason response from the network. If the
+         * network provided no reason with the sip code, the string should be empty.
+         * @param reasonHeaderCause The “cause” parameter of the “reason” header
+         * included in the SIP message.
+         * @param reasonHeaderText The “text” parameter of the “reason” header
+         * included in the SIP message.
+         * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+         * not currently connected to the framework. This can happen if the
+         * {@link RcsFeature} is not
+         * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+         * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+         * rare cases when the Telephony stack has crashed.
+         */
+        void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
+                @NonNull String reasonPhrase,
+                @IntRange(from = 100, to = 699) int reasonHeaderCause,
+                @NonNull String reasonHeaderText) throws ImsException;
     }
 
     /**
      * Interface used by the framework to respond to OPTIONS requests.
-     * @hide
      */
     public interface OptionsResponseCallback {
         /**
@@ -189,7 +215,7 @@
          * cases when the Telephony stack has crashed.
          */
         void onNetworkResponse(int sipCode, @NonNull String reason,
-                @Nullable List<String> theirCaps) throws ImsException;
+                @NonNull List<String> theirCaps) throws ImsException;
     }
 
     /**
@@ -215,13 +241,16 @@
 
         /**
          * Notify the framework of the response to the SUBSCRIBE request from
-         * {@link #subscribeForCapabilities(List<Uri>, SubscribeResponseCallback)}.
+         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)}.
          * <p>
          * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
          * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
          * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the
          * subsequent NOTIFY responses to the subscription.
          *
+         * If this network response also contains a “Reason” header, then the
+         * {@link #onNetworkResponse(int, String, int, String)} method should be used instead.
+         *
          * @param sipCode The SIP response code sent from the network for the operation
          * token specified.
          * @param reason The optional reason response from the network. If the network
@@ -236,9 +265,35 @@
                 @NonNull String reason) throws ImsException;
 
         /**
+         * Notify the framework  of the response to the SUBSCRIBE request from
+         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)} that also
+         * includes a reason provided in the “reason” header. See RFC3326 for more
+         * information.
+         *
+         * @param sipCode The SIP response code sent from the network,
+         * @param reasonPhrase The optional reason response from the network. If the
+         * network provided no reason with the sip code, the string should be empty.
+         * @param reasonHeaderCause The “cause” parameter of the “reason” header
+         * included in the SIP message.
+         * @param reasonHeaderText The “text” parameter of the “reason” header
+         * included in the SIP message.
+         * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+         * not currently connected to the framework. This can happen if the
+         * {@link RcsFeature} is not
+         * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+         * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+         * rare cases when the Telephony stack has crashed.
+         */
+        void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
+                @NonNull String reasonPhrase,
+                @IntRange(from = 100, to = 699) int reasonHeaderCause,
+                @NonNull String reasonHeaderText) throws ImsException;
+
+        /**
          * Notify the framework of the latest XML PIDF documents included in the network response
          * for the requested contacts' capabilities requested by the Framework using
-         * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}.
+         * {@link RcsUceAdapter#requestCapabilities(List, Executor,
+         * RcsUceAdapter.CapabilitiesCallback)}.
          * <p>
          * The expected format for the PIDF XML is defined in RFC3861. Each XML document must be a
          * "application/pidf+xml" object and start with a root <presence> element. For NOTIFY
@@ -280,7 +335,8 @@
 
         /**
          * The subscription associated with a previous
-         * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}
+         * {@link RcsUceAdapter#requestCapabilities(List, Executor,
+         * RcsUceAdapter.CapabilitiesCallback)}
          * operation has been terminated. This will mostly be due to the network sending a final
          * NOTIFY response due to the subscription expiring, but this may also happen due to a
          * network error.
@@ -371,12 +427,11 @@
      * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
      * in order to receive the capabilities of the remote user in response.
      * <p>
-     * The implementer must call {@link #onNetworkResponse} to send the response of this
-     * query back to the framework.
+     * The implementer must use {@link OptionsResponseCallback} to send the response of
+     * this query from the network back to the framework.
      * @param contactUri The URI of the remote user that we wish to get the capabilities of.
      * @param myCapabilities The capabilities of this device to send to the remote user.
      * @param callback The callback of this request which is sent from the remote user.
-     * @hide
      */
     // executor used is defined in the constructor.
     @SuppressLint("ExecutorRegistration")
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index d79225f..ec12040 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -28,6 +29,7 @@
 import com.android.telephony.Rlog;
 
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
@@ -253,13 +255,48 @@
         }
 
         if ((b & 0x0f) <= 0x09) {
-            ret +=  (b & 0xf);
+            ret += (b & 0xf);
         }
 
         return ret;
     }
 
     /**
+     * Encodes a string to be formatted like the EF[ADN] alpha identifier.
+     *
+     * <p>See javadoc for {@link #adnStringFieldToString(byte[], int, int)} for more details on
+     * the relevant specs.
+     *
+     * <p>This will attempt to encode using the GSM 7-bit alphabet but will fallback to UCS-2 if
+     * there are characters that are not supported by it.
+     *
+     * @return the encoded string including the prefix byte necessary to identify the encoding.
+     * @see #adnStringFieldToString(byte[], int, int)
+     */
+    @NonNull
+    public static byte[] stringToAdnStringField(@NonNull String alphaTag) {
+        int septets = GsmAlphabet.countGsmSeptetsUsingTables(alphaTag, false, 0, 0);
+        if (septets != -1) {
+            byte[] ret = new byte[septets];
+            GsmAlphabet.stringToGsm8BitUnpackedField(alphaTag, ret, 0, ret.length);
+            return ret;
+        }
+
+        // Strictly speaking UCS-2 disallows surrogate characters but it's much more complicated to
+        // validate that the string contains only valid UCS-2 characters. Since the read path
+        // in most modern software will decode "UCS-2" by treating it as UTF-16 this should be fine
+        // (e.g. the adnStringFieldToString has done this for a long time on Android). Also there's
+        // already a precedent in SMS applications to ignore the UCS-2/UTF-16 distinction.
+        byte[] alphaTagBytes = alphaTag.getBytes(StandardCharsets.UTF_16BE);
+        byte[] ret = new byte[alphaTagBytes.length + 1];
+        // 0x80 tags the remaining bytes as UCS-2
+        ret[0] = (byte) 0x80;
+        System.arraycopy(alphaTagBytes, 0, ret, 1, alphaTagBytes.length);
+
+        return ret;
+    }
+
+    /**
      * Decodes a string field that's formatted like the EF[ADN] alpha
      * identifier
      *
@@ -309,7 +346,7 @@
                     ret = new String(data, offset + 1, ucslen * 2, "utf-16be");
                 } catch (UnsupportedEncodingException ex) {
                     Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException",
-                          ex);
+                            ex);
                 }
 
                 if (ret != null) {
@@ -342,7 +379,7 @@
                 len = length - 4;
 
             base = (char) (((data[offset + 2] & 0xFF) << 8) |
-                            (data[offset + 3] & 0xFF));
+                    (data[offset + 3] & 0xFF));
             offset += 4;
             isucs2 = true;
         }
@@ -366,7 +403,7 @@
                     count++;
 
                 ret.append(GsmAlphabet.gsm8BitUnpackedToString(data,
-                           offset, count));
+                        offset, count));
 
                 offset += count;
                 len -= count;
diff --git a/test-base/Android.bp b/test-base/Android.bp
index c7c9fc7..9bd639b 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -19,6 +19,16 @@
 // This contains the junit.framework and android.test classes that were in
 // Android API level 25 excluding those from android.test.runner.
 // Also contains the com.android.internal.util.Predicate[s] classes.
+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
+    //   SPDX-license-identifier-CPL-1.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_sdk_library {
     name: "android.test.base",
 
@@ -39,6 +49,12 @@
 
     compile_dex: true,
     default_to_stubs: true,
+
+    // Additional hiddenapi annotations are provided in a separate module.
+    // TODO(b/180295980) - investigate whether this can be removed
+    hiddenapi_additional_annotations: [
+        "android.test.base-hiddenapi-annotations",
+    ],
 }
 
 // Build the android.test.base_static library
@@ -81,8 +97,9 @@
 // ===============================================
 // This contains the android.test classes from android.test.base plus
 // the com.android.internal.util.Predicate[s] classes. This is only
-// intended for inclusion in android.test.legacy and must not be used
-// elsewhere.
+// intended for inclusion in android.test.legacy and in
+// android.test.base-hiddenapi-annotations to avoid a dependency cycle and must
+// not be used elsewhere.
 java_library_static {
     name: "android.test.base-minus-junit",
 
diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp
index c202467..1466590 100644
--- a/test-base/hiddenapi/Android.bp
+++ b/test-base/hiddenapi/Android.bp
@@ -14,19 +14,29 @@
 // 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"],
+}
+
 // Provided solely to contribute information about which hidden parts of the android.test.base
 // library are used by apps. The source files are stubs of the actual files in ../src which use the
 // UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi.
-// Relies on the convention that modules with name <x>-hiddenapi provide hiddenapi information for
-// module <x> that is on the bootclasspath.
 java_library {
-    name: "android.test.base-hiddenapi",
+    name: "android.test.base-hiddenapi-annotations",
     compile_dex: true,
 
     srcs: ["src/**/*.java"],
 
     libs: [
-        "android.test.base",
+        // Use this instead of `android.test.base` to avoid a dependency cycle
+        // as `android.test.base` depends on this.
+        "android.test.base-minus-junit",
+        "junit",
         "unsupportedappusage",
     ],
 }
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index af26c5b..ce5e4cf 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -27,6 +27,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := android.test.legacy
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
 
 LOCAL_SDK_VERSION := current
 
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 7d0f92f..a2447d7 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -16,6 +16,15 @@
 
 // Build the android.test.mock library
 // ===================================
+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_sdk_library {
     name: "android.test.mock",
 
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 1f6db84..fe007e39 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -16,6 +16,16 @@
 
 // Build the android.test.runner library
 // =====================================
+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
+    //   SPDX-license-identifier-CPL-1.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_sdk_library {
     name: "android.test.runner",
 
diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp
index d74cee4..ac21bcb 100644
--- a/test-runner/tests/Android.bp
+++ b/test-runner/tests/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: "FrameworkTestRunnerTests",
 
diff --git a/tests/AccessibilityEventsLogger/Android.bp b/tests/AccessibilityEventsLogger/Android.bp
index ead1656..c403f9b 100644
--- a/tests/AccessibilityEventsLogger/Android.bp
+++ b/tests/AccessibilityEventsLogger/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: "AccessibilityEventsLogger",
     srcs: ["**/*.java"],
diff --git a/tests/AccessoryDisplay/common/Android.bp b/tests/AccessoryDisplay/common/Android.bp
index 3ce4c57..fd3af1e 100644
--- a/tests/AccessoryDisplay/common/Android.bp
+++ b/tests/AccessoryDisplay/common/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Build the application.
+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_static {
     name: "AccessoryDisplayCommon",
     sdk_version: "current",
diff --git a/tests/AccessoryDisplay/sink/Android.bp b/tests/AccessoryDisplay/sink/Android.bp
index 4e50a81..d825c60 100644
--- a/tests/AccessoryDisplay/sink/Android.bp
+++ b/tests/AccessoryDisplay/sink/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Build the application.
+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: "AccessoryDisplaySink",
     sdk_version: "current",
diff --git a/tests/AccessoryDisplay/source/Android.bp b/tests/AccessoryDisplay/source/Android.bp
index 6d8087f..6ed752e 100644
--- a/tests/AccessoryDisplay/source/Android.bp
+++ b/tests/AccessoryDisplay/source/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Build the application.
+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: "AccessoryDisplaySource",
     sdk_version: "current",
diff --git a/tests/ActivityManagerPerfTests/stub-app/Android.bp b/tests/ActivityManagerPerfTests/stub-app/Android.bp
index a3c1f5b..19225e4 100644
--- a/tests/ActivityManagerPerfTests/stub-app/Android.bp
+++ b/tests/ActivityManagerPerfTests/stub-app/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: "ActivityManagerPerfTestsStubApp1",
     static_libs: ["ActivityManagerPerfTestsUtils"],
@@ -65,4 +74,3 @@
         "--auto-add-overlay",
     ],
 }
-
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.bp b/tests/ActivityManagerPerfTests/test-app/Android.bp
index ef9d587..5fd1d5a 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.bp
+++ b/tests/ActivityManagerPerfTests/test-app/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: "ActivityManagerPerfTestsTestApp",
     srcs: ["src/**/*.java"],
diff --git a/tests/ActivityManagerPerfTests/tests/Android.bp b/tests/ActivityManagerPerfTests/tests/Android.bp
index 2ae2cc4..c8dbf81 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.bp
+++ b/tests/ActivityManagerPerfTests/tests/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: "ActivityManagerPerfTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/ActivityManagerPerfTests/utils/Android.bp b/tests/ActivityManagerPerfTests/utils/Android.bp
index 766c3ac..99c43c8 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.bp
+++ b/tests/ActivityManagerPerfTests/utils/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"],
+}
+
 java_test {
     name: "ActivityManagerPerfTestsUtils",
     sdk_version: "current",
diff --git a/tests/ActivityTests/Android.bp b/tests/ActivityTests/Android.bp
index 0182862..be6096f 100644
--- a/tests/ActivityTests/Android.bp
+++ b/tests/ActivityTests/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: "ActivityTest",
     srcs: ["**/*.java"],
diff --git a/tests/ActivityViewTest/Android.bp b/tests/ActivityViewTest/Android.bp
index e7b8c8e..95178a0 100644
--- a/tests/ActivityViewTest/Android.bp
+++ b/tests/ActivityViewTest/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: "ActivityViewTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/AmSlam/Android.bp b/tests/AmSlam/Android.bp
index a8e575a..cc33d88 100644
--- a/tests/AmSlam/Android.bp
+++ b/tests/AmSlam/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AmSlam",
     srcs: ["**/*.java"],
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 02c75ed..0cdb11fe 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/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"],
+}
+
 java_test_host {
     name: "ApkVerityTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp b/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
index 69632b2..adf8f9f 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
+++ b/tests/ApkVerityTest/ApkVerityTestApp/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: "ApkVerityTestApp",
   manifest: "AndroidManifest.xml",
diff --git a/tests/ApkVerityTest/OWNERS b/tests/ApkVerityTest/OWNERS
new file mode 100644
index 0000000..d67285ed
--- /dev/null
+++ b/tests/ApkVerityTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+victorhsieh@google.com
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index 37fbc29..b5a46da 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -14,6 +14,15 @@
 
 // This is a cc_test just because it supports test_suites. This should be converted to something
 // like cc_binary_test_helper once supported, thus auto_gen_config:false below.
+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_test {
     // Depending on how the test runs, the executable may be uploaded to different location.
     // Before the bug in the file pusher is fixed, workaround by making the name unique.
diff --git a/tests/ApkVerityTest/testdata/Android.bp b/tests/ApkVerityTest/testdata/Android.bp
index c10b0ce..ccfc4c9 100644
--- a/tests/ApkVerityTest/testdata/Android.bp
+++ b/tests/ApkVerityTest/testdata/Android.bp
@@ -12,6 +12,17 @@
 // 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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "ApkVerityTestKeyPem",
     srcs: ["ApkVerityTestKey.pem"],
@@ -74,4 +85,3 @@
     srcs: [":ApkVerityTestAppSplitDm"],
     out: ["ApkVerityTestAppSplit.dm.fsv_sig"],
 }
-
diff --git a/tests/AppLaunch/Android.bp b/tests/AppLaunch/Android.bp
index 75db551..f838c5a 100644
--- a/tests/AppLaunch/Android.bp
+++ b/tests/AppLaunch/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: "AppLaunch",
     // Only compile source java files in this apk.
diff --git a/tests/AppLaunchWear/Android.bp b/tests/AppLaunchWear/Android.bp
index 8d34b6e..e2fc473 100644
--- a/tests/AppLaunchWear/Android.bp
+++ b/tests/AppLaunchWear/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: "AppLaunchWear",
     // Only compile source java files in this apk.
diff --git a/tests/AppResourcesLoaders/Android.bp b/tests/AppResourcesLoaders/Android.bp
index e5739db..d882db8 100644
--- a/tests/AppResourcesLoaders/Android.bp
+++ b/tests/AppResourcesLoaders/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AppResourcesLoaders",
     srcs: ["**/*.java"],
diff --git a/tests/AppResourcesLoaders/Overlay/Android.bp b/tests/AppResourcesLoaders/Overlay/Android.bp
index 80443f6..b063023 100644
--- a/tests/AppResourcesLoaders/Overlay/Android.bp
+++ b/tests/AppResourcesLoaders/Overlay/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AppResourcesLoaders_Overlay",
 }
diff --git a/tests/Assist/Android.bp b/tests/Assist/Android.bp
index 216e751..033c140 100644
--- a/tests/Assist/Android.bp
+++ b/tests/Assist/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: "Assist",
     srcs: ["**/*.java"],
diff --git a/tests/AutoVerify/app1/Android.bp b/tests/AutoVerify/app1/Android.bp
index 548519f..0e26067 100644
--- a/tests/AutoVerify/app1/Android.bp
+++ b/tests/AutoVerify/app1/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_app {
     name: "AutoVerifyTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/AutoVerify/app2/Android.bp b/tests/AutoVerify/app2/Android.bp
index 1c6c97b..5fcff1a 100644
--- a/tests/AutoVerify/app2/Android.bp
+++ b/tests/AutoVerify/app2/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_app {
     name: "AutoVerifyTest2",
     srcs: ["src/**/*.java"],
diff --git a/tests/AutoVerify/app3/Android.bp b/tests/AutoVerify/app3/Android.bp
index 70a2b77..479f355 100644
--- a/tests/AutoVerify/app3/Android.bp
+++ b/tests/AutoVerify/app3/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_app {
     name: "AutoVerifyTest3",
     srcs: ["src/**/*.java"],
diff --git a/tests/AutoVerify/app4/Android.bp b/tests/AutoVerify/app4/Android.bp
index fbdae11..dcf8902 100644
--- a/tests/AutoVerify/app4/Android.bp
+++ b/tests/AutoVerify/app4/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_app {
     name: "AutoVerifyTest4",
     srcs: ["src/**/*.java"],
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
index a85d129..0a45d53 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "BackgroundDexOptServiceIntegrationTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/BandwidthTests/Android.bp b/tests/BandwidthTests/Android.bp
index 523f522..a7fc89d 100644
--- a/tests/BandwidthTests/Android.bp
+++ b/tests/BandwidthTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "BandwidthEnforcementTest",
     platform_apis: true,
diff --git a/tests/BatteryWaster/Android.bp b/tests/BatteryWaster/Android.bp
index 4698910..1fa4f82 100644
--- a/tests/BatteryWaster/Android.bp
+++ b/tests/BatteryWaster/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: "BatteryWaster",
     srcs: ["**/*.java"],
diff --git a/tests/BiDiTests/Android.bp b/tests/BiDiTests/Android.bp
index c659e8c..79ae41f 100644
--- a/tests/BiDiTests/Android.bp
+++ b/tests/BiDiTests/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: "BiDiTests",
     // Only compile source java files in this apk.
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
index 53d3638..c4faf7f 100644
--- a/tests/BlobStoreTestUtils/Android.bp
+++ b/tests/BlobStoreTestUtils/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"],
+}
+
 java_library {
   name: "BlobStoreTestUtils",
   srcs: ["src/**/*.java"],
@@ -21,4 +30,4 @@
     "androidx.test.ext.junit",
   ],
   sdk_version: "test_current",
-}
\ No newline at end of file
+}
diff --git a/tests/BootImageProfileTest/Android.bp b/tests/BootImageProfileTest/Android.bp
index 1b097a8..9fb5aa2 100644
--- a/tests/BootImageProfileTest/Android.bp
+++ b/tests/BootImageProfileTest/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"],
+}
+
 java_test_host {
     name: "BootImageProfileTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/BrowserPowerTest/Android.bp b/tests/BrowserPowerTest/Android.bp
index 1d358cb..a8a9897 100644
--- a/tests/BrowserPowerTest/Android.bp
+++ b/tests/BrowserPowerTest/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: "BrowserPowerTests",
     libs: [
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
index 125deb5..b889b0d 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 cc_test_library {
     name: "libsmartcamera_jni",
     sdk_version: "14",
diff --git a/tests/CameraPrewarmTest/Android.bp b/tests/CameraPrewarmTest/Android.bp
index eaf453b..07c4923 100644
--- a/tests/CameraPrewarmTest/Android.bp
+++ b/tests/CameraPrewarmTest/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: "CameraPrewarmTest",
     srcs: ["**/*.java"],
diff --git a/tests/Codegen/Android.bp b/tests/Codegen/Android.bp
index 966c560..ddbf168 100644
--- a/tests/Codegen/Android.bp
+++ b/tests/Codegen/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: "CodegenTests",
     srcs: [
diff --git a/tests/Compatibility/Android.bp b/tests/Compatibility/Android.bp
index c14e705..c58c99e 100644
--- a/tests/Compatibility/Android.bp
+++ b/tests/Compatibility/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: "AppCompatibilityTest",
     static_libs: ["androidx.test.rules"],
diff --git a/tests/CoreTests/android/Android.bp b/tests/CoreTests/android/Android.bp
index 24134e8..e2f194b 100644
--- a/tests/CoreTests/android/Android.bp
+++ b/tests/CoreTests/android/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: "LegacyCoreTests",
     srcs: ["**/*.java"],
diff --git a/tests/DataIdleTest/Android.bp b/tests/DataIdleTest/Android.bp
index 19656ce..f9509cc 100644
--- a/tests/DataIdleTest/Android.bp
+++ b/tests/DataIdleTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "DataIdleTest",
     platform_apis: true,
diff --git a/tests/DozeTest/Android.bp b/tests/DozeTest/Android.bp
index f1be029..36ea91a 100644
--- a/tests/DozeTest/Android.bp
+++ b/tests/DozeTest/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_app {
     name: "DozeTest",
     // Only compile source java files in this apk.
diff --git a/tests/DpiTest/Android.bp b/tests/DpiTest/Android.bp
index 7d6a78b..52bb08b 100644
--- a/tests/DpiTest/Android.bp
+++ b/tests/DpiTest/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: "DensityTest",
     srcs: ["**/*.java"],
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
index 2d58ce8..bfb5b07 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -22,6 +22,9 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := DynamicCodeLoggerTestLibrary
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
 
 include $(BUILD_JAVA_LIBRARY)
@@ -35,6 +38,9 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
 LOCAL_HEADER_LIBRARIES := jni_headers
 LOCAL_SDK_VERSION := 28
@@ -48,6 +54,9 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := DynamicCodeLoggerNativeExecutable
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_SRC_FILES := src/cpp/test_executable.cpp
 
 include $(BUILD_EXECUTABLE)
diff --git a/tests/FeatureSplit/base/Android.bp b/tests/FeatureSplit/base/Android.bp
index ab25464..89c26d2 100644
--- a/tests/FeatureSplit/base/Android.bp
+++ b/tests/FeatureSplit/base/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FeatureSplitBase",
     srcs: ["**/*.java"],
diff --git a/tests/FeatureSplit/feature1/Android.bp b/tests/FeatureSplit/feature1/Android.bp
index 706a4f5..2f8aa8b 100644
--- a/tests/FeatureSplit/feature1/Android.bp
+++ b/tests/FeatureSplit/feature1/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FeatureSplit1",
     srcs: ["**/*.java"],
diff --git a/tests/FeatureSplit/feature2/Android.bp b/tests/FeatureSplit/feature2/Android.bp
index a363482..2a5c432 100644
--- a/tests/FeatureSplit/feature2/Android.bp
+++ b/tests/FeatureSplit/feature2/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FeatureSplit2",
     srcs: ["**/*.java"],
diff --git a/tests/FixVibrateSetting/Android.bp b/tests/FixVibrateSetting/Android.bp
index 5608a2b..bd7c701 100644
--- a/tests/FixVibrateSetting/Android.bp
+++ b/tests/FixVibrateSetting/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_app {
     name: "FixVibrateSetting",
     srcs: ["**/*.java"],
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 05f0a8e7..4f463f9 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FlickerTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS
index f35a318..b556101 100644
--- a/tests/FlickerTests/OWNERS
+++ b/tests/FlickerTests/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 909476
 include /services/core/java/com/android/server/wm/OWNERS
 natanieljr@google.com
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 0bea209..1d5f732 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/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: "FlickerTestApp",
     srcs: ["**/*.java"],
diff --git a/tests/FrameworkPerf/Android.bp b/tests/FrameworkPerf/Android.bp
index a259ebd..9be3ab7 100644
--- a/tests/FrameworkPerf/Android.bp
+++ b/tests/FrameworkPerf/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: "FrameworkPerf",
     srcs: ["**/*.java"],
diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp
index 648fd81..07d0f42 100644
--- a/tests/GamePerformance/Android.bp
+++ b/tests/GamePerformance/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: "GamePerformance",
     // Don't include this package in any target
diff --git a/tests/GridLayoutTest/Android.bp b/tests/GridLayoutTest/Android.bp
index b4b5ba5..71d884c 100644
--- a/tests/GridLayoutTest/Android.bp
+++ b/tests/GridLayoutTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "GridLayoutTest",
     srcs: ["**/*.java"],
diff --git a/tests/HierarchyViewerTest/Android.bp b/tests/HierarchyViewerTest/Android.bp
index 814c883..9c5d1c0 100644
--- a/tests/HierarchyViewerTest/Android.bp
+++ b/tests/HierarchyViewerTest/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: "HierarchyViewerTest",
     srcs: ["**/*.java"],
diff --git a/tests/HugeBackup/Android.bp b/tests/HugeBackup/Android.bp
index b44c457..7d4e52a 100644
--- a/tests/HugeBackup/Android.bp
+++ b/tests/HugeBackup/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: "HugeBackup",
     // Only compile source java files in this apk.
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp
index 37d3f5d..7606322 100644
--- a/tests/HwAccelerationTest/Android.bp
+++ b/tests/HwAccelerationTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "HwAccelerationTest",
     srcs: ["**/*.java"],
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index e233fed..8546ec2 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/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: "InternalTests",
     proto: {
diff --git a/tests/JankBench/Android.bp b/tests/JankBench/Android.bp
index 166639d..39dd197 100644
--- a/tests/JankBench/Android.bp
+++ b/tests/JankBench/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: "JankBench",
     manifest: "app/src/main/AndroidManifest.xml",
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
index 2ae8c33..eb9b2f6 100644
--- a/tests/JobSchedulerPerfTests/Android.bp
+++ b/tests/JobSchedulerPerfTests/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: "JobSchedulerPerfTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/JobSchedulerTestApp/Android.bp b/tests/JobSchedulerTestApp/Android.bp
index bac0220..893a983 100644
--- a/tests/JobSchedulerTestApp/Android.bp
+++ b/tests/JobSchedulerTestApp/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_app {
     name: "JobSchedulerTestApp",
     srcs: ["src/**/*.java"],
diff --git a/tests/LargeAssetTest/Android.bp b/tests/LargeAssetTest/Android.bp
index 499e6a0..2a6de77 100644
--- a/tests/LargeAssetTest/Android.bp
+++ b/tests/LargeAssetTest/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_app {
     name: "LargeAssetTest",
     srcs: ["**/*.java"],
diff --git a/tests/LegacyAssistant/Android.bp b/tests/LegacyAssistant/Android.bp
index fef924d..ab8ef88 100644
--- a/tests/LegacyAssistant/Android.bp
+++ b/tests/LegacyAssistant/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: "LegacyAssistant",
     srcs: ["**/*.java"],
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
index c4bfcb1..4e0b0a8 100644
--- a/tests/LocalizationTest/Android.bp
+++ b/tests/LocalizationTest/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: "LocalizationTest",
     srcs: ["java/**/*.kt"],
diff --git a/tests/LocationTracker/Android.bp b/tests/LocationTracker/Android.bp
index f0075a9..538687c 100644
--- a/tests/LocationTracker/Android.bp
+++ b/tests/LocationTracker/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: "LocationTracker",
     srcs: ["**/*.java"],
diff --git a/tests/LotsOfApps/Android.bp b/tests/LotsOfApps/Android.bp
index 68b9f88..5f6c089 100644
--- a/tests/LotsOfApps/Android.bp
+++ b/tests/LotsOfApps/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_app {
     name: "LotsOfApps",
     srcs: ["**/*.java"],
diff --git a/tests/LowStorageTest/Android.bp b/tests/LowStorageTest/Android.bp
index e72e4a5..6dcf39d 100644
--- a/tests/LowStorageTest/Android.bp
+++ b/tests/LowStorageTest/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: "lowstoragetest",
     certificate: "platform",
diff --git a/tests/ManagedProfileLifecycleStressTest/Android.bp b/tests/ManagedProfileLifecycleStressTest/Android.bp
index 639ce3c..3ef6322 100644
--- a/tests/ManagedProfileLifecycleStressTest/Android.bp
+++ b/tests/ManagedProfileLifecycleStressTest/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"],
+}
+
 java_test_host {
     name: "ManagedProfileLifecycleStressTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
index 1f47b03..7a9b6cf 100644
--- a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/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: "DummyDPC",
     defaults: ["cts_defaults"],
diff --git a/tests/MemoryUsage/Android.bp b/tests/MemoryUsage/Android.bp
index aeb5338..e30a0a7 100644
--- a/tests/MemoryUsage/Android.bp
+++ b/tests/MemoryUsage/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: "MemoryUsage",
     // Only compile source java files in this apk.
diff --git a/tests/MirrorSurfaceTest/Android.bp b/tests/MirrorSurfaceTest/Android.bp
index e359c64..1368f26 100644
--- a/tests/MirrorSurfaceTest/Android.bp
+++ b/tests/MirrorSurfaceTest/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: "MirrorSurfaceTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/NativeProcessesMemoryTest/Android.bp b/tests/NativeProcessesMemoryTest/Android.bp
index f2625bf..b7160e9 100644
--- a/tests/NativeProcessesMemoryTest/Android.bp
+++ b/tests/NativeProcessesMemoryTest/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"],
+}
+
 java_test_host {
     name: "native-processes-memory-test",
     srcs: ["src/**/*.java"],
diff --git a/tests/NetworkSecurityConfigTest/Android.bp b/tests/NetworkSecurityConfigTest/Android.bp
index cf8ca57..473eadb 100644
--- a/tests/NetworkSecurityConfigTest/Android.bp
+++ b/tests/NetworkSecurityConfigTest/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: "NetworkSecurityConfigTests",
     certificate: "platform",
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
index 99248bf..a5720db 100644
--- a/tests/NullHomeTest/Android.bp
+++ b/tests/NullHomeTest/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: "NullHomeTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/OdmApps/Android.bp b/tests/OdmApps/Android.bp
index d86f9cc..de86498 100644
--- a/tests/OdmApps/Android.bp
+++ b/tests/OdmApps/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"],
+}
+
 java_test_host {
     name: "OdmAppsTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/OdmApps/app/Android.bp b/tests/OdmApps/app/Android.bp
index 5eb8590..a33a1cf 100644
--- a/tests/OdmApps/app/Android.bp
+++ b/tests/OdmApps/app/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: "TestOdmApp",
     test_suites: ["device-tests"],
diff --git a/tests/OdmApps/priv-app/Android.bp b/tests/OdmApps/priv-app/Android.bp
index 9dd477cf..7527729 100644
--- a/tests/OdmApps/priv-app/Android.bp
+++ b/tests/OdmApps/priv-app/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: "TestOdmPrivApp",
     test_suites: ["device-tests"],
diff --git a/tests/OneMedia/Android.bp b/tests/OneMedia/Android.bp
index 11e12f35..5c73177 100644
--- a/tests/OneMedia/Android.bp
+++ b/tests/OneMedia/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_app {
     name: "OneMedia",
     srcs: [
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 0b75039..1e1dc84 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // PackageWatchdogTest
+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: "PackageWatchdogTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 7d918cc..f0f9c4b 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -14,6 +14,15 @@
 // 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: "PlatformCompatGating",
     // Only compile source java files in this apk.
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index eb04f69..ac9e681 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -76,11 +76,11 @@
                 Params(enableDisable = null, targetSdk = 29, result = false),
                 Params(enableDisable = null, targetSdk = 30, result = true),
 
-                Params(enableDisable = true, targetSdk = 29, result = true),
+                Params(enableDisable = true, targetSdk = 29, result = false),
                 Params(enableDisable = true, targetSdk = 30, result = true),
 
                 Params(enableDisable = false, targetSdk = 29, result = false),
-                Params(enableDisable = false, targetSdk = 30, result = false)
+                Params(enableDisable = false, targetSdk = 30, result = true)
         )
     }
 
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
index 10fa2dc..5f91f9d0 100644
--- a/tests/PlatformCompatGating/test-rules/Android.bp
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_library {
     name: "platform-compat-test-rules",
     srcs: ["src/**/*.java"],
@@ -23,4 +32,4 @@
         "truth-prebuilt",
         "core-compat-test-rules"
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/ProtoInputStreamTests/Android.bp b/tests/ProtoInputStreamTests/Android.bp
index ecc40566..0029080 100644
--- a/tests/ProtoInputStreamTests/Android.bp
+++ b/tests/ProtoInputStreamTests/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: "ProtoInputStreamTests",
     proto: {
diff --git a/tests/RemoteDisplayProvider/Android.bp b/tests/RemoteDisplayProvider/Android.bp
index 6c7798f..55732d1 100644
--- a/tests/RemoteDisplayProvider/Android.bp
+++ b/tests/RemoteDisplayProvider/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Build the application.
+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: "RemoteDisplayProviderTest",
     sdk_version: "system_current",
diff --git a/tests/RenderThreadTest/Android.bp b/tests/RenderThreadTest/Android.bp
index 1659776..b18b04e 100644
--- a/tests/RenderThreadTest/Android.bp
+++ b/tests/RenderThreadTest/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: "RenderThreadTest",
     // Only compile source java files in this apk.
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 4f5a305..f7dda57 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/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: "RollbackTest",
     manifest: "RollbackTest/AndroidManifest.xml",
@@ -95,6 +104,7 @@
   key: "com.android.apex.apkrollback.test.key",
   apps: ["TestAppAv1"],
   installable: false,
+  updatable: false,
 }
 
 apex {
@@ -105,6 +115,7 @@
   key: "com.android.apex.apkrollback.test.key",
   apps: ["TestAppAv2"],
   installable: false,
+  updatable: false,
 }
 
 apex {
@@ -115,4 +126,5 @@
   key: "com.android.apex.apkrollback.test.key",
   apps: ["TestAppACrashingV2"],
   installable: false,
-}
\ No newline at end of file
+  updatable: false,
+}
diff --git a/tests/SerialChat/Android.bp b/tests/SerialChat/Android.bp
index 3c18035..8719e010 100644
--- a/tests/SerialChat/Android.bp
+++ b/tests/SerialChat/Android.bp
@@ -14,6 +14,15 @@
 // 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: "SerialChat",
     srcs: ["**/*.java"],
diff --git a/tests/ServiceCrashTest/Android.bp b/tests/ServiceCrashTest/Android.bp
index 40a377d..fb98b763 100644
--- a/tests/ServiceCrashTest/Android.bp
+++ b/tests/ServiceCrashTest/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: "ServiceCrashTest",
     // Only compile source java files in this apk.
diff --git a/tests/SharedLibrary/client/Android.bp b/tests/SharedLibrary/client/Android.bp
index dbf6dc9..6eab7c2 100644
--- a/tests/SharedLibrary/client/Android.bp
+++ b/tests/SharedLibrary/client/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: "SharedLibraryClient",
     srcs: ["**/*.java"],
diff --git a/tests/SharedLibrary/lib/Android.bp b/tests/SharedLibrary/lib/Android.bp
index f69d388..0595cb1 100644
--- a/tests/SharedLibrary/lib/Android.bp
+++ b/tests/SharedLibrary/lib/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_app {
     name: "SharedLibrary",
     srcs: ["**/*.java"],
diff --git a/tests/ShowWhenLockedApp/Android.bp b/tests/ShowWhenLockedApp/Android.bp
index dba564c..f24834a 100644
--- a/tests/ShowWhenLockedApp/Android.bp
+++ b/tests/ShowWhenLockedApp/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: "ShowWhenLocked",
     srcs: ["**/*.java"],
diff --git a/tests/SmokeTest/Android.bp b/tests/SmokeTest/Android.bp
index bc45ee6..4c853e3 100644
--- a/tests/SmokeTest/Android.bp
+++ b/tests/SmokeTest/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: "SmokeTestApp",
     // This builds "SmokeTestApp"
diff --git a/tests/SmokeTest/tests/Android.bp b/tests/SmokeTest/tests/Android.bp
index ceb2d19..5542dd0 100644
--- a/tests/SmokeTest/tests/Android.bp
+++ b/tests/SmokeTest/tests/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: "SmokeTest",
     // Include all test java files.
diff --git a/tests/SmokeTestApps/Android.bp b/tests/SmokeTestApps/Android.bp
index 0feb0004..3505fe1 100644
--- a/tests/SmokeTestApps/Android.bp
+++ b/tests/SmokeTestApps/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: "SmokeTestTriggerApps",
     srcs: ["src/**/*.java"],
diff --git a/tests/SoundTriggerTestApp/Android.bp b/tests/SoundTriggerTestApp/Android.bp
index d3a1300..09f1e10 100644
--- a/tests/SoundTriggerTestApp/Android.bp
+++ b/tests/SoundTriggerTestApp/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_app {
     name: "SoundTriggerTestApp",
     srcs: ["**/*.java"],
diff --git a/tests/Split/Android.bp b/tests/Split/Android.bp
index d8c89ba..727b202 100644
--- a/tests/Split/Android.bp
+++ b/tests/Split/Android.bp
@@ -14,6 +14,15 @@
 // 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: "Split",
     srcs: ["**/*.java"],
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 45c1c73..243c301 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/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: "StagedInstallInternalTestApp",
     manifest: "app/AndroidManifest.xml",
@@ -37,4 +46,3 @@
     test_suites: ["general-tests"],
     test_config: "StagedInstallInternalTest.xml",
 }
-
diff --git a/tests/StagedInstallTest/StagedInstallInternalTest.xml b/tests/StagedInstallTest/StagedInstallInternalTest.xml
index 1b8fa67..1f22cae 100644
--- a/tests/StagedInstallTest/StagedInstallInternalTest.xml
+++ b/tests/StagedInstallTest/StagedInstallInternalTest.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License.
   -->
 <configuration description="Runs the internal staged install tests">
-    <option name="test-suite-tag" value="StagedInstallTest" />
+    <option name="test-suite-tag" value="StagedInstallInternalTest" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="StagedInstallInternalTestApp.apk" />
diff --git a/tests/StagedInstallTest/TEST_MAPPING b/tests/StagedInstallTest/TEST_MAPPING
index 5a7a5a7..73094c5 100644
--- a/tests/StagedInstallTest/TEST_MAPPING
+++ b/tests/StagedInstallTest/TEST_MAPPING
@@ -1,6 +1,16 @@
 {
   "presubmit": [
     {
+      "name": "StagedInstallInternalTest",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
       "name": "StagedInstallInternalTest"
     }
   ]
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 02597d5..e673549 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -96,6 +96,19 @@
         assertSessionReady(sessionId);
     }
 
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
+        InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
+                Install.single(TestApp.AIncompleteSplit).setStaged());
+    }
+
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage()
+            throws Exception {
+        InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
+                Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged());
+    }
+
     private static void assertSessionReady(int sessionId) {
         assertSessionState(sessionId,
                 (session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index b7c9e59..1b5e6dd 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.cts.install.lib.host.InstallUtilsHost;
+import android.platform.test.annotations.LargeTest;
 
 import com.android.ddmlib.Log;
 import com.android.tests.rollback.host.AbandonSessionsRule;
@@ -141,6 +142,7 @@
 
     // Test rollback-app command waits for staged sessions to be ready
     @Test
+    @LargeTest
     public void testAdbRollbackAppWaitsForStagedReady() throws Exception {
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
diff --git a/tests/StatusBar/Android.bp b/tests/StatusBar/Android.bp
index 0b650ed..2fad051 100644
--- a/tests/StatusBar/Android.bp
+++ b/tests/StatusBar/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: "StatusBarTest",
     srcs: ["**/*.java"],
diff --git a/tests/SurfaceComposition/Android.bp b/tests/SurfaceComposition/Android.bp
index 53e4d52..f5aba8f5 100644
--- a/tests/SurfaceComposition/Android.bp
+++ b/tests/SurfaceComposition/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: "SurfaceComposition",
     // Don't include this package in any target
diff --git a/tests/SurfaceControlViewHostTest/Android.bp b/tests/SurfaceControlViewHostTest/Android.bp
index e4e0600..0127ba5 100644
--- a/tests/SurfaceControlViewHostTest/Android.bp
+++ b/tests/SurfaceControlViewHostTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "SurfaceControlViewHostTest",
     srcs: ["**/*.java"],
diff --git a/tests/SystemMemoryTest/device/Android.bp b/tests/SystemMemoryTest/device/Android.bp
index 2bf0fec..d7cec1a 100644
--- a/tests/SystemMemoryTest/device/Android.bp
+++ b/tests/SystemMemoryTest/device/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: "SystemMemoryTestDevice",
     sdk_version: "current",
diff --git a/tests/SystemMemoryTest/host/Android.bp b/tests/SystemMemoryTest/host/Android.bp
index 3bb5489..7974462 100644
--- a/tests/SystemMemoryTest/host/Android.bp
+++ b/tests/SystemMemoryTest/host/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"],
+}
+
 java_test_host {
     name: "system-memory-test",
     srcs: ["src/**/*.java"],
diff --git a/tests/SystemUIDemoModeController/Android.bp b/tests/SystemUIDemoModeController/Android.bp
index 1e4c437..d952cf6 100644
--- a/tests/SystemUIDemoModeController/Android.bp
+++ b/tests/SystemUIDemoModeController/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: "DemoModeController",
     srcs: ["**/*.java"],
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index 8a13dbc..56d5695 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "TaskOrganizerTest",
     srcs: ["**/*.java"],
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index 4f7569d..a9fbfd9 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "TelephonyCommonTests",
     srcs: [
diff --git a/tests/TouchLatency/Android.bp b/tests/TouchLatency/Android.bp
index 1174bcb0..3a9e240 100644
--- a/tests/TouchLatency/Android.bp
+++ b/tests/TouchLatency/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: "TouchLatency",
     manifest: "app/src/main/AndroidManifest.xml",
diff --git a/tests/TransformTest/Android.bp b/tests/TransformTest/Android.bp
index fd7aaeb..f58fe8f 100644
--- a/tests/TransformTest/Android.bp
+++ b/tests/TransformTest/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: "TransformTest",
     srcs: ["**/*.java"],
diff --git a/tests/TransitionTests/Android.bp b/tests/TransitionTests/Android.bp
index 57f19e3..4daa5b8 100644
--- a/tests/TransitionTests/Android.bp
+++ b/tests/TransitionTests/Android.bp
@@ -1,3 +1,14 @@
+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
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_app {
     name: "TransitionTests",
     // Only compile source java files in this apk.
diff --git a/tests/TtsTests/Android.bp b/tests/TtsTests/Android.bp
index b137523..b7aa5d4 100644
--- a/tests/TtsTests/Android.bp
+++ b/tests/TtsTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "TtsTests",
     srcs: ["**/*.java"],
diff --git a/tests/UiBench/Android.bp b/tests/UiBench/Android.bp
index e0608e2..0d2f2ef 100644
--- a/tests/UiBench/Android.bp
+++ b/tests/UiBench/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: "UiBench",
     sdk_version: "current",
diff --git a/tests/UpdatableSystemFontTest/OWNERS b/tests/UpdatableSystemFontTest/OWNERS
new file mode 100644
index 0000000..34ac813
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/tests/UsageReportingTest/Android.bp b/tests/UsageReportingTest/Android.bp
index 0bac5a2..dfce070 100644
--- a/tests/UsageReportingTest/Android.bp
+++ b/tests/UsageReportingTest/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: "UsageReportingTest",
     // Only compile source java files in this apk.
diff --git a/tests/UsageStatsPerfTests/Android.bp b/tests/UsageStatsPerfTests/Android.bp
index 3991fb8..0e372a3 100644
--- a/tests/UsageStatsPerfTests/Android.bp
+++ b/tests/UsageStatsPerfTests/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: "UsageStatsPerfTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsageStatsTest/Android.bp b/tests/UsageStatsTest/Android.bp
index 0808b05..afb266b 100644
--- a/tests/UsageStatsTest/Android.bp
+++ b/tests/UsageStatsTest/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: "UsageStatsTest",
     // Only compile source java files in this apk.
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
index c7e9df0..9133bae 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
@@ -16,6 +16,15 @@
 
 //#################################################
 
+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: "AoapTestDeviceApp",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
index 6fa58cb..6893002 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
@@ -16,6 +16,15 @@
 
 //#################################################
 
+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: "AoapTestHostApp",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
index edd4205..2fca4d3 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
@@ -17,6 +17,15 @@
 //#################################################
 
 // TODO: should this be android_helper_test_app?
+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_app {
     name: "UsbHostExternalManagementTestApp",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index a03c6e2..97fbf5b 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "UsbManagerTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp
index 3c5d91b..994484c 100644
--- a/tests/UsbManagerTests/lib/Android.bp
+++ b/tests/UsbManagerTests/lib/Android.bp
@@ -14,6 +14,15 @@
 // 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_library {
     name: "UsbManagerTestLib",
     srcs: ["src/**/*.java"],
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
index 7c2be9b..9328b67 100644
--- a/tests/UsbTests/Android.bp
+++ b/tests/UsbTests/Android.bp
@@ -14,6 +14,15 @@
 // 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: "UsbTests",
     srcs: ["**/*.java"],
diff --git a/tests/UsesFeature2Test/Android.bp b/tests/UsesFeature2Test/Android.bp
index a1b77d0..624e4ec 100644
--- a/tests/UsesFeature2Test/Android.bp
+++ b/tests/UsesFeature2Test/Android.bp
@@ -14,6 +14,15 @@
 // 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: "UsesFeature2Test",
     srcs: ["**/*.java"],
diff --git a/tests/VectorDrawableTest/Android.bp b/tests/VectorDrawableTest/Android.bp
index 13f318e..9da7c5f 100644
--- a/tests/VectorDrawableTest/Android.bp
+++ b/tests/VectorDrawableTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "VectorDrawableTest",
     srcs: ["**/*.java"],
diff --git a/tests/VoiceEnrollment/Android.bp b/tests/VoiceEnrollment/Android.bp
index e43b38c..b5d62bb 100644
--- a/tests/VoiceEnrollment/Android.bp
+++ b/tests/VoiceEnrollment/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_app {
     name: "VoiceEnrollment",
     srcs: ["**/*.java"],
diff --git a/tests/VoiceInteraction/Android.bp b/tests/VoiceInteraction/Android.bp
index 7059473..1aa7faf 100644
--- a/tests/VoiceInteraction/Android.bp
+++ b/tests/VoiceInteraction/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: "VoiceInteraction",
     srcs: ["**/*.java"],
diff --git a/tests/WallpaperTest/Android.bp b/tests/WallpaperTest/Android.bp
index f68b6ec..b009af2 100644
--- a/tests/WallpaperTest/Android.bp
+++ b/tests/WallpaperTest/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_app {
     name: "WallpaperTest",
     srcs: ["src/**/*.java"],
diff --git a/tests/WindowAnimationJank/Android.bp b/tests/WindowAnimationJank/Android.bp
index 50b2297..ed86aa5 100644
--- a/tests/WindowAnimationJank/Android.bp
+++ b/tests/WindowAnimationJank/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: "WindowAnimationJank",
     srcs: ["src/**/*.java"],
diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp
index 7272152..b1f4819 100644
--- a/tests/WindowInsetsTests/Android.bp
+++ b/tests/WindowInsetsTests/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: "WindowInsetsTests",
     srcs: ["src/**/*.java"],
@@ -24,4 +33,3 @@
         "com.google.android.material_material",
     ],
 }
-
diff --git a/tests/appwidgets/AppWidgetHostTest/Android.bp b/tests/appwidgets/AppWidgetHostTest/Android.bp
index 24b7613..a3838e5 100644
--- a/tests/appwidgets/AppWidgetHostTest/Android.bp
+++ b/tests/appwidgets/AppWidgetHostTest/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_app {
     name: "AppWidgetHostTest",
     srcs: ["**/*.java"],
diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.bp b/tests/appwidgets/AppWidgetProviderTest/Android.bp
index a1a5991..a9ee7ad 100644
--- a/tests/appwidgets/AppWidgetProviderTest/Android.bp
+++ b/tests/appwidgets/AppWidgetProviderTest/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_app {
     name: "AppWidgetProvider",
     srcs: ["**/*.java"],
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index e9618300..9b155c9 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -24,6 +24,9 @@
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := backup_helper_test
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 LOCAL_SHARED_LIBRARIES := libandroidfw libutils
 
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index f16ddb9..f87ca2e 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -15,6 +15,15 @@
 // build framework base core benchmarks
 // ============================================================
 
+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: "networkStatsFactory-benchmarks",
     installable: true,
diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp
index 66a1f83..a8ce8a4 100644
--- a/tests/libs-permissions/Android.bp
+++ b/tests/libs-permissions/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: "com.android.test.libs.product",
     installable: true,
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index ffde68e..8122495 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -1,6 +1,15 @@
 //########################################################################
 // Build FrameworksNetTests package
 //########################################################################
+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_defaults {
     name: "FrameworksNetTests-jni-defaults",
     jni_libs: [
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index 009f817..d08b2f8 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -48,6 +48,7 @@
     <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.NETWORK_FACTORY" />
     <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
+    <uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index c271f49..babb81c 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -16,6 +16,15 @@
 
 // Tests in this folder are included both in unit tests and CTS.
 // They must be fast and stable, and exercise public or test APIs.
+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: "FrameworksNetCommonTests",
     srcs: ["java/**/*.java", "java/**/*.kt"],
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index b2bcfeb..ad5bbf2 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -54,12 +54,26 @@
             }
             .build()
 
+    private val dataFromPasspoint = CaptivePortalData.Builder()
+            .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+            .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+            .setCaptive(true)
+            .apply {
+                if (SdkLevel.isAtLeastS()) {
+                    setVenueFriendlyName("venue friendly name")
+                }
+            }
+            .build()
+
     private fun makeBuilder() = CaptivePortalData.Builder(data)
 
     @Test
     fun testParcelUnparcel() {
-        val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
+        val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
         assertParcelSane(data, fieldCount)
+        assertParcelSane(dataFromPasspoint, fieldCount)
 
         assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
         assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
@@ -83,6 +97,27 @@
             assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
             assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
         }
+
+        assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
+        assertNotEqualsAfterChange { it.setUserPortalUrl(
+                Uri.parse("https://tc.example.com/passpoint")) }
+        assertNotEqualsAfterChange { it.setUserPortalUrl(
+                Uri.parse("https://tc.example.com/passpoint"),
+                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+        assertNotEqualsAfterChange { it.setUserPortalUrl(
+                Uri.parse("https://tc.example.com/other"),
+                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+        assertNotEqualsAfterChange { it.setUserPortalUrl(
+                Uri.parse("https://tc.example.com/passpoint"),
+                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+        assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                Uri.parse("https://venue.example.com/passpoint")) }
+        assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                Uri.parse("https://venue.example.com/other"),
+                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+        assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                Uri.parse("https://venue.example.com/passpoint"),
+                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
     }
 
     @Test
@@ -130,6 +165,22 @@
         assertEquals("venue friendly name", data.venueFriendlyName)
     }
 
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    fun testGetVenueInfoUrlSource() {
+        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+                data.venueInfoUrlSource)
+        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
+                dataFromPasspoint.venueInfoUrlSource)
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    fun testGetUserPortalUrlSource() {
+        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+                data.userPortalUrlSource)
+        assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
+                dataFromPasspoint.userPortalUrlSource)
+    }
+
     private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
             CaptivePortalData.Builder(this).apply { mutator(this) }.build()
 
diff --git a/tests/net/common/java/android/net/NetworkStackTest.java b/tests/net/common/java/android/net/NetworkStackTest.java
index a99aa01..f8f9c72 100644
--- a/tests/net/common/java/android/net/NetworkStackTest.java
+++ b/tests/net/common/java/android/net/NetworkStackTest.java
@@ -15,20 +15,8 @@
  */
 package android.net;
 
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.NetworkStack.checkNetworkStackPermission;
-import static android.net.NetworkStack.checkNetworkStackPermissionOr;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.os.Build;
 import android.os.IBinder;
 
@@ -46,44 +34,15 @@
 
 @RunWith(AndroidJUnit4.class)
 public class NetworkStackTest {
-    private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
-
     @Rule
     public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
 
-    @Mock Context mCtx;
     @Mock private IBinder mConnectorBinder;
 
     @Before public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
     }
 
-    @Test
-    public void testCheckNetworkStackPermission() throws Exception {
-        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
-        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
-                .thenReturn(PERMISSION_DENIED);
-        checkNetworkStackPermission(mCtx);
-        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
-        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
-        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
-                .thenReturn(PERMISSION_GRANTED);
-        checkNetworkStackPermission(mCtx);
-        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
-        when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
-
-        try {
-            checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-        } catch (SecurityException e) {
-            // Expect to get a SecurityException
-            return;
-        }
-
-        fail("Expect fail but permission granted.");
-    }
-
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testGetService() {
         NetworkStack.setServiceForTest(mConnectorBinder);
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index cade5ba..fd29a95 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -20,76 +20,74 @@
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Build;
-import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 import com.android.testutils.DevSdkIgnoreRunner;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 
 @IgnoreUpTo(Build.VERSION_CODES.R)
 @RunWith(DevSdkIgnoreRunner.class)
 @SmallTest
 public class OemNetworkPreferencesTest {
 
-    private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
+    private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
     private static final String TEST_PACKAGE = "com.google.apps.contacts";
 
-    private final List<String> mPackages = new ArrayList<>();
     private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
 
-    @Before
-    public void beforeEachTestMethod() {
-        mPackages.add(TEST_PACKAGE);
-    }
-
     @Test
-    public void builderAddNetworkPreferenceRequiresNonNullPackages() {
+    public void testBuilderAddNetworkPreferenceRequiresNonNullPackageName() {
         assertThrows(NullPointerException.class,
-                () -> mBuilder.addNetworkPreference(TEST_PREF, null));
+                () -> mBuilder.addNetworkPreference(null, TEST_PREF));
     }
 
     @Test
-    public void getNetworkPreferencesReturnsCorrectValue() {
-        final int expectedNumberOfMappings = 1;
-        mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+    public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
+        assertThrows(NullPointerException.class,
+                () -> mBuilder.clearNetworkPreference(null));
+    }
 
-        final SparseArray<List<String>> networkPreferences =
+    @Test
+    public void testGetNetworkPreferenceReturnsCorrectValue() {
+        final int expectedNumberOfMappings = 1;
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+
+        final Map<String, Integer> networkPreferences =
                 mBuilder.build().getNetworkPreferences();
 
         assertEquals(expectedNumberOfMappings, networkPreferences.size());
-        assertEquals(mPackages.size(), networkPreferences.get(TEST_PREF).size());
-        assertEquals(mPackages.get(0), networkPreferences.get(TEST_PREF).get(0));
+        assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
     }
 
     @Test
-    public void getNetworkPreferencesReturnsUnmodifiableValue() {
+    public void testGetNetworkPreferenceReturnsUnmodifiableValue() {
         final String newPackage = "new.com.google.apps.contacts";
-        mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
 
-        final SparseArray<List<String>> networkPreferences =
+        final Map<String, Integer> networkPreferences =
                 mBuilder.build().getNetworkPreferences();
 
         assertThrows(UnsupportedOperationException.class,
-                () -> networkPreferences.get(TEST_PREF).set(mPackages.size() - 1, newPackage));
+                () -> networkPreferences.put(newPackage, TEST_PREF));
 
         assertThrows(UnsupportedOperationException.class,
-                () -> networkPreferences.get(TEST_PREF).add(newPackage));
+                () -> networkPreferences.remove(TEST_PACKAGE));
+
     }
 
     @Test
-    public void toStringReturnsCorrectValue() {
-        mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+    public void testToStringReturnsCorrectValue() {
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
 
         final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
 
@@ -99,10 +97,56 @@
 
     @Test
     public void testOemNetworkPreferencesParcelable() {
-        mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
 
         final OemNetworkPreferences prefs = mBuilder.build();
 
         assertParcelSane(prefs, 1 /* fieldCount */);
     }
+
+    @Test
+    public void testAddNetworkPreferenceOverwritesPriorPreference() {
+        final int newPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+        Map<String, Integer> networkPreferences =
+                mBuilder.build().getNetworkPreferences();
+
+        assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+        assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
+
+        mBuilder.addNetworkPreference(TEST_PACKAGE, newPref);
+        networkPreferences = mBuilder.build().getNetworkPreferences();
+
+        assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+        assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), newPref);
+    }
+
+    @Test
+    public void testRemoveNetworkPreferenceRemovesValue() {
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+        Map<String, Integer> networkPreferences =
+                mBuilder.build().getNetworkPreferences();
+
+        assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+
+        mBuilder.clearNetworkPreference(TEST_PACKAGE);
+        networkPreferences = mBuilder.build().getNetworkPreferences();
+
+        assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
+    }
+
+    @Test
+    public void testConstructorByOemNetworkPreferencesSetsValue() {
+        mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+        OemNetworkPreferences networkPreference = mBuilder.build();
+
+        final Map<String, Integer> networkPreferences =
+                new OemNetworkPreferences
+                        .Builder(networkPreference)
+                        .build()
+                        .getNetworkPreferences();
+
+        assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+        assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
+    }
 }
diff --git a/tests/net/deflake/Android.bp b/tests/net/deflake/Android.bp
index b1b0171..58ece37 100644
--- a/tests/net/deflake/Android.bp
+++ b/tests/net/deflake/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_test_host {
     name: "FrameworksNetDeflakeTest",
     srcs: ["src/**/*.kt"],
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 69742b9..4d1e337 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -14,6 +14,15 @@
 // 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: "FrameworksNetIntegrationTests",
     platform_apis: true,
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 083c8c8..9ed55f0 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -38,6 +38,7 @@
 import android.os.ConditionVariable
 import android.os.IBinder
 import android.os.INetworkManagementService
+import android.os.SystemConfigManager
 import android.os.UserHandle
 import android.testing.TestableContext
 import android.util.Log
@@ -57,6 +58,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.AdditionalAnswers
+import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Mock
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyInt
@@ -94,6 +96,8 @@
     private lateinit var netd: INetd
     @Mock
     private lateinit var dnsResolver: IDnsResolver
+    @Mock
+    private lateinit var systemConfigManager: SystemConfigManager
     @Spy
     private var context = TestableContext(realContext)
 
@@ -151,6 +155,11 @@
         doReturn(UserHandle.ALL).`when`(asUserCtx).user
         doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
         doNothing().`when`(context).sendStickyBroadcast(any(), any())
+        doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context)
+                .getSystemServiceName(SystemConfigManager::class.java)
+        doReturn(systemConfigManager).`when`(context)
+                .getSystemService(Context.SYSTEM_CONFIG_SERVICE)
+        doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
 
         networkStackClient = TestNetworkStackClient(realContext)
         networkStackClient.init()
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index c2fddf3..6a09b02 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -35,6 +35,7 @@
 import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -329,6 +330,9 @@
         mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
         mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
 
+        mustFail(() -> { manager.registerSystemDefaultNetworkCallback(null, handler); });
+        mustFail(() -> { manager.registerSystemDefaultNetworkCallback(callback, null); });
+
         mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
         mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
         mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
@@ -345,15 +349,17 @@
     @Test
     public void testRequestType() throws Exception {
         final String testPkgName = "MyPackage";
+        final String testAttributionTag = "MyTag";
         final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
         when(mCtx.getOpPackageName()).thenReturn(testPkgName);
+        when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
         final NetworkRequest request = makeRequest(1);
         final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
 
         manager.requestNetwork(request, callback);
         verify(mService).requestNetwork(eq(request.networkCapabilities),
                 eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
-                eq(testPkgName), eq(null));
+                eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         // Verify that register network callback does not calls requestNetwork at all.
@@ -361,19 +367,26 @@
         verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
                 anyInt(), any(), any());
         verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
-                eq(testPkgName));
+                eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         manager.registerDefaultNetworkCallback(callback);
         verify(mService).requestNetwork(eq(null),
                 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
-                eq(testPkgName), eq(null));
+                eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         manager.requestBackgroundNetwork(request, null, callback);
         verify(mService).requestNetwork(eq(request.networkCapabilities),
                 eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
-                eq(testPkgName), eq(null));
+                eq(testPkgName), eq(testAttributionTag));
+        reset(mService);
+
+        Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+        manager.registerSystemDefaultNetworkCallback(callback, handler);
+        verify(mService).requestNetwork(eq(null),
+                eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(testPkgName), eq(testAttributionTag));
         reset(mService);
     }
 
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 91fcbc0..b39555d 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -35,7 +35,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
 import org.mockito.MockitoAnnotations
 import kotlin.test.assertFalse
@@ -60,16 +59,13 @@
         subscriberId: String? = null,
         ssid: String? = null
     ): NetworkState {
-        val info = mock(NetworkInfo::class.java)
-        doReturn(type).`when`(info).type
-        doReturn(NetworkInfo.State.CONNECTED).`when`(info).state
         val lp = LinkProperties()
         val caps = NetworkCapabilities().apply {
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
             setSSID(ssid)
         }
-        return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
+        return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
     }
 
     private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
index 95a7942..c548e30 100644
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -49,7 +49,7 @@
     private static final String IDENTITY_STRING = "Identity";
     private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
 
-    private IConnectivityManager mMockCs;
+    private IVpnManager mMockService;
     private VpnManager mVpnManager;
     private final MockContext mMockContext =
             new MockContext() {
@@ -61,24 +61,26 @@
 
     @Before
     public void setUp() throws Exception {
-        mMockCs = mock(IConnectivityManager.class);
-        mVpnManager = new VpnManager(mMockContext, mMockCs);
+        mMockService = mock(IVpnManager.class);
+        mVpnManager = new VpnManager(mMockContext, mMockService);
     }
 
     @Test
     public void testProvisionVpnProfilePreconsented() throws Exception {
         final PlatformVpnProfile profile = getPlatformVpnProfile();
-        when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(true);
+        when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+                .thenReturn(true);
 
         // Expect there to be no intent returned, as consent has already been granted.
         assertNull(mVpnManager.provisionVpnProfile(profile));
-        verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+        verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
     }
 
     @Test
     public void testProvisionVpnProfileNeedsConsent() throws Exception {
         final PlatformVpnProfile profile = getPlatformVpnProfile();
-        when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false);
+        when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+                .thenReturn(false);
 
         // Expect intent to be returned, as consent has not already been granted.
         final Intent intent = mVpnManager.provisionVpnProfile(profile);
@@ -88,25 +90,25 @@
                 ComponentName.unflattenFromString(
                         "com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
         assertEquals(expectedComponentName, intent.getComponent());
-        verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+        verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
     }
 
     @Test
     public void testDeleteProvisionedVpnProfile() throws Exception {
         mVpnManager.deleteProvisionedVpnProfile();
-        verify(mMockCs).deleteVpnProfile(eq(PKG_NAME));
+        verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
     }
 
     @Test
     public void testStartProvisionedVpnProfile() throws Exception {
         mVpnManager.startProvisionedVpnProfile();
-        verify(mMockCs).startVpnProfile(eq(PKG_NAME));
+        verify(mMockService).startVpnProfile(eq(PKG_NAME));
     }
 
     @Test
     public void testStopProvisionedVpnProfile() throws Exception {
         mVpnManager.stopProvisionedVpnProfile();
-        verify(mMockCs).stopVpnProfile(eq(PKG_NAME));
+        verify(mMockService).stopVpnProfile(eq(PKG_NAME));
     }
 
     private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
new file mode 100644
index 0000000..866f38c
--- /dev/null
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 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.net;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnTransportInfoTest {
+
+    @Test
+    public void testParceling() {
+        VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+        assertParcelSane(v, 1 /* fieldCount */);
+    }
+
+    @Test
+    public void testEqualsAndHashCode() {
+        VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+        VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
+        VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+        assertNotEquals(v1, v2);
+        assertEquals(v1, v3);
+        assertEquals(v1.hashCode(), v3.hashCode());
+    }
+}
\ No newline at end of file
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b0cc7f1..6241127 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -66,6 +66,8 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
@@ -82,6 +84,11 @@
 import static android.net.NetworkPolicyManager.RULE_NONE;
 import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
@@ -169,6 +176,7 @@
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
+import android.net.IOnSetOemNetworkPreferenceListener;
 import android.net.IQosCallback;
 import android.net.InetAddresses;
 import android.net.InterfaceConfigurationParcel;
@@ -192,6 +200,7 @@
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
 import android.net.NetworkTestResultParcelable;
+import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
 import android.net.QosCallbackException;
 import android.net.QosFilter;
@@ -200,11 +209,13 @@
 import android.net.RouteInfo;
 import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
+import android.net.TransportInfo;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
 import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
 import android.net.VpnManager;
+import android.net.VpnTransportInfo;
 import android.net.metrics.IpConnectivityLog;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
@@ -227,6 +238,7 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
+import android.os.SystemConfigManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -298,6 +310,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -331,11 +344,12 @@
     private static final String TAG = "ConnectivityServiceTest";
 
     private static final int TIMEOUT_MS = 500;
-    private static final int TEST_LINGER_DELAY_MS = 300;
-    // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
-    // LOST callback that arrives immediately and a LOST callback that arrives after the linger
-    // timeout. For this, our assertions should run fast enough to leave less than
-    // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
+    private static final int TEST_LINGER_DELAY_MS = 400;
+    private static final int TEST_NASCENT_DELAY_MS = 300;
+    // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
+    // between a LOST callback that arrives immediately and a LOST callback that arrives after
+    // the linger/nascent timeout. For this, our assertions should run fast enough to leave
+    // less than (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
     // supposedly fired, and the time we call expectCallback.
     private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
     // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
@@ -347,6 +361,7 @@
     private static final long TIMESTAMP = 1234L;
 
     private static final int NET_ID = 110;
+    private static final int OEM_PREF_ANY_NET_ID = -1;
     // Set a non-zero value to verify the flow to set tcp init rwnd value.
     private static final int TEST_TCP_INIT_RWND = 60;
 
@@ -356,17 +371,26 @@
     private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
     private static final String VPN_IFNAME = "tun10042";
     private static final String TEST_PACKAGE_NAME = "com.android.test.package";
+    private static final int TEST_PACKAGE_UID = 123;
     private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
 
     private static final String INTERFACE_NAME = "interface";
 
-    private static final String TEST_VENUE_URL_NA = "https://android.com/";
+    private static final String TEST_VENUE_URL_NA_PASSPOINT = "https://android.com/";
+    private static final String TEST_VENUE_URL_NA_OTHER = "https://example.com/";
+    private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT =
+            "https://android.com/terms/";
+    private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER =
+            "https://example.com/terms/";
     private static final String TEST_VENUE_URL_CAPPORT = "https://android.com/capport/";
+    private static final String TEST_USER_PORTAL_API_URL_CAPPORT =
+            "https://android.com/user/api/capport/";
     private static final String TEST_FRIENDLY_NAME = "Network friendly name";
     private static final String TEST_REDIRECT_URL = "http://example.com/firstPath";
 
     private MockContext mServiceContext;
     private HandlerThread mCsHandlerThread;
+    private HandlerThread mVMSHandlerThread;
     private ConnectivityService.Dependencies mDeps;
     private ConnectivityService mService;
     private WrappedConnectivityManager mCm;
@@ -381,6 +405,7 @@
     private TestNetIdManager mNetIdManager;
     private QosCallbackMockHelper mQosCallbackMockHelper;
     private QosCallbackTracker mQosCallbackTracker;
+    private VpnManagerService mVpnManagerService;
 
     // State variables required to emulate NetworkPolicyManagerService behaviour.
     private int mUidRules = RULE_NONE;
@@ -406,6 +431,7 @@
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
     @Mock KeyStore mKeyStore;
+    @Mock SystemConfigManager mSystemConfigManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -502,6 +528,7 @@
             if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
             if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
             if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
+            if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
             return super.getSystemService(name);
         }
 
@@ -975,10 +1002,12 @@
         // Used to collect the networks requests managed by this factory. This is a duplicate of
         // the internal information stored in the NetworkFactory (which is private).
         private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
+        private final HandlerThread mHandlerSendingRequests;
 
         public MockNetworkFactory(Looper looper, Context context, String logTag,
-                NetworkCapabilities filter) {
+                NetworkCapabilities filter, HandlerThread threadSendingRequests) {
             super(looper, context, logTag, filter);
+            mHandlerSendingRequests = threadSendingRequests;
         }
 
         public int getMyRequestCount() {
@@ -1032,7 +1061,8 @@
         public void terminate() {
             super.terminate();
             // Make sure there are no remaining requests unaccounted for.
-            assertNull(mRequestHistory.poll(TIMEOUT_MS, r -> true));
+            HandlerUtils.waitForIdle(mHandlerSendingRequests, TIMEOUT_MS);
+            assertNull(mRequestHistory.poll(0, r -> true));
         }
 
         // Trigger releasing the request as unfulfillable
@@ -1109,7 +1139,7 @@
         }
 
         @Override
-        public int getActiveAppVpnType() {
+        public int getActiveVpnType() {
             return mVpnType;
         }
 
@@ -1122,10 +1152,12 @@
         private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
                 throws Exception {
             if (mAgentRegistered) throw new IllegalStateException("already registered");
+            updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
             mConfig = new VpnConfig();
             setUids(uids);
             if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
             mInterface = VPN_IFNAME;
+            mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
             mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
                     mNetworkCapabilities);
             mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -1251,33 +1283,77 @@
                 r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
     }
 
+    private VpnManagerService makeVpnManagerService() {
+        final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
+            public int getCallingUid() {
+                return mDeps.getCallingUid();
+            }
+
+            public HandlerThread makeHandlerThread() {
+                return mVMSHandlerThread;
+            }
+
+            public KeyStore getKeyStore() {
+                return mKeyStore;
+            }
+
+            public INetd getNetd() {
+                return mMockNetd;
+            }
+
+            public INetworkManagementService getINetworkManagementService() {
+                return mNetworkManagementService;
+            }
+        };
+        return new VpnManagerService(mServiceContext, deps);
+    }
+
+    private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
+        assertNotNull(nc);
+        final TransportInfo ti = nc.getTransportInfo();
+        assertTrue("VPN TransportInfo is not a VpnTransportInfo: " + ti,
+                ti instanceof VpnTransportInfo);
+        assertEquals(type, ((VpnTransportInfo) ti).type);
+
+    }
+
+    private void processBroadcastForVpn(Intent intent) {
+        mServiceContext.sendBroadcast(intent);
+        HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
+        waitForIdle();
+    }
+
     private void mockVpn(int uid) {
-        synchronized (mService.mVpns) {
+        synchronized (mVpnManagerService.mVpns) {
             int userId = UserHandle.getUserId(uid);
             mMockVpn = new MockVpn(userId);
-            // This has no effect unless the VPN is actually connected, because things like
-            // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
-            // netId, and check if that network is actually connected.
-            mService.mVpns.put(userId, mMockVpn);
+            // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
+            mVpnManagerService.mVpns.put(userId, mMockVpn);
         }
     }
 
-    private void updateUidNetworkingBlocked() {
-        doAnswer(i -> NetworkPolicyManagerInternal.isUidNetworkingBlocked(
-                i.getArgument(0) /* uid */, mUidRules, i.getArgument(1) /* metered */,
-                mRestrictBackground)
+    private void mockUidNetworkingBlocked() {
+        doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
+                .checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
+                        i.getArgument(1) /* metered */, mRestrictBackground)
         ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
+
+        doAnswer(inv -> mContext.getSystemService(NetworkPolicyManager.class)
+                .checkUidNetworkingBlocked(inv.getArgument(0) /* uid */,
+                        inv.getArgument(1) /* uidRules */,
+                        inv.getArgument(2) /* isNetworkMetered */,
+                        inv.getArgument(3) /* isBackgroundRestricted */)
+        ).when(mNetworkPolicyManager).checkUidNetworkingBlocked(
+                anyInt(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     private void setUidRulesChanged(int uidRules) throws RemoteException {
         mUidRules = uidRules;
-        updateUidNetworkingBlocked();
         mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
     }
 
     private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
         mRestrictBackground = restrictBackground;
-        updateUidNetworkingBlocked();
         mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
     }
 
@@ -1359,6 +1435,7 @@
         applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
                 .thenReturn(applicationInfo);
+        when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
 
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
         // http://b/25897652 .
@@ -1370,6 +1447,7 @@
         FakeSettingsProvider.clearSettingsProvider();
         mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
                 new FakeSettingsProvider());
+        mServiceContext.setUseRegisteredHandlers(true);
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
         LocalServices.addService(
                 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -1379,6 +1457,7 @@
         initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
 
         mCsHandlerThread = new HandlerThread("TestConnectivityService");
+        mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
         mDeps = makeDependencies();
         returnRealCallingUid();
         mService = new ConnectivityService(mServiceContext,
@@ -1389,6 +1468,7 @@
                 mMockNetd,
                 mDeps);
         mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
+        mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
         verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
@@ -1400,6 +1480,8 @@
         // getSystemService() correctly.
         mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
         mService.systemReadyInternal();
+        mVpnManagerService = makeVpnManagerService();
+        mVpnManagerService.systemReady();
         mockVpn(Process.myUid());
         mCm.bindProcessToNetwork(null);
         mQosCallbackTracker = mock(QosCallbackTracker.class);
@@ -1427,7 +1509,6 @@
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
-        doReturn(mKeyStore).when(deps).getKeyStore();
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
                     inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1540,10 +1621,13 @@
         }
         switch (transport) {
             case TRANSPORT_WIFI:
-                assertEquals(mCm.getActiveNetwork(), mWiFiNetworkAgent.getNetwork());
+                assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
                 break;
             case TRANSPORT_CELLULAR:
-                assertEquals(mCm.getActiveNetwork(), mCellNetworkAgent.getNetwork());
+                assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+                break;
+            case TRANSPORT_ETHERNET:
+                assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
                 break;
             default:
                 break;
@@ -1552,6 +1636,7 @@
         assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
         assertEquals(transportToLegacyType(transport),
                 mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
+        assertNotNull(mCm.getActiveNetworkInfoForUid(Process.myUid()));
         // Test getNetworkCapabilities(Network)
         assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
         assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
@@ -1731,6 +1816,108 @@
         verifyNoNetwork();
     }
 
+    /**
+     * Verify a newly created network will be inactive instead of torn down even if no one is
+     * requesting.
+     */
+    @Test
+    public void testNewNetworkInactive() throws Exception {
+        // Create a callback that monitoring the testing network.
+        final TestNetworkCallback listenCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), listenCallback);
+
+        // 1. Create a network that is not requested by anyone, and does not satisfy any of the
+        // default requests. Verify that the network will be inactive instead of torn down.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connectWithoutInternet();
+        listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        listenCallback.assertNoCallback();
+
+        // Verify that the network will be torn down after nascent expiry. A small period of time
+        // is added in case of flakiness.
+        final int nascentTimeoutMs =
+                mService.mNascentDelayMs + mService.mNascentDelayMs / 4;
+        listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, nascentTimeoutMs);
+
+        // 2. Create a network that is satisfied by a request comes later.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connectWithoutInternet();
+        listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI).build();
+        final TestNetworkCallback wifiCallback = new TestNetworkCallback();
+        mCm.requestNetwork(wifiRequest, wifiCallback);
+        wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+        // Verify that the network will be kept since the request is still satisfied. And is able
+        // to get disconnected as usual if the request is released after the nascent timer expires.
+        listenCallback.assertNoCallback(nascentTimeoutMs);
+        mCm.unregisterNetworkCallback(wifiCallback);
+        listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+
+        // 3. Create a network that is satisfied by a request comes later.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connectWithoutInternet();
+        listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        mCm.requestNetwork(wifiRequest, wifiCallback);
+        wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+        // Verify that the network will still be torn down after the request gets removed.
+        mCm.unregisterNetworkCallback(wifiCallback);
+        listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+
+        // There is no need to ensure that LOSING is never sent in the common case that the
+        // network immediately satisfies a request that was already present, because it is already
+        // verified anywhere whenever {@code TestNetworkCallback#expectAvailable*} is called.
+
+        mCm.unregisterNetworkCallback(listenCallback);
+    }
+
+    /**
+     * Verify a newly created network will be inactive and switch to background if only background
+     * request is satisfied.
+     */
+    @Test
+    public void testNewNetworkInactive_bgNetwork() throws Exception {
+        // Create a callback that monitoring the wifi network.
+        final TestNetworkCallback wifiListenCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI).build(), wifiListenCallback);
+
+        // Create callbacks that can monitor background and foreground mobile networks.
+        // This is done by granting using background networks permission before registration. Thus,
+        // the service will not add {@code NET_CAPABILITY_FOREGROUND} by default.
+        grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+        final TestNetworkCallback bgMobileListenCallback = new TestNetworkCallback();
+        final TestNetworkCallback fgMobileListenCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build(), bgMobileListenCallback);
+        mCm.registerNetworkCallback(new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_FOREGROUND).build(), fgMobileListenCallback);
+
+        // Connect wifi, which satisfies default request.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+
+        // Connect a cellular network, verify that satisfies only the background callback.
+        setAlwaysOnNetworks(true);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        fgMobileListenCallback.assertNoCallback();
+        assertFalse(isForegroundNetwork(mCellNetworkAgent));
+
+        mCellNetworkAgent.disconnect();
+        bgMobileListenCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        fgMobileListenCallback.assertNoCallback();
+
+        mCm.unregisterNetworkCallback(wifiListenCallback);
+        mCm.unregisterNetworkCallback(bgMobileListenCallback);
+        mCm.unregisterNetworkCallback(fgMobileListenCallback);
+    }
+
     @Test
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
@@ -1987,6 +2174,24 @@
         }
     }
 
+    static void expectOnLost(TestNetworkAgentWrapper network, TestNetworkCallback ... callbacks) {
+        for (TestNetworkCallback c : callbacks) {
+            c.expectCallback(CallbackEntry.LOST, network);
+        }
+    }
+
+    static void expectAvailableCallbacksUnvalidatedWithSpecifier(TestNetworkAgentWrapper network,
+            NetworkSpecifier specifier, TestNetworkCallback ... callbacks) {
+        for (TestNetworkCallback c : callbacks) {
+            c.expectCallback(CallbackEntry.AVAILABLE, network);
+            c.expectCapabilitiesThat(network, (nc) ->
+                    !nc.hasCapability(NET_CAPABILITY_VALIDATED)
+                            && Objects.equals(specifier, nc.getNetworkSpecifier()));
+            c.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, network);
+            c.expectCallback(CallbackEntry.BLOCKED_STATUS, network);
+        }
+    }
+
     @Test
     public void testStateChangeNetworkCallbacks() throws Exception {
         final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
@@ -2593,7 +2798,7 @@
         final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
         handlerThread.start();
         final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
-                mServiceContext, "testFactory", filter);
+                mServiceContext, "testFactory", filter, mCsHandlerThread);
         testFactory.setScoreFilter(40);
         ConditionVariable cv = testFactory.getNetworkStartedCV();
         testFactory.register();
@@ -2701,7 +2906,7 @@
         // does not crash.
         for (int i = 0; i < 100; i++) {
             final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
-                    mServiceContext, "testFactory", filter);
+                    mServiceContext, "testFactory", filter, mCsHandlerThread);
             // Register the factory and don't be surprised when the default request arrives.
             testFactory.register();
             testFactory.expectRequestAdd();
@@ -3165,39 +3370,68 @@
     }
 
     private class CaptivePortalTestData {
-        CaptivePortalTestData(CaptivePortalData naData, CaptivePortalData capportData,
-                CaptivePortalData expectedMergedData) {
-            mNaData = naData;
+        CaptivePortalTestData(CaptivePortalData naPasspointData, CaptivePortalData capportData,
+                CaptivePortalData naOtherData, CaptivePortalData expectedMergedPasspointData,
+                CaptivePortalData expectedMergedOtherData) {
+            mNaPasspointData = naPasspointData;
             mCapportData = capportData;
-            mExpectedMergedData = expectedMergedData;
+            mNaOtherData = naOtherData;
+            mExpectedMergedPasspointData = expectedMergedPasspointData;
+            mExpectedMergedOtherData = expectedMergedOtherData;
         }
 
-        public final CaptivePortalData mNaData;
+        public final CaptivePortalData mNaPasspointData;
         public final CaptivePortalData mCapportData;
-        public final CaptivePortalData mExpectedMergedData;
+        public final CaptivePortalData mNaOtherData;
+        public final CaptivePortalData mExpectedMergedPasspointData;
+        public final CaptivePortalData mExpectedMergedOtherData;
+
     }
 
     private CaptivePortalTestData setupCaptivePortalData() {
         final CaptivePortalData capportData = new CaptivePortalData.Builder()
                 .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
                 .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
+                .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
                 .setExpiryTime(1000000L)
                 .setBytesRemaining(12345L)
                 .build();
 
-        final CaptivePortalData naData = new CaptivePortalData.Builder()
+        final CaptivePortalData naPasspointData = new CaptivePortalData.Builder()
                 .setBytesRemaining(80802L)
-                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA))
+                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+                .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
                 .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
 
-        final CaptivePortalData expectedMergedData = new CaptivePortalData.Builder()
+        final CaptivePortalData naOtherData = new CaptivePortalData.Builder()
+                .setBytesRemaining(80802L)
+                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_OTHER),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
+                .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
+                .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
+
+        final CaptivePortalData expectedMergedPasspointData = new CaptivePortalData.Builder()
                 .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
                 .setBytesRemaining(12345L)
                 .setExpiryTime(1000000L)
-                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA))
+                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+                .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
+                        CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
                 .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
 
-        return new CaptivePortalTestData(naData, capportData, expectedMergedData);
+        final CaptivePortalData expectedMergedOtherData = new CaptivePortalData.Builder()
+                .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
+                .setBytesRemaining(12345L)
+                .setExpiryTime(1000000L)
+                .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
+                .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
+                .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
+        return new CaptivePortalTestData(naPasspointData, capportData, naOtherData,
+                expectedMergedPasspointData, expectedMergedOtherData);
     }
 
     @Test
@@ -3211,15 +3445,26 @@
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
                 lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
 
-        // Venue URL and friendly name from Network agent, confirm that API data gets precedence
-        // on the bytes remaining.
+        // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm
+        // that API data gets precedence on the bytes remaining.
         final LinkProperties linkProperties = new LinkProperties();
-        linkProperties.setCaptivePortalData(captivePortalTestData.mNaData);
+        linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
         mWiFiNetworkAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the capport data is merged
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
-                lp -> captivePortalTestData.mExpectedMergedData.equals(lp.getCaptivePortalData()));
+                lp -> captivePortalTestData.mExpectedMergedPasspointData
+                        .equals(lp.getCaptivePortalData()));
+
+        // Now send this information from non-Passpoint source, confirm that Capport data takes
+        // precedence
+        linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
+        mWiFiNetworkAgent.sendLinkProperties(linkProperties);
+
+        // Make sure that the capport data is merged
+        captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+                lp -> captivePortalTestData.mExpectedMergedOtherData
+                        .equals(lp.getCaptivePortalData()));
 
         // Create a new LP with no Network agent capport data
         final LinkProperties newLps = new LinkProperties();
@@ -3236,12 +3481,12 @@
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
                 lp -> lp.getCaptivePortalData() == null);
 
-        newLps.setCaptivePortalData(captivePortalTestData.mNaData);
+        newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
         mWiFiNetworkAgent.sendLinkProperties(newLps);
 
         // Make sure that only the network agent capport data is available
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
-                lp -> captivePortalTestData.mNaData.equals(lp.getCaptivePortalData()));
+                lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
     }
 
     @Test
@@ -3252,12 +3497,12 @@
         // Venue URL and friendly name from Network agent, confirm that API data gets precedence
         // on the bytes remaining.
         final LinkProperties linkProperties = new LinkProperties();
-        linkProperties.setCaptivePortalData(captivePortalTestData.mNaData);
+        linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
         mWiFiNetworkAgent.sendLinkProperties(linkProperties);
 
         // Make sure that the data is saved correctly
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
-                lp -> captivePortalTestData.mNaData.equals(lp.getCaptivePortalData()));
+                lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
 
         // Expected merged data: Network agent data is preferred, and values that are not used by
         // it are merged from capport data
@@ -3265,7 +3510,8 @@
 
         // Make sure that the Capport data is merged correctly
         captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
-                lp -> captivePortalTestData.mExpectedMergedData.equals(lp.getCaptivePortalData()));
+                lp -> captivePortalTestData.mExpectedMergedPasspointData.equals(
+                        lp.getCaptivePortalData()));
 
         // Now set the naData to null
         linkProperties.setCaptivePortalData(null);
@@ -3276,6 +3522,32 @@
                 lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
     }
 
+    @Test
+    public void testMergeCaptivePortalDataFromNetworkAgentOtherSourceFirstThenCapport()
+            throws Exception {
+        final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
+        final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
+
+        // Venue URL and friendly name from Network agent, confirm that API data gets precedence
+        // on the bytes remaining.
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
+        mWiFiNetworkAgent.sendLinkProperties(linkProperties);
+
+        // Make sure that the data is saved correctly
+        captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+                lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData()));
+
+        // Expected merged data: Network agent data is preferred, and values that are not used by
+        // it are merged from capport data
+        mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
+
+        // Make sure that the Capport data is merged correctly
+        captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+                lp -> captivePortalTestData.mExpectedMergedOtherData.equals(
+                        lp.getCaptivePortalData()));
+    }
+
     private NetworkRequest.Builder newWifiRequestBuilder() {
         return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
     }
@@ -3283,11 +3555,9 @@
     /**
      * Verify request matching behavior with network specifiers.
      *
-     * Note: this test is somewhat problematic since it involves removing capabilities from
-     * agents - i.e. agents rejecting requests which they previously accepted. This is flagged
-     * as a WTF bug in
-     * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)} but
-     * does work.
+     * This test does not check updating the specifier on a live network because the specifier is
+     * immutable and this triggers a WTF in
+     * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)}.
      */
     @Test
     public void testNetworkSpecifier() throws Exception {
@@ -3372,60 +3642,49 @@
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        cEmpty3.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
+                cEmpty1, cEmpty2, cEmpty3, cEmpty4);
         assertNoCallbacks(cFoo, cBar);
 
+        mWiFiNetworkAgent.disconnect();
+        expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4);
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
-        cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        for (TestNetworkCallback c: emptyCallbacks) {
-            c.expectCapabilitiesThat(mWiFiNetworkAgent,
-                    (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
-        }
-        cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
-                (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
+        mWiFiNetworkAgent.connect(false);
+        expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsFoo,
+                cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
+        cBar.assertNoCallback();
         assertEquals(nsFoo,
                 mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-        cFoo.assertNoCallback();
+        assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
 
+        mWiFiNetworkAgent.disconnect();
+        expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
-        cFoo.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-        cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        for (TestNetworkCallback c: emptyCallbacks) {
-            c.expectCapabilitiesThat(mWiFiNetworkAgent,
-                    (caps) -> caps.getNetworkSpecifier().equals(nsBar));
-        }
-        cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
-                (caps) -> caps.getNetworkSpecifier().equals(nsBar));
+        mWiFiNetworkAgent.connect(false);
+        expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsBar,
+                cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
+        cFoo.assertNoCallback();
         assertEquals(nsBar,
                 mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-        cBar.assertNoCallback();
 
+        mWiFiNetworkAgent.disconnect();
+        expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
+        cFoo.assertNoCallback();
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
-        cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        for (TestNetworkCallback c : emptyCallbacks) {
-            c.expectCapabilitiesThat(mWiFiNetworkAgent,
-                    (caps) -> caps.getNetworkSpecifier() == null);
-        }
-        cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
-                (caps) -> caps.getNetworkSpecifier() == null);
-        cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
-                (caps) -> caps.getNetworkSpecifier() == null);
+        mWiFiNetworkAgent.connect(false);
+        expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
+                cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
         assertNull(
                 mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-        cFoo.assertNoCallback();
-        cBar.assertNoCallback();
 
-        mWiFiNetworkAgent.setNetworkSpecifier(null);
-        cFoo.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-        cBar.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-        for (TestNetworkCallback c: emptyCallbacks) {
-            c.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent);
-        }
-
-        assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
+        mWiFiNetworkAgent.disconnect();
+        expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
     }
 
     /**
@@ -3528,10 +3787,19 @@
 
     @Test
     public void testRegisterDefaultNetworkCallback() throws Exception {
+        // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_GRANTED);
+
         final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
         defaultNetworkCallback.assertNoCallback();
 
+        final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+        final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
+        mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback, handler);
+        systemDefaultCallback.assertNoCallback();
+
         // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
         // whenever Wi-Fi is up. Without this, the mobile network agent is
         // reaped before any other activity can take place.
@@ -3546,27 +3814,35 @@
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring down cell. Expect no default network callback, since it wasn't the default.
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
+        systemDefaultCallback.assertNoCallback();
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up cell. Expect no default network callback, since it won't be the default.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
+        systemDefaultCallback.assertNoCallback();
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring down wifi. Expect the default network callback to notified of LOST wifi
         // followed by AVAILABLE cell.
@@ -3574,19 +3850,25 @@
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        systemDefaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         waitForIdle();
         assertEquals(null, mCm.getActiveNetwork());
 
         mMockVpn.establishForMyUid();
         assertUidRangesUpdatedForMyUid(true);
         defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        systemDefaultCallback.assertNoCallback();
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(null, systemDefaultCallback.getLastAvailableNetwork());
 
         mMockVpn.disconnect();
         defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        systemDefaultCallback.assertNoCallback();
         waitForIdle();
         assertEquals(null, mCm.getActiveNetwork());
     }
@@ -3652,6 +3934,24 @@
         mCm.unregisterNetworkCallback(cellNetworkCallback);
     }
 
+    @Test
+    public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(false /* validated */);
+
+        final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        assertThrows(SecurityException.class,
+                () -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
+        callback.assertNoCallback();
+
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_GRANTED);
+        mCm.registerSystemDefaultNetworkCallback(callback, handler);
+        callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        mCm.unregisterNetworkCallback(callback);
+    }
+
     private void setCaptivePortalMode(int mode) {
         ContentResolver cr = mServiceContext.getContentResolver();
         Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
@@ -3843,7 +4143,7 @@
                 .addTransportType(TRANSPORT_CELLULAR)
                 .addCapability(NET_CAPABILITY_INTERNET);
         final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
-                mServiceContext, "testFactory", filter);
+                mServiceContext, "testFactory", filter, mCsHandlerThread);
         testFactory.setScoreFilter(40);
 
         // Register the factory and expect it to start looking for a network.
@@ -3888,8 +4188,10 @@
             setAlwaysOnNetworks(false);
             testFactory.expectRequestRemove();
 
-            // ...  and cell data to be torn down.
-            cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            // ...  and cell data to be torn down after nascent network timeout.
+            cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
+                    mService.mNascentDelayMs + TEST_CALLBACK_TIMEOUT_MS);
+            waitForIdle();
             assertLength(1, mCm.getAllNetworks());
         } finally {
             testFactory.terminate();
@@ -4189,7 +4491,7 @@
                 .addTransportType(TRANSPORT_WIFI)
                 .addCapability(NET_CAPABILITY_INTERNET);
         final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
-                mServiceContext, "testFactory", filter);
+                mServiceContext, "testFactory", filter, mCsHandlerThread);
         testFactory.setScoreFilter(40);
 
         // Register the factory and expect it to receive the default request.
@@ -5294,20 +5596,20 @@
         // MOBILE_IFNAME even though the default network is wifi.
         // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
         // applies to the system server UID should not have any bearing on network stats.
-        mService.setUnderlyingNetworksForVpn(onlyCell);
+        mMockVpn.setUnderlyingNetworks(onlyCell);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME});
         reset(mStatsService);
 
-        mService.setUnderlyingNetworksForVpn(cellAndWifi);
+        mMockVpn.setUnderlyingNetworks(cellAndWifi);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
         reset(mStatsService);
 
         // Null underlying networks are ignored.
-        mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
+        mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
@@ -5356,25 +5658,25 @@
         // is probably a performance improvement (though it's very unlikely that a VPN would declare
         // no underlying networks).
         // Also, for the same reason as above, the active interface passed in is null.
-        mService.setUnderlyingNetworksForVpn(new Network[0]);
+        mMockVpn.setUnderlyingNetworks(new Network[0]);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, null);
         reset(mStatsService);
 
         // Specifying only a null underlying network is the same as no networks.
-        mService.setUnderlyingNetworksForVpn(onlyNull);
+        mMockVpn.setUnderlyingNetworks(onlyNull);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, null);
         reset(mStatsService);
 
         // Specifying networks that are all disconnected is the same as specifying no networks.
-        mService.setUnderlyingNetworksForVpn(onlyCell);
+        mMockVpn.setUnderlyingNetworks(onlyCell);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, null);
         reset(mStatsService);
 
         // Passing in null again means follow the default network again.
-        mService.setUnderlyingNetworksForVpn(null);
+        mMockVpn.setUnderlyingNetworks(null);
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{WIFI_IFNAME});
@@ -5849,7 +6151,7 @@
         mMockVpn.establishForMyUid(false, true, false);
         assertUidRangesUpdatedForMyUid(true);
         final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
-        mService.setUnderlyingNetworksForVpn(new Network[]{wifiNetwork});
+        mMockVpn.setUnderlyingNetworks(new Network[]{wifiNetwork});
         callback.expectAvailableCallbacksUnvalidated(mMockVpn);
         assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
                 .hasTransport(TRANSPORT_VPN));
@@ -6009,6 +6311,10 @@
 
     @Test
     public void testVpnNetworkActive() throws Exception {
+        // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_GRANTED);
+
         final int uid = Process.myUid();
 
         final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
@@ -6016,6 +6322,7 @@
         final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
         final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
         final NetworkRequest genericRequest = new NetworkRequest.Builder()
                 .removeCapability(NET_CAPABILITY_NOT_VPN).build();
@@ -6029,6 +6336,8 @@
         mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
         mCm.registerDefaultNetworkCallback(defaultCallback);
+        mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+                new Handler(ConnectivityThread.getInstanceLooper()));
         defaultCallback.assertNoCallback();
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -6038,12 +6347,13 @@
         genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         vpnNetworkCallback.assertNoCallback();
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         final Set<UidRange> ranges = uidRangesForUid(uid);
         mMockVpn.registerAgent(ranges);
-        mService.setUnderlyingNetworksForVpn(new Network[0]);
+        mMockVpn.setUnderlyingNetworks(new Network[0]);
 
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
@@ -6058,7 +6368,10 @@
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
         defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        systemDefaultCallback.assertNoCallback();
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+        assertEquals(mWiFiNetworkAgent.getNetwork(),
+                systemDefaultCallback.getLastAvailableNetwork());
 
         ranges.clear();
         mMockVpn.setUids(ranges);
@@ -6075,6 +6388,7 @@
         // much, but that is the reason the test here has to check for an update to the
         // capabilities instead of the expected LOST then AVAILABLE.
         defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+        systemDefaultCallback.assertNoCallback();
 
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setUids(ranges);
@@ -6086,6 +6400,7 @@
         // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
         // happen outside of the test, ConnectivityService does not rematch callbacks.
         defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+        systemDefaultCallback.assertNoCallback();
 
         mWiFiNetworkAgent.disconnect();
 
@@ -6094,6 +6409,7 @@
         wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         vpnNetworkCallback.assertNoCallback();
         defaultCallback.assertNoCallback();
+        systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
 
         mMockVpn.disconnect();
 
@@ -6102,12 +6418,14 @@
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
         defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        systemDefaultCallback.assertNoCallback();
         assertEquals(null, mCm.getActiveNetwork());
 
         mCm.unregisterNetworkCallback(genericNetworkCallback);
         mCm.unregisterNetworkCallback(wifiNetworkCallback);
         mCm.unregisterNetworkCallback(vpnNetworkCallback);
         mCm.unregisterNetworkCallback(defaultCallback);
+        mCm.unregisterNetworkCallback(systemDefaultCallback);
     }
 
     @Test
@@ -6243,11 +6561,13 @@
         assertTrue(nc.hasCapability(NET_CAPABILITY_VALIDATED));
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+
+        assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
     }
 
     private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
         final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
-                userId, "com.android.calling.package");
+                userId, "com.android.calling.package", "com.test");
         final String defaultCapsString = Arrays.toString(defaultCaps);
         assertEquals(defaultCapsString, defaultCaps.length, networks.length);
         final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
@@ -6282,6 +6602,7 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
         // A VPN without underlying networks is not suspended.
         assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
 
         final int userId = UserHandle.getUserId(Process.myUid());
         assertDefaultNetworkCapabilities(userId /* no networks */);
@@ -6291,7 +6612,7 @@
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
         mCellNetworkAgent.connect(true);
 
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6306,7 +6627,7 @@
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
         mWiFiNetworkAgent.connect(true);
 
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6317,7 +6638,7 @@
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Don't disconnect, but note the VPN is not using wifi any more.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6348,7 +6669,7 @@
         vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
 
         // Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mWiFiNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6359,7 +6680,7 @@
         assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
 
         // Use both again.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6374,7 +6695,7 @@
         vpnNetworkCallback.assertNoCallback();
 
         // Stop using WiFi. The VPN is suspended again.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork() });
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
                 (caps) -> caps.hasTransport(TRANSPORT_VPN)
@@ -6385,7 +6706,7 @@
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Use both again.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
 
         vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6445,6 +6766,7 @@
         // By default, VPN is set to track default network (i.e. its underlying networks is null).
         // In case of no default network, VPN is considered metered.
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+        assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
 
         // Connect to Cell; Cell is the default network.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -6502,6 +6824,7 @@
         NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
         assertNotNull("nc=" + nc, nc.getUids());
         assertEquals(nc.getUids(), uidRangesForUid(uid));
+        assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
 
         // Set an underlying network and expect to see the VPN transports change.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -6517,19 +6840,18 @@
                 .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
 
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
 
         // Send a USER_ADDED broadcast for it.
-        // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
-        final Handler handler = new Handler(mCsHandlerThread.getLooper());
-        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+        processBroadcastForVpn(addedIntent);
 
         // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
         // restricted user.
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
+                && caps.getUids().contains(createUidRange(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6539,14 +6861,15 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
+                && caps.getUids().contains(createUidRange(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
         removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-        handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+        processBroadcastForVpn(removedIntent);
 
         // Expect that the VPN gains the UID range for the restricted user, and that the capability
         // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
@@ -6586,8 +6909,8 @@
 
         // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
         final ArrayList<String> allowList = new ArrayList<>();
-        mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
-                allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
+                true /* lockdown */, allowList);
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         // This is arguably overspecified: a UID that is not running doesn't have an active network.
@@ -6602,10 +6925,9 @@
                 RESTRICTED_USER_INFO));
         // TODO: check that VPN app within restricted profile still has access, etc.
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-        final Handler handler = new Handler(mCsHandlerThread.getLooper());
-        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
-        waitForIdle();
+        processBroadcastForVpn(addedIntent);
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNull(mCm.getActiveNetworkForUid(restrictedUid));
 
@@ -6614,13 +6936,14 @@
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
         removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-        handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
-        waitForIdle();
+        processBroadcastForVpn(removedIntent);
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
-        mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
+                allowList);
         waitForIdle();
     }
 
@@ -6718,7 +7041,7 @@
         // Ensure VPN is now the active network.
         assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
         // VPN is using Cell
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork() });
         waitForIdle();
 
@@ -6726,7 +7049,7 @@
         assertTrue(mCm.isActiveNetworkMetered());
 
         // VPN is now using WiFi
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mWiFiNetworkAgent.getNetwork() });
         waitForIdle();
 
@@ -6734,7 +7057,7 @@
         assertFalse(mCm.isActiveNetworkMetered());
 
         // VPN is using Cell | WiFi.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
         waitForIdle();
 
@@ -6742,7 +7065,7 @@
         assertTrue(mCm.isActiveNetworkMetered());
 
         // VPN is using WiFi | Cell.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() });
         waitForIdle();
 
@@ -6750,7 +7073,7 @@
         assertTrue(mCm.isActiveNetworkMetered());
 
         // VPN is not using any underlying networks.
-        mService.setUnderlyingNetworksForVpn(new Network[0]);
+        mMockVpn.setUnderlyingNetworks(new Network[0]);
         waitForIdle();
 
         // VPN without underlying networks is treated as metered.
@@ -6777,7 +7100,7 @@
         assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
 
         // VPN is tracking current platform default (WiFi).
-        mService.setUnderlyingNetworksForVpn(null);
+        mMockVpn.setUnderlyingNetworks(null);
         waitForIdle();
 
         // Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
@@ -6785,7 +7108,7 @@
 
 
         // VPN explicitly declares WiFi as its underlying network.
-        mService.setUnderlyingNetworksForVpn(
+        mMockVpn.setUnderlyingNetworks(
                 new Network[] { mWiFiNetworkAgent.getNetwork() });
         waitForIdle();
 
@@ -6809,6 +7132,7 @@
                 .addTransportType(TRANSPORT_CELLULAR)
                 .build();
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+        mockUidNetworkingBlocked();
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
@@ -6891,6 +7215,7 @@
     public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
+        mockUidNetworkingBlocked();
 
         // No Networkcallbacks invoked before any network is active.
         setUidRulesChanged(RULE_REJECT_ALL);
@@ -6994,7 +7319,8 @@
         final int uid = Process.myUid();
         final int userId = UserHandle.getUserId(uid);
         final ArrayList<String> allowList = new ArrayList<>();
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         waitForIdle();
 
         UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
@@ -7016,7 +7342,7 @@
         assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
 
         // Disable lockdown, expect to see the network unblocked.
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
         callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         vpnUidCallback.assertNoCallback();
@@ -7029,7 +7355,8 @@
 
         // Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
         allowList.add(TEST_PACKAGE_NAME);
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         callback.assertNoCallback();
         defaultCallback.assertNoCallback();
         vpnUidCallback.assertNoCallback();
@@ -7062,11 +7389,12 @@
 
         // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
         // Everything should now be blocked.
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
         waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
         allowList.clear();
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
         defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
@@ -7079,7 +7407,7 @@
         assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
 
         // Disable lockdown. Everything is unblocked.
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
         defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
         vpnUidCallback.assertNoCallback();
@@ -7091,7 +7419,8 @@
 
         // Enable and disable an always-on VPN package without lockdown. Expect no changes.
         reset(mMockNetd);
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
+                allowList);
         inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
         callback.assertNoCallback();
         defaultCallback.assertNoCallback();
@@ -7102,7 +7431,7 @@
         assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
 
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
         inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
         callback.assertNoCallback();
         defaultCallback.assertNoCallback();
@@ -7114,7 +7443,8 @@
         assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
 
         // Enable lockdown and connect a VPN. The VPN is not blocked.
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
         vpnUidCallback.assertNoCallback();
@@ -7160,10 +7490,24 @@
         when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
     }
 
+    private void establishLegacyLockdownVpn(Network underlying) throws Exception {
+        // The legacy lockdown VPN only supports userId 0, and must have an underlying network.
+        assertNotNull(underlying);
+        mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
+        // The legacy lockdown VPN only supports userId 0.
+        final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER));
+        mMockVpn.registerAgent(ranges);
+        mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
+        mMockVpn.connect(true);
+    }
+
     @Test
     public void testLegacyLockdownVpn() throws Exception {
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+        // For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
+        mServiceContext.setPermission(
+                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -7172,6 +7516,10 @@
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
+        final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
+        mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+                new Handler(ConnectivityThread.getInstanceLooper()));
+
         // Pretend lockdown VPN was configured.
         setupLegacyLockdownVpn();
 
@@ -7183,10 +7531,9 @@
         // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
         final int userId = UserHandle.getUserId(Process.myUid());
         final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
+        addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        final Handler handler = new Handler(mCsHandlerThread.getLooper());
-        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
-        waitForIdle();
+        processBroadcastForVpn(addedIntent);
 
         // Lockdown VPN disables teardown and enables lockdown.
         assertFalse(mMockVpn.getEnableTeardown());
@@ -7203,6 +7550,7 @@
         mCellNetworkAgent.connect(false /* validated */);
         callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         waitForIdle();
         assertNull(mMockVpn.getAgent());
 
@@ -7214,6 +7562,8 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        systemDefaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
+                mCellNetworkAgent);
         waitForIdle();
         assertNull(mMockVpn.getAgent());
 
@@ -7223,6 +7573,7 @@
         mCellNetworkAgent.disconnect();
         callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         b1.expectBroadcast();
 
         // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
@@ -7232,6 +7583,7 @@
         mCellNetworkAgent.connect(false /* validated */);
         callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         b1.expectBroadcast();
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7254,22 +7606,32 @@
         mMockVpn.expectStartLegacyVpnRunner();
         b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
         ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
-        mMockVpn.establishForMyUid();
+        establishLegacyLockdownVpn(mCellNetworkAgent.getNetwork());
         callback.expectAvailableThenValidatedCallbacks(mMockVpn);
         defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        systemDefaultCallback.assertNoCallback();
+        NetworkCapabilities vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
         b1.expectBroadcast();
         b2.expectBroadcast();
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
         assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
+        assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
+        assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
+        assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
+        assertVpnTransportInfo(vpnNc, VpnManager.TYPE_VPN_LEGACY);
 
         // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
         final LinkProperties wifiLp = new LinkProperties();
         wifiLp.setInterfaceName("wlan0");
         wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
         wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+        final NetworkCapabilities wifiNc = new NetworkCapabilities();
+        wifiNc.addTransportType(TRANSPORT_WIFI);
+        wifiNc.addCapability(NET_CAPABILITY_NOT_METERED);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc);
 
         b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
         // Wifi is CONNECTING because the VPN isn't up yet.
@@ -7287,11 +7649,10 @@
         // fact that a VPN is connected should only result in the VPN itself being unblocked, not
         // any other network. Bug in isUidBlockedByVpn?
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-        callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
         callback.expectCallback(CallbackEntry.LOST, mMockVpn);
-        defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
         defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+        systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
 
         // While the VPN is reconnecting on the new network, everything is blocked.
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7302,26 +7663,27 @@
         // The VPN comes up again on wifi.
         b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
         b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
-        mMockVpn.establishForMyUid();
+        establishLegacyLockdownVpn(mWiFiNetworkAgent.getNetwork());
         callback.expectAvailableThenValidatedCallbacks(mMockVpn);
         defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        systemDefaultCallback.assertNoCallback();
         b1.expectBroadcast();
         b2.expectBroadcast();
-
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
+        assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
+        assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI));
+        assertFalse(vpnNc.hasTransport(TRANSPORT_CELLULAR));
+        assertTrue(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Disconnect cell. Nothing much happens since it's not the default network.
-        // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
-        // NetworkInfo is updated. This is probably a bug.
-        // TODO: consider fixing this.
-        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mCellNetworkAgent.disconnect();
-        b1.expectBroadcast();
         callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         defaultCallback.assertNoCallback();
+        systemDefaultCallback.assertNoCallback();
 
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
@@ -7331,6 +7693,7 @@
         b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         b1.expectBroadcast();
         callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
         b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
@@ -7869,8 +8232,8 @@
         reset(mNetworkManagementService);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_CELLULAR));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final LinkProperties wifiLp = new LinkProperties();
@@ -7878,25 +8241,27 @@
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
 
         // Network switch
-        reset(mNetworkManagementService);
         mWiFiNetworkAgent.connect(true);
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
         networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_WIFI));
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // Disconnect wifi and switch back to cell
-        reset(mNetworkManagementService);
+        reset(mMockNetd);
         mWiFiNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         assertNoCallbacks(networkCallback);
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_CELLULAR));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // reconnect wifi
+        reset(mMockNetd);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
@@ -7904,9 +8269,12 @@
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
         networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // Disconnect cell
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         mCellNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -7914,17 +8282,18 @@
         // sent as network being switched. Ensure rule removal for cell will not be triggered
         // unexpectedly before network being removed.
         waitForIdle();
-        verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
+        verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
         verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
         verify(mMockDnsResolver, times(1))
                 .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
         ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
-        reset(mNetworkManagementService);
         mWiFiNetworkAgent.disconnect();
         b.expectBroadcast();
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
 
         // Clean up
         mCm.unregisterNetworkCallback(networkCallback);
@@ -8045,7 +8414,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -8073,7 +8442,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -8089,7 +8458,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -8104,7 +8473,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -8156,7 +8525,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
+        final UidRange vpnRange = createUidRange(PRIMARY_USER);
         final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8245,7 +8614,8 @@
         when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
 
         if (op != null) {
-            when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+            when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()),
+                    eq(mContext.getPackageName()), eq(getAttributionTag()), anyString()))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         }
 
@@ -8258,7 +8628,7 @@
         final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
 
         return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                netCap, callerUid, mContext.getPackageName()).getOwnerUid();
+                netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
     }
 
     private void verifyWifiInfoCopyNetCapsForCallerPermission(
@@ -8268,7 +8638,7 @@
         final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
 
         mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                netCap, callerUid, mContext.getPackageName());
+                netCap, callerUid, mContext.getPackageName(), getAttributionTag());
         verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
     }
 
@@ -8354,14 +8724,15 @@
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        mMockVpn.setVpnType(vpnType);
         mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
-        mMockVpn.setVpnType(vpnType);
 
         final UnderlyingNetworkInfo underlyingNetworkInfo =
                 new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
         mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
+        when(mDeps.getConnectionOwnerUid(anyInt(), any(), any())).thenReturn(42);
     }
 
     private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -8386,11 +8757,7 @@
         final int myUid = Process.myUid();
         setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_PLATFORM);
 
-        try {
-            mService.getConnectionOwnerUid(getTestConnectionInfo());
-            fail("Expected SecurityException for non-VpnService app");
-        } catch (SecurityException expected) {
-        }
+        assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
     }
 
     @Test
@@ -8398,11 +8765,7 @@
         final int myUid = Process.myUid();
         setupConnectionOwnerUidAsVpnApp(myUid + 1, VpnManager.TYPE_VPN_SERVICE);
 
-        try {
-            mService.getConnectionOwnerUid(getTestConnectionInfo());
-            fail("Expected SecurityException for non-VpnService app");
-        } catch (SecurityException expected) {
-        }
+        assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
     }
 
     @Test
@@ -8410,8 +8773,7 @@
         final int myUid = Process.myUid();
         setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_SERVICE);
 
-        // TODO: Test the returned UID
-        mService.getConnectionOwnerUid(getTestConnectionInfo());
+        assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
     }
 
     @Test
@@ -8421,8 +8783,7 @@
         mServiceContext.setPermission(
                 android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
 
-        // TODO: Test the returned UID
-        mService.getConnectionOwnerUid(getTestConnectionInfo());
+        assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
     }
 
     @Test
@@ -8433,8 +8794,7 @@
         mServiceContext.setPermission(
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED);
 
-        // TODO: Test the returned UID
-        mService.getConnectionOwnerUid(getTestConnectionInfo());
+        assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
     }
 
     private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
@@ -8618,7 +8978,7 @@
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
+        assertTrue(mMockVpn.setUnderlyingNetworks(new Network[] {naiWithoutUid.network}));
         waitForIdle();
         assertTrue(
                 "Active VPN permission not applied",
@@ -8626,7 +8986,7 @@
                         Process.myPid(), Process.myUid(), naiWithoutUid,
                         mContext.getOpPackageName()));
 
-        assertTrue(mService.setUnderlyingNetworksForVpn(null));
+        assertTrue(mMockVpn.setUnderlyingNetworks(null));
         waitForIdle();
         assertFalse(
                 "VPN shouldn't receive callback on non-underlying network",
@@ -8923,7 +9283,7 @@
         lp.setInterfaceName("tun0");
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
-        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
+        final UidRange vpnRange = createUidRange(PRIMARY_USER);
         Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9102,4 +9462,888 @@
         }
         fail("TOO_MANY_REQUESTS never thrown");
     }
+
+    private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid)
+            throws Exception {
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = uid;
+        when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+                .thenReturn(applicationInfo);
+    }
+
+    private void mockHasSystemFeature(@NonNull final String featureName,
+            @NonNull final boolean hasFeature) {
+        when(mPackageManager.hasSystemFeature(eq(featureName)))
+                .thenReturn(hasFeature);
+    }
+
+    private UidRange getNriFirstUidRange(
+            @NonNull final ConnectivityService.NetworkRequestInfo nri) {
+        return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
+    }
+
+    private OemNetworkPreferences createDefaultOemNetworkPreferences(
+            @OemNetworkPreferences.OemNetworkPreference final int preference)
+            throws Exception {
+        // Arrange PackageManager mocks
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+
+        // Build OemNetworkPreferences object
+        return new OemNetworkPreferences.Builder()
+                .addNetworkPreference(TEST_PACKAGE_NAME, preference)
+                .build();
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
+            throws PackageManager.NameNotFoundException {
+        @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
+                OEM_NETWORK_PREFERENCE_UNINITIALIZED;
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.new OemNetworkRequestFactory()
+                        .createNrisFromOemNetworkPreferences(
+                                createDefaultOemNetworkPreferences(prefToTest)));
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryPreferenceOemPaid()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 1;
+        final int expectedNumOfRequests = 3;
+
+        @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory()
+                        .createNrisFromOemNetworkPreferences(
+                                createDefaultOemNetworkPreferences(prefToTest));
+
+        final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+        assertEquals(expectedNumOfNris, nris.size());
+        assertEquals(expectedNumOfRequests, mRequests.size());
+        assertTrue(mRequests.get(0).isListen());
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
+        assertTrue(mRequests.get(1).isRequest());
+        assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
+        assertTrue(mRequests.get(2).isRequest());
+        assertTrue(mService.getDefaultRequest().networkCapabilities.equalsNetCapabilities(
+                mRequests.get(2).networkCapabilities));
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryPreferenceOemPaidNoFallback()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 1;
+        final int expectedNumOfRequests = 2;
+
+        @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory()
+                        .createNrisFromOemNetworkPreferences(
+                                createDefaultOemNetworkPreferences(prefToTest));
+
+        final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+        assertEquals(expectedNumOfNris, nris.size());
+        assertEquals(expectedNumOfRequests, mRequests.size());
+        assertTrue(mRequests.get(0).isListen());
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
+        assertTrue(mRequests.get(1).isRequest());
+        assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryPreferenceOemPaidOnly()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 1;
+        final int expectedNumOfRequests = 1;
+
+        @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory()
+                        .createNrisFromOemNetworkPreferences(
+                                createDefaultOemNetworkPreferences(prefToTest));
+
+        final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+        assertEquals(expectedNumOfNris, nris.size());
+        assertEquals(expectedNumOfRequests, mRequests.size());
+        assertTrue(mRequests.get(0).isRequest());
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryPreferenceOemPrivateOnly()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 1;
+        final int expectedNumOfRequests = 1;
+
+        @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
+                OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory()
+                        .createNrisFromOemNetworkPreferences(
+                                createDefaultOemNetworkPreferences(prefToTest));
+
+        final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+        assertEquals(expectedNumOfNris, nris.size());
+        assertEquals(expectedNumOfRequests, mRequests.size());
+        assertTrue(mRequests.get(0).isRequest());
+        assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PRIVATE));
+        assertFalse(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryCreatesCorrectNumOfNris()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 2;
+
+        // Arrange PackageManager mocks
+        final String testPackageName2 = "com.google.apps.dialer";
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+        mockGetApplicationInfo(testPackageName2, TEST_PACKAGE_UID);
+
+        // Build OemNetworkPreferences object
+        final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
+                .addNetworkPreference(testPackageName2, testOemPref2)
+                .build();
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
+
+        assertNotNull(nris);
+        assertEquals(expectedNumOfNris, nris.size());
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryCorrectlySetsUids()
+            throws Exception {
+        // Arrange PackageManager mocks
+        final String testPackageName2 = "com.google.apps.dialer";
+        final int testPackageNameUid2 = 456;
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+        mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
+
+        // Build OemNetworkPreferences object
+        final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
+                .addNetworkPreference(testPackageName2, testOemPref2)
+                .build();
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final List<ConnectivityService.NetworkRequestInfo> nris =
+                new ArrayList<>(
+                        mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
+                                pref));
+
+        // Sort by uid to access nris by index
+        nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start));
+        assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start);
+        assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop);
+        assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start);
+        assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop);
+    }
+
+    @Test
+    public void testOemNetworkRequestFactoryAddsPackagesToCorrectPreference()
+            throws Exception {
+        // Expectations
+        final int expectedNumOfNris = 1;
+        final int expectedNumOfAppUids = 2;
+
+        // Arrange PackageManager mocks
+        final String testPackageName2 = "com.google.apps.dialer";
+        final int testPackageNameUid2 = 456;
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+        mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
+
+        // Build OemNetworkPreferences object
+        final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
+                .addNetworkPreference(testPackageName2, testOemPref)
+                .build();
+
+        // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+        final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+                mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
+
+        assertEquals(expectedNumOfNris, nris.size());
+        assertEquals(expectedNumOfAppUids,
+                nris.iterator().next().mRequests.get(0).networkCapabilities.getUids().size());
+    }
+
+    @Test
+    public void testSetOemNetworkPreferenceNullListenerAndPrefParamThrowsNpe() {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
+        // Act on ConnectivityService.setOemNetworkPreference()
+        assertThrows(NullPointerException.class,
+                () -> mService.setOemNetworkPreference(
+                        null,
+                        null));
+    }
+
+    @Test
+    public void testSetOemNetworkPreferenceFailsForNonAutomotive()
+            throws Exception {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+
+        // Act on ConnectivityService.setOemNetworkPreference()
+        assertThrows(UnsupportedOperationException.class,
+                () -> mService.setOemNetworkPreference(
+                        createDefaultOemNetworkPreferences(networkPref),
+                        new TestOemListenerCallback()));
+    }
+
+    private void setOemNetworkPreferenceAgentConnected(final int transportType,
+            final boolean connectAgent) throws Exception {
+        switch(transportType) {
+            // Corresponds to a metered cellular network. Will be used for the default network.
+            case TRANSPORT_CELLULAR:
+                if (!connectAgent) {
+                    mCellNetworkAgent.disconnect();
+                    break;
+                }
+                mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+                mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+                mCellNetworkAgent.connect(true);
+                break;
+            // Corresponds to a restricted ethernet network with OEM_PAID/OEM_PRIVATE.
+            case TRANSPORT_ETHERNET:
+                if (!connectAgent) {
+                    stopOemManagedNetwork();
+                    break;
+                }
+                startOemManagedNetwork(true);
+                break;
+            // Corresponds to unmetered Wi-Fi.
+            case TRANSPORT_WIFI:
+                if (!connectAgent) {
+                    mWiFiNetworkAgent.disconnect();
+                    break;
+                }
+                mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+                mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+                mWiFiNetworkAgent.connect(true);
+                break;
+            default:
+                throw new AssertionError("Unsupported transport type passed in.");
+
+        }
+        waitForIdle();
+    }
+
+    private void startOemManagedNetwork(final boolean isOemPaid) throws Exception {
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent.addCapability(
+                isOemPaid ? NET_CAPABILITY_OEM_PAID : NET_CAPABILITY_OEM_PRIVATE);
+        mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+        mEthernetNetworkAgent.connect(true);
+    }
+
+    private void stopOemManagedNetwork() {
+        mEthernetNetworkAgent.disconnect();
+        waitForIdle();
+    }
+
+    private void verifyMultipleDefaultNetworksTracksCorrectly(
+            final int expectedOemRequestsSize,
+            @NonNull final Network expectedDefaultNetwork,
+            @NonNull final Network expectedPerAppNetwork) {
+        // The current test setup assumes two tracked default network requests; one for the default
+        // network and the other for the OEM network preference being tested. This will be validated
+        // each time to confirm it doesn't change under test.
+        final int expectedDefaultNetworkRequestsSize = 2;
+        assertEquals(expectedDefaultNetworkRequestsSize, mService.mDefaultNetworkRequests.size());
+        for (final ConnectivityService.NetworkRequestInfo defaultRequest
+                : mService.mDefaultNetworkRequests) {
+            final Network defaultNetwork = defaultRequest.getSatisfier() == null
+                    ? null : defaultRequest.getSatisfier().network();
+            // If this is the default request.
+            if (defaultRequest == mService.mDefaultRequest) {
+                assertEquals(
+                        expectedDefaultNetwork,
+                        defaultNetwork);
+                // Make sure this value doesn't change.
+                assertEquals(1, defaultRequest.mRequests.size());
+                continue;
+            }
+            assertEquals(expectedPerAppNetwork, defaultNetwork);
+            assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size());
+        }
+    }
+
+    private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
+            throws Exception {
+        final int testPackageNameUid = 123;
+        final String testPackageName = "per.app.defaults.package";
+        setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
+                networkPrefToSetup, testPackageNameUid, testPackageName);
+    }
+
+    private void setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
+            throws Exception {
+        final int testPackageNameUid = Process.myUid();
+        final String testPackageName = "per.app.defaults.package";
+        setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
+                networkPrefToSetup, testPackageNameUid, testPackageName);
+    }
+
+    private void setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+            final int testPackageUid, @NonNull final String testPackageName) throws Exception {
+        // Only the default request should be included at start.
+        assertEquals(1, mService.mDefaultNetworkRequests.size());
+
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageUid));
+        setupSetOemNetworkPreferenceForPreferenceTest(
+                networkPrefToSetup, uidRanges, testPackageName);
+    }
+
+    private void setupSetOemNetworkPreferenceForPreferenceTest(
+            @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+            @NonNull final UidRangeParcel[] uidRanges,
+            @NonNull final String testPackageName)
+            throws Exception {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
+        // These tests work off a single UID therefore using 'start' is valid.
+        mockGetApplicationInfo(testPackageName, uidRanges[0].start);
+
+        // Build OemNetworkPreferences object
+        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+                .addNetworkPreference(testPackageName, networkPrefToSetup)
+                .build();
+
+        // Act on ConnectivityService.setOemNetworkPreference()
+        final TestOemListenerCallback mOnSetOemNetworkPreferenceTestListener =
+                new TestOemListenerCallback();
+        mService.setOemNetworkPreference(pref, mOnSetOemNetworkPreferenceTestListener);
+
+        // Verify call returned successfully
+        mOnSetOemNetworkPreferenceTestListener.expectOnComplete();
+    }
+
+    private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener {
+        final CompletableFuture<Object> mDone = new CompletableFuture<>();
+
+        @Override
+        public void onComplete() {
+            mDone.complete(new Object());
+        }
+
+        void expectOnComplete() throws Exception {
+            try {
+                mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                fail("Expected onComplete() not received after " + TIMEOUT_MS + " ms");
+            }
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testMultiDefaultGetActiveNetworkIsCorrect() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        final int expectedOemPrefRequestSize = 1;
+
+        // Setup the test process to use networkPref for their default network.
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        // The active network for the default should be null at this point as this is a retricted
+        // network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // Verify that the active network is correct
+        verifyActiveNetwork(TRANSPORT_ETHERNET);
+    }
+
+    @Test
+    public void testMultiDefaultIsActiveNetworkMeteredIsCorrect() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        final int expectedOemPrefRequestSize = 1;
+
+        // Setup the test process to use networkPref for their default network.
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+
+        // Returns true by default when no network is available.
+        assertTrue(mCm.isActiveNetworkMetered());
+
+        // Connect to an unmetered restricted network that will only be available to the OEM pref.
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent.addCapability(NET_CAPABILITY_OEM_PAID);
+        mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+        mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+        mEthernetNetworkAgent.connect(true);
+        waitForIdle();
+
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        assertFalse(mCm.isActiveNetworkMetered());
+    }
+
+    @Test
+    public void testPerAppDefaultRegisterDefaultNetworkCallback() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        final int expectedOemPrefRequestSize = 1;
+        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
+
+        // Register the default network callback before the pref is already set. This means that
+        // the policy will be applied to the callback on setOemNetworkPreference().
+        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Setup the test process to use networkPref for their default network.
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        // The active nai for the default is null at this point as this is a restricted network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // At this point with a restricted network used, the available callback should trigger
+        defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Now bring down the default network which should trigger a LOST callback.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+
+        // At this point, with no network is available, the lost callback should trigger
+        defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+
+        // Confirm we can unregister without issues.
+        mCm.unregisterNetworkCallback(defaultNetworkCallback);
+    }
+
+    @Test
+    public void testPerAppDefaultRegisterDefaultNetworkCallbackAfterPrefSet() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        final int expectedOemPrefRequestSize = 1;
+        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
+
+        // Setup the test process to use networkPref for their default network.
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+
+        // Register the default network callback after the pref is already set. This means that
+        // the policy will be applied to the callback on requestNetwork().
+        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        // The active nai for the default is null at this point as this is a restricted network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // At this point with a restricted network used, the available callback should trigger
+        defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Now bring down the default network which should trigger a LOST callback.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+
+        // At this point, with no network is available, the lost callback should trigger
+        defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+
+        // Confirm we can unregister without issues.
+        mCm.unregisterNetworkCallback(defaultNetworkCallback);
+    }
+
+    @Test
+    public void testPerAppDefaultRegisterDefaultNetworkCallbackDoesNotFire() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        final int expectedOemPrefRequestSize = 1;
+        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
+        final int userId = UserHandle.getUserId(Process.myUid());
+
+        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Setup a process different than the test process to use the default network. This means
+        // that the defaultNetworkCallback won't be tracked by the per-app policy.
+        setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        // The active nai for the default is null at this point as this is a restricted network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // As this callback does not have access to the OEM_PAID network, it will not fire.
+        defaultNetworkCallback.assertNoCallback();
+        assertDefaultNetworkCapabilities(userId /* no networks */);
+
+        // Bring up unrestricted cellular. This should now satisfy the default network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // At this point with an unrestricted network used, the available callback should trigger
+        defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
+                mCellNetworkAgent.getNetwork());
+        assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
+
+        // Now bring down the per-app network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+
+        // Since the callback didn't use the per-app network, no callback should fire.
+        defaultNetworkCallback.assertNoCallback();
+
+        // Now bring down the default network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+
+        // As this callback was tracking the default, this should now trigger.
+        defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+
+        // Confirm we can unregister without issues.
+        mCm.unregisterNetworkCallback(defaultNetworkCallback);
+    }
+
+    private void verifySetOemNetworkPreferenceForPreference(
+            @NonNull final UidRangeParcel[] uidRanges,
+            final int addUidRangesNetId,
+            final int addUidRangesTimes,
+            final int removeUidRangesNetId,
+            final int removeUidRangesTimes,
+            final boolean shouldDestroyNetwork) throws RemoteException {
+        final boolean useAnyIdForAdd = OEM_PREF_ANY_NET_ID == addUidRangesNetId;
+        final boolean useAnyIdForRemove = OEM_PREF_ANY_NET_ID == removeUidRangesNetId;
+
+        // Validate netd.
+        verify(mMockNetd, times(addUidRangesTimes))
+                .networkAddUidRanges(
+                        (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(uidRanges));
+        verify(mMockNetd, times(removeUidRangesTimes))
+                .networkRemoveUidRanges(
+                        (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)), eq(uidRanges));
+        if (shouldDestroyNetwork) {
+            verify(mMockNetd, times(1))
+                    .networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
+        }
+        reset(mMockNetd);
+    }
+
+    /**
+     * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
+     * @throws Exception
+     */
+    @Test
+    public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final int testPackageUid = 123;
+        final String testPackageName = "com.google.apps.contacts";
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageUid));
+
+        // Validate the starting requests only includes the fallback request.
+        assertEquals(1, mService.mDefaultNetworkRequests.size());
+
+        // Add an OEM default network request to track.
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
+
+        // Two requests should exist, one for the fallback and one for the pref.
+        assertEquals(2, mService.mDefaultNetworkRequests.size());
+
+        networkPref = OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
+
+        // Two requests should still exist validating the previous per-app request was replaced.
+        assertEquals(2, mService.mDefaultNetworkRequests.size());
+    }
+
+    /**
+     * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID following in order:
+     * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
+     * @throws Exception
+     */
+    @Test
+    public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+
+        // Arrange PackageManager mocks
+        final int testPackageNameUid = 123;
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
+
+        // Verify the starting state. No networks should be connected.
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Disconnecting OEM_PAID should have no effect as it is lower in priority then unmetered.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        // netd should not be called as default networks haven't changed.
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Disconnecting unmetered should put PANS on lowest priority fallback request.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+
+        // Disconnecting the fallback network should result in no connectivity.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                mCellNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK following in order:
+     * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
+     * @throws Exception
+     */
+    @Test
+    public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+
+        // Arrange PackageManager mocks
+        final int testPackageNameUid = 123;
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
+
+        // Verify the starting state. This preference doesn't support using the fallback network
+        // therefore should be on the disconnected network as it has no networks to connect to.
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network.
+        // This preference should not use this network as it doesn't support fallback usage.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Disconnecting unmetered should put PANS on OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+
+        // Disconnecting OEM_PAID should result in no connectivity.
+        // OEM_PAID_NO_FALLBACK not supporting a fallback now uses the disconnected network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY following in order:
+     * NET_CAPABILITY_OEM_PAID
+     * This preference should only apply to OEM_PAID networks.
+     * @throws Exception
+     */
+    @Test
+    public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+
+        // Arrange PackageManager mocks
+        final int testPackageNameUid = 123;
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
+
+        // Verify the starting state. This preference doesn't support using the fallback network
+        // therefore should be on the disconnected network as it has no networks to connect to.
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up metered cellular. This should not apply to this preference.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up unmetered Wi-Fi. This should not apply to this preference.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Disconnecting OEM_PAID should result in no connectivity.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY following in order:
+     * NET_CAPABILITY_OEM_PRIVATE
+     * This preference should only apply to OEM_PRIVATE networks.
+     * @throws Exception
+     */
+    @Test
+    public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+
+        // Arrange PackageManager mocks
+        final int testPackageNameUid = 123;
+        final UidRangeParcel[] uidRanges =
+                toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+        setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
+
+        // Verify the starting state. This preference doesn't support using the fallback network
+        // therefore should be on the disconnected network as it has no networks to connect to.
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up metered cellular. This should not apply to this preference.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up unmetered Wi-Fi. This should not apply to this preference.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
+        startOemManagedNetwork(false);
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Disconnecting OEM_PRIVATE should result in no connectivity.
+        stopOemManagedNetwork();
+        verifySetOemNetworkPreferenceForPreference(uidRanges,
+                mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
+                mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
+                true /* shouldDestroyNetwork */);
+    }
+
+    private UidRange createUidRange(int userId) {
+        return UidRange.createForUser(UserHandle.of(userId));
+    }
 }
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 799bcc8..32c95f1 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -16,12 +16,16 @@
 
 package com.android.server;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -33,8 +37,10 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.InetAddresses;
+import android.net.InterfaceConfigurationParcel;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecConfig;
 import android.net.IpSecManager;
@@ -44,15 +50,17 @@
 import android.net.IpSecTunnelInterfaceResponse;
 import android.net.IpSecUdpEncapResponse;
 import android.net.LinkAddress;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.os.Binder;
-import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
 import android.system.Os;
 import android.test.mock.MockContext;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.IpSecService.TunnelInterfaceRecord;
+
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -109,6 +117,7 @@
     };
 
     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+    ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
 
     MockContext mMockContext = new MockContext() {
         @Override
@@ -116,12 +125,22 @@
             switch(name) {
                 case Context.APP_OPS_SERVICE:
                     return mMockAppOps;
+                case Context.CONNECTIVITY_SERVICE:
+                    return mMockConnectivityMgr;
                 default:
                     return null;
             }
         }
 
         @Override
+        public String getSystemServiceName(Class<?> serviceClass) {
+            if (ConnectivityManager.class == serviceClass) {
+                return Context.CONNECTIVITY_SERVICE;
+            }
+            return null;
+        }
+
+        @Override
         public PackageManager getPackageManager() {
             return mMockPkgMgr;
         }
@@ -133,10 +152,17 @@
             }
             throw new SecurityException("Unavailable permission requested");
         }
+
+        @Override
+        public int checkCallingOrSelfPermission(String permission) {
+            if (android.Manifest.permission.NETWORK_STACK.equals(permission)) {
+                return PERMISSION_GRANTED;
+            }
+            throw new UnsupportedOperationException();
+        }
     };
 
     INetd mMockNetd;
-    INetworkManagementService mNetworkManager;
     PackageManager mMockPkgMgr;
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
@@ -151,6 +177,10 @@
             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
     private static final int REMOTE_ENCAP_PORT = 4500;
 
+    private static final String BLESSED_PACKAGE = "blessedPackage";
+    private static final String SYSTEM_PACKAGE = "systemPackage";
+    private static final String BAD_PACKAGE = "badPackage";
+
     public IpSecServiceParameterizedTest(
             String sourceAddr, String destAddr, String localInnerAddr, int family) {
         mSourceAddr = sourceAddr;
@@ -162,10 +192,9 @@
     @Before
     public void setUp() throws Exception {
         mMockNetd = mock(INetd.class);
-        mNetworkManager = mock(INetworkManagementService.class);
         mMockPkgMgr = mock(PackageManager.class);
         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
-        mIpSecService = new IpSecService(mMockContext, mNetworkManager, mMockIpSecSrvConfig);
+        mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
 
         // Injecting mock netd
         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -174,15 +203,15 @@
         when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
 
         // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
-        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
-            .thenReturn(AppOpsManager.MODE_ALLOWED);
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
+                .thenReturn(AppOpsManager.MODE_ALLOWED);
         // A system package will not be granted the app op, so this should fall back to
         // a permissions check, which should pass.
-        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
-            .thenReturn(AppOpsManager.MODE_DEFAULT);
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
+                .thenReturn(AppOpsManager.MODE_DEFAULT);
         // A mismatch between the package name and the UID will return MODE_IGNORED.
-        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
-            .thenReturn(AppOpsManager.MODE_IGNORED);
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
+                .thenReturn(AppOpsManager.MODE_IGNORED);
     }
 
     //TODO: Add a test to verify SPI.
@@ -338,7 +367,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -352,7 +381,7 @@
         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -370,14 +399,14 @@
 
         if (mFamily == AF_INET) {
             IpSecTransformResponse createTransformResp =
-                    mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                    mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
         } else {
             try {
                 IpSecTransformResponse createTransformResp =
-                        mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                        mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
             } catch (IllegalArgumentException expected) {
             }
@@ -396,14 +425,14 @@
 
         if (mFamily == AF_INET) {
             IpSecTransformResponse createTransformResp =
-                    mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                    mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
             assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
             verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
         } else {
             try {
                 IpSecTransformResponse createTransformResp =
-                        mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                        mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                 fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
             } catch (IllegalArgumentException expected) {
             }
@@ -417,12 +446,12 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         // Attempting to create transform a second time with the same SPIs should throw an error...
         try {
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+            mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                 fail("IpSecService should have thrown an error for reuse of SPI");
         } catch (IllegalStateException expected) {
         }
@@ -430,7 +459,7 @@
         // ... even if the transform is deleted
         mIpSecService.deleteTransform(createTransformResp.resourceId);
         try {
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+            mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
                 fail("IpSecService should have thrown an error for reuse of SPI");
         } catch (IllegalStateException expected) {
         }
@@ -443,7 +472,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -467,7 +496,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         mIpSecService.deleteTransform(createTransformResp.resourceId);
 
         verify(mMockNetd, times(1))
@@ -515,7 +544,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
 
         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
@@ -562,7 +591,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
 
         if (closeSpiBeforeApply) {
             mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -592,7 +621,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
 
         // Close SPI record
         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -625,7 +654,10 @@
     }
 
     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
-            String localAddr, String remoteAddr, String pkgName) {
+            String localAddr, String remoteAddr, String pkgName) throws Exception {
+        final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
+        config.flags = new String[] {IF_STATE_DOWN};
+        when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config);
         IpSecTunnelInterfaceResponse createTunnelResp =
                 mIpSecService.createTunnelInterface(
                         mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
@@ -638,7 +670,7 @@
     @Test
     public void testCreateTunnelInterface() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
 
         // Check that we have stored the tracking object, and retrieve it
         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
@@ -655,17 +687,18 @@
                         anyInt(),
                         anyInt(),
                         anyInt());
-        verify(mNetworkManager).setInterfaceUp(createTunnelResp.interfaceName);
+        verify(mMockNetd).interfaceSetCfg(argThat(
+                config -> Arrays.asList(config.flags).contains(IF_STATE_UP)));
     }
 
     @Test
     public void testDeleteTunnelInterface() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
 
         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
 
-        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
+        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -678,10 +711,73 @@
         }
     }
 
+    private Network createFakeUnderlyingNetwork(String interfaceName) {
+        final Network fakeNetwork = new Network(1000);
+        final LinkProperties fakeLp = new LinkProperties();
+        fakeLp.setInterfaceName(interfaceName);
+        when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
+        return fakeNetwork;
+    }
+
+    @Test
+    public void testSetNetworkForTunnelInterface() throws Exception {
+        final IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+        final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
+        final int tunnelIfaceResourceId = createTunnelResp.resourceId;
+        mIpSecService.setNetworkForTunnelInterface(
+                tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
+
+        final IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(mUid);
+        assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
+
+        final TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
+        assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
+    }
+
+    @Test
+    public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
+        final IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+        final Network newFakeNetwork = new Network(1000);
+
+        try {
+            mIpSecService.setNetworkForTunnelInterface(
+                    IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
+            fail("Expected an IllegalArgumentException for invalid resource ID.");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
+        final IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+        final int tunnelIfaceResourceId = createTunnelResp.resourceId;
+        final IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(mUid);
+        final TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
+
+        final Network newFakeNetwork =
+                createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());
+
+        try {
+            mIpSecService.setNetworkForTunnelInterface(
+                    tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
+            fail(
+                    "Expected an IllegalArgumentException because the underlying network is the"
+                            + " network being exposed by this tunnel.");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
     @Test
     public void testTunnelInterfaceBinderDeath() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
 
         IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
@@ -718,9 +814,9 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
 
         if (closeSpiBeforeApply) {
             mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -728,8 +824,8 @@
 
         int transformResourceId = createTransformResp.resourceId;
         int tunnelResourceId = createTunnelResp.resourceId;
-        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
-                transformResourceId, "blessedPackage");
+        mIpSecService.applyTunnelModeTransform(
+                tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
 
         for (int selAddrFamily : ADDRESS_FAMILIES) {
             verify(mMockNetd)
@@ -758,17 +854,17 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+                mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
 
         // Close SPI record
         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
 
         int transformResourceId = createTransformResp.resourceId;
         int tunnelResourceId = createTunnelResp.resourceId;
-        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
-                transformResourceId, "blessedPackage");
+        mIpSecService.applyTunnelModeTransform(
+                tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
 
         for (int selAddrFamily : ADDRESS_FAMILIES) {
             verify(mMockNetd)
@@ -790,7 +886,7 @@
 
     @Test
     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
-        for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+        for (String pkgName : new String[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
             IpSecTunnelInterfaceResponse createTunnelResp =
                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
             mIpSecService.addAddressToTunnelInterface(
@@ -816,7 +912,7 @@
     public void testAddTunnelFailsForBadPackageName() throws Exception {
         try {
             IpSecTunnelInterfaceResponse createTunnelResp =
-                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
             fail("Expected a SecurityException for badPackage.");
         } catch (SecurityException expected) {
         }
@@ -830,7 +926,7 @@
         try {
             String addr = Inet4Address.getLoopbackAddress().getHostAddress();
             mIpSecService.createTunnelInterface(
-                    addr, addr, new Network(0), new Binder(), "blessedPackage");
+                    addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
             fail("Expected UnsupportedOperationException for disabled feature");
         } catch (UnsupportedOperationException expected) {
         }
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 788e4ef..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -31,7 +31,6 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
@@ -62,8 +61,7 @@
     public void setUp() throws Exception {
         mMockContext = mock(Context.class);
         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
-        mIpSecService = new IpSecService(
-                mMockContext, mock(INetworkManagementService.class), mMockIpSecSrvConfig);
+        mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
     }
 
     private void assertResourceState(
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 536e983..f97eabf 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -42,7 +42,6 @@
 import android.net.IpSecSpiResponse;
 import android.net.IpSecUdpEncapResponse;
 import android.os.Binder;
-import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.system.ErrnoException;
@@ -116,7 +115,6 @@
     }
 
     Context mMockContext;
-    INetworkManagementService mMockNetworkManager;
     INetd mMockNetd;
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
@@ -124,10 +122,9 @@
     @Before
     public void setUp() throws Exception {
         mMockContext = mock(Context.class);
-        mMockNetworkManager = mock(INetworkManagementService.class);
         mMockNetd = mock(INetd.class);
         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
-        mIpSecService = new IpSecService(mMockContext, mMockNetworkManager, mMockIpSecSrvConfig);
+        mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
 
         // Injecting mock netd
         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -135,7 +132,7 @@
 
     @Test
     public void testIpSecServiceCreate() throws InterruptedException {
-        IpSecService ipSecSrv = IpSecService.create(mMockContext, mMockNetworkManager);
+        IpSecService ipSecSrv = IpSecService.create(mMockContext);
         assertNotNull(ipSecSrv);
     }
 
@@ -608,7 +605,7 @@
     public void testOpenUdpEncapSocketTagsSocket() throws Exception {
         IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
         IpSecService testIpSecService = new IpSecService(
-                mMockContext, mMockNetworkManager, mMockIpSecSrvConfig, mockTagger);
+                mMockContext, mMockIpSecSrvConfig, mockTagger);
 
         IpSecUdpEncapResponse udpEncapResp =
                 testIpSecService.openUdpEncapsulationSocket(0, new Binder());
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index e590fb7..a10a3c8 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -55,7 +55,7 @@
     private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
 
     private val mMockService = mock(ConnectivityService::class.java).apply {
-        doReturn(false).`when`(this).isFallbackNetwork(any())
+        doReturn(false).`when`(this).isDefaultNetwork(any())
     }
     private val mTracker = LegacyTypeTracker(mMockService).apply {
         supportedTypes.forEach {
@@ -126,11 +126,11 @@
     fun testBroadcastOnDisconnect() {
         val mobileNai1 = mock(NetworkAgentInfo::class.java)
         val mobileNai2 = mock(NetworkAgentInfo::class.java)
-        doReturn(false).`when`(mMockService).isFallbackNetwork(mobileNai1)
+        doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
         mTracker.add(TYPE_MOBILE, mobileNai1)
         verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
         reset(mMockService)
-        doReturn(false).`when`(mMockService).isFallbackNetwork(mobileNai2)
+        doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
         mTracker.add(TYPE_MOBILE, mobileNai2)
         verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
         mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index b47be97..ff8c632 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -46,7 +46,10 @@
 import com.android.internal.R;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.AdditionalAnswers;
@@ -63,6 +66,8 @@
 @SmallTest
 public class NetworkNotificationManagerTest {
 
+    private static final String TEST_SSID = "Test SSID";
+    private static final String TEST_EXTRA_INFO = "extra";
     static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
     static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
     static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
@@ -72,6 +77,7 @@
 
         WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        WIFI_CAPABILITIES.setSSID(TEST_SSID);
 
         // Set the underyling network to wifi.
         VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
@@ -112,7 +118,7 @@
         when(mCtx.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
         when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);
-        when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
+        when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
         when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
 
         mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
@@ -125,11 +131,11 @@
                 .notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
         final int transportType = NetworkNotificationManager.approximateTransportType(nai);
         if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
-            verify(mResources, times(1)).getString(title, eq(any()));
+            verify(mResources, times(1)).getString(eq(title), eq(TEST_EXTRA_INFO));
         } else {
             verify(mResources, times(1)).getString(title);
         }
-        verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+        verify(mResources, times(1)).getString(eq(R.string.private_dns_broken_detailed));
     }
 
     @Test
@@ -178,6 +184,9 @@
     }
 
     @Test
+    @Ignore
+    // Ignored because the code under test calls Log.wtf, which crashes the tests on eng builds.
+    // TODO: re-enable after fixing this (e.g., turn Log.wtf into exceptions that this test catches)
     public void testNoInternetNotificationsNotShownForCellular() {
         mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
         mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 3556c72..e4e24b4 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -61,6 +61,7 @@
 import android.net.INetd;
 import android.net.UidRange;
 import android.os.Build;
+import android.os.SystemConfigManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.SparseIntArray;
@@ -89,8 +90,8 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PermissionMonitorTest {
-    private static final int MOCK_USER1 = 0;
-    private static final int MOCK_USER2 = 1;
+    private static final UserHandle MOCK_USER1 = UserHandle.of(0);
+    private static final UserHandle MOCK_USER2 = UserHandle.of(1);
     private static final int MOCK_UID1 = 10001;
     private static final int MOCK_UID2 = 10086;
     private static final int SYSTEM_UID1 = 1000;
@@ -114,6 +115,7 @@
     @Mock private PackageManagerInternal mMockPmi;
     @Mock private UserManager mUserManager;
     @Mock private PermissionMonitor.Dependencies mDeps;
+    @Mock private SystemConfigManager mSystemConfigManager;
 
     private PermissionMonitor mPermissionMonitor;
 
@@ -123,10 +125,12 @@
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
         when(mUserManager.getUserHandles(eq(true))).thenReturn(
-                Arrays.asList(new UserHandle[] {
-                        new UserHandle(MOCK_USER1),
-                        new UserHandle(MOCK_USER2),
-                }));
+                Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
+        when(mContext.getSystemServiceName(SystemConfigManager.class))
+                .thenReturn(Context.SYSTEM_CONFIG_SERVICE);
+        when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
+                .thenReturn(mSystemConfigManager);
+        when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
 
         mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
 
@@ -184,7 +188,8 @@
         return packageInfo;
     }
 
-    private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
+    private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid,
+            UserHandle user) {
         final PackageInfo pkgInfo;
         if (hasSystemPermission) {
             pkgInfo = systemPackageInfoWithPermissions(
@@ -192,7 +197,7 @@
         } else {
             pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
         }
-        pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+        pkgInfo.applicationInfo.uid = UserHandle.getUid(user, UserHandle.getAppId(uid));
         return pkgInfo;
     }
 
@@ -382,8 +387,8 @@
             }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
         }
 
-        public void expectPermission(Boolean permission, int[] users, int[] apps) {
-            for (final int user : users) {
+        public void expectPermission(Boolean permission, UserHandle[] users, int[] apps) {
+            for (final UserHandle user : users) {
                 for (final int app : apps) {
                     final int uid = UserHandle.getUid(user, app);
                     if (!mApps.containsKey(uid)) {
@@ -396,8 +401,8 @@
             }
         }
 
-        public void expectNoPermission(int[] users, int[] apps) {
-            for (final int user : users) {
+        public void expectNoPermission(UserHandle[] users, int[] apps) {
+            for (final UserHandle user : users) {
                 for (final int app : apps) {
                     final int uid = UserHandle.getUid(user, app);
                     if (mApps.containsKey(uid)) {
@@ -425,46 +430,48 @@
 
         // Add SYSTEM_PACKAGE2, expect only have network permission.
         mPermissionMonitor.onUserAdded(MOCK_USER1);
-        addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
+        mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
 
         // Add SYSTEM_PACKAGE1, expect permission escalate.
-        addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
-        mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+        addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
+        mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
 
         mPermissionMonitor.onUserAdded(MOCK_USER2);
-        mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+        mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID});
 
-        addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+        addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
+        mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID});
-        mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+        mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{MOCK_UID1});
 
         // Remove MOCK_UID1, expect no permission left for all user.
         mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
-        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
-        mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
+        removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
+        mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                new int[]{MOCK_UID1});
 
         // Remove SYSTEM_PACKAGE1, expect permission downgrade.
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
-        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID);
-        mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+        removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+                SYSTEM_PACKAGE1, SYSTEM_UID);
+        mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID});
 
         mPermissionMonitor.onUserRemoved(MOCK_USER1);
-        mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
+        mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER2}, new int[]{SYSTEM_UID});
 
         // Remove all packages, expect no permission left.
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
-        removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
-        mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+        removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
+        mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID, MOCK_UID1});
 
         // Remove last user, expect no redundant clearPermission is invoked.
         mPermissionMonitor.onUserRemoved(MOCK_USER2);
-        mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+        mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID, MOCK_UID1});
     }
 
@@ -548,14 +555,14 @@
     // Normal package add/remove operations will trigger multiple intent for uids corresponding to
     // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
     // called multiple times with the uid corresponding to each user.
-    private void addPackageForUsers(int[] users, String packageName, int uid) {
-        for (final int user : users) {
+    private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
+        for (final UserHandle user : users) {
             mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
         }
     }
 
-    private void removePackageForUsers(int[] users, String packageName, int uid) {
-        for (final int user : users) {
+    private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
+        for (final UserHandle user : users) {
             mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid));
         }
     }
@@ -747,4 +754,20 @@
                 GET_PERMISSIONS | MATCH_ANY_USER);
         assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
     }
+
+    @Test
+    public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
+        final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
+        when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
+                .thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
+        when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS)))
+                .thenReturn(new int[]{ MOCK_UID2 });
+
+        mPermissionMonitor.startMonitoring();
+        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 });
+        mNetdServiceMonitor.expectPermission(
+                INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+                new int[]{ MOCK_UID2 });
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f478282..7489a0f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,10 +21,13 @@
 import static android.content.pm.UserInfo.FLAG_PRIMARY;
 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
 import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -49,6 +52,7 @@
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -60,6 +64,7 @@
 import android.net.INetd;
 import android.net.Ikev2VpnProfile;
 import android.net.InetAddresses;
+import android.net.InterfaceConfigurationParcel;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
 import android.net.IpSecTunnelInterfaceResponse;
@@ -73,6 +78,7 @@
 import android.net.UidRangeParcel;
 import android.net.VpnManager;
 import android.net.VpnService;
+import android.net.VpnTransportInfo;
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
 import android.os.Build.VERSION_CODES;
@@ -119,6 +125,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -175,7 +182,8 @@
             mPackages.put(PKGS[i], PKG_UIDS[i]);
         }
     }
-    private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id);
+    private static final UidRange PRI_USER_RANGE =
+            UidRange.createForUser(UserHandle.of(primaryUser.id));
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
     @Mock private UserManager mUserManager;
@@ -213,6 +221,8 @@
 
         when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
         when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
+        when(mContext.getSystemServiceName(UserManager.class))
+                .thenReturn(Context.USER_SERVICE);
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
         when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
         when(mContext.getSystemServiceName(NotificationManager.class))
@@ -253,21 +263,22 @@
 
     @Test
     public void testRestrictedProfilesAreAddedToVpn() {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
 
         final Vpn vpn = createVpn(primaryUser.id);
-        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
-                null, null);
+
+        // Assume the user can have restricted profiles.
+        doReturn(true).when(mUserManager).canHaveRestrictedProfile();
+        final Set<UidRange> ranges =
+                vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
 
         assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-                PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id)
+                PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
         })), ranges);
     }
 
     @Test
     public void testManagedProfilesAreNotAddedToVpn() {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         setMockedUsers(primaryUser, managedProfileA);
 
         final Vpn vpn = createVpn(primaryUser.id);
@@ -290,7 +301,6 @@
 
     @Test
     public void testUidAllowAndDenylist() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -316,7 +326,6 @@
 
     @Test
     public void testGetAlwaysAndOnGetLockDown() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
 
         // Default state.
@@ -341,7 +350,6 @@
 
     @Test
     public void testLockdownChangingPackage() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
 
@@ -369,7 +377,6 @@
 
     @Test
     public void testLockdownAllowlist() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
 
@@ -444,7 +451,6 @@
 
     @Test
     public void testLockdownRuleRepeatability() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
                 new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
@@ -477,7 +483,6 @@
 
     @Test
     public void testLockdownRuleReversibility() throws Exception {
-        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] entireUser = {
             new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
@@ -871,17 +876,28 @@
                         eq(AppOpsManager.MODE_IGNORED));
     }
 
-    private NetworkCallback triggerOnAvailableAndGetCallback() {
+    private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
         final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
                 ArgumentCaptor.forClass(NetworkCallback.class);
         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
                 .requestNetwork(any(), networkCallbackCaptor.capture());
 
+        // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
+        // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
+        final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
+        config.flags = new String[] {IF_STATE_DOWN};
+        when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
         final NetworkCallback cb = networkCallbackCaptor.getValue();
         cb.onAvailable(TEST_NETWORK);
         return cb;
     }
 
+    private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
+        // Add a timeout for waiting for interfaceSetCfg to be called.
+        verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
+                config -> Arrays.asList(config.flags).contains(flag)));
+    }
+
     @Test
     public void testStartPlatformVpnAuthenticationFailed() throws Exception {
         final ArgumentCaptor<IkeSessionCallback> captor =
@@ -893,6 +909,8 @@
         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
 
+        verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
         // state
         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
@@ -911,6 +929,8 @@
         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
 
+        verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
         // state
         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
@@ -985,6 +1005,13 @@
         startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
     }
 
+    private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
+        assertNotNull(nc);
+        VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
+        assertNotNull(ti);
+        assertEquals(type, ti.type);
+    }
+
     public void startRacoon(final String serverAddr, final String expectedAddr)
             throws Exception {
         final ConditionVariable legacyRunnerReady = new ConditionVariable();
@@ -997,14 +1024,12 @@
         profile.ipsecIdentifier = "id";
         profile.ipsecSecret = "secret";
         profile.l2tpSecret = "l2tpsecret";
+
         when(mConnectivityManager.getAllNetworks())
             .thenReturn(new Network[] { new Network(101) });
+
         when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
-                anyInt(), any(), anyInt())).thenAnswer(invocation -> {
-                    // The runner has registered an agent and is now ready.
-                    legacyRunnerReady.open();
-                    return new Network(102);
-                });
+                anyInt(), any(), anyInt())).thenReturn(new Network(102));
         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
         final TestDeps deps = (TestDeps) vpn.mDeps;
         try {
@@ -1020,14 +1045,24 @@
                             "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
                             "idle", "1800", "mtu", "1270", "mru", "1270" },
                     deps.mtpdArgs.get(10, TimeUnit.SECONDS));
+
             // Now wait for the runner to be ready before testing for the route.
-            legacyRunnerReady.block(10_000);
-            // In this test the expected address is always v4 so /32
+            ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
+            ArgumentCaptor<NetworkCapabilities> ncCaptor =
+                    ArgumentCaptor.forClass(NetworkCapabilities.class);
+            verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
+                    lpCaptor.capture(), ncCaptor.capture(), anyInt(), any(), anyInt());
+
+            // In this test the expected address is always v4 so /32.
+            // Note that the interface needs to be specified because RouteInfo objects stored in
+            // LinkProperties objects always acquire the LinkProperties' interface.
             final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
-                    RouteInfo.RTN_THROW);
-            assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : "
-                    + vpn.mConfig.routes,
-                    vpn.mConfig.routes.contains(expectedRoute));
+                    null, EGRESS_IFACE, RouteInfo.RTN_THROW);
+            final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
+            assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
+                    actualRoutes.contains(expectedRoute));
+
+            assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
         } finally {
             // Now interrupt the thread, unblock the runner and clean up.
             vpn.mVpnRunner.exitVpnRunner();
@@ -1083,6 +1118,11 @@
         }
 
         @Override
+        public PendingIntent getIntentForStatusPanel(Context context) {
+            return null;
+        }
+
+        @Override
         public void sendArgumentsToDaemon(
                 final String daemon, final LocalSocket socket, final String[] arguments,
                 final Vpn.RetryScheduler interruptChecker) throws IOException {
@@ -1179,11 +1219,6 @@
             final int id = (int) invocation.getArguments()[0];
             return userMap.get(id);
         }).when(mUserManager).getUserInfo(anyInt());
-
-        doAnswer(invocation -> {
-            final int id = (int) invocation.getArguments()[0];
-            return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
-        }).when(mUserManager).canHaveRestrictedProfile();
     }
 
     /**
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index dde78aa..d644739 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -80,8 +80,6 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
@@ -1456,8 +1454,6 @@
     }
 
     private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
-        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1465,7 +1461,7 @@
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         capabilities.setSSID(TEST_SSID);
-        return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
+        return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null);
     }
 
     private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1473,17 +1469,13 @@
     }
 
     private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
-        final NetworkInfo info = new NetworkInfo(
-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
-        info.setRoaming(isRoaming);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
+        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
     }
 
     private NetworkStats buildEmptyStats() {
@@ -1491,11 +1483,9 @@
     }
 
     private static NetworkState buildVpnState() {
-        final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TUN_IFACE);
-        return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+        return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
     }
 
     private long getElapsedRealtime() {
diff --git a/tests/net/jni/Android.bp b/tests/net/jni/Android.bp
index 9225ffb..22a04f5 100644
--- a/tests/net/jni/Android.bp
+++ b/tests/net/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: "libnetworkstatsfactorytestjni",
 
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
index 84ae2b5..1535f3d 100644
--- a/tests/net/smoketest/Android.bp
+++ b/tests/net/smoketest/Android.bp
@@ -9,6 +9,15 @@
 //
 // TODO: remove this hack when there is a better solution for jni_libs that includes
 // dependent libraries.
+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: "FrameworksNetSmokeTests",
     defaults: ["FrameworksNetTests-jni-defaults"],
@@ -19,4 +28,4 @@
         "mockito-target-minus-junit4",
         "services.core",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/notification/Android.bp b/tests/notification/Android.bp
index f05edaf..1c1b5a2 100644
--- a/tests/notification/Android.bp
+++ b/tests/notification/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: "NotificationTests",
     // Include all test java files.
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index bd07009..bbc2358 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/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: "FrameworkPermissionTests",
     // Include all test java files.
diff --git a/tests/privapp-permissions/Android.bp b/tests/privapp-permissions/Android.bp
index b661850..082b08dea 100644
--- a/tests/privapp-permissions/Android.bp
+++ b/tests/privapp-permissions/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_app {
     name: "PrivAppPermissionTest",
     sdk_version: "current",
diff --git a/tests/testables/Android.bp b/tests/testables/Android.bp
index eb6811c..c0e3d63 100644
--- a/tests/testables/Android.bp
+++ b/tests/testables/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_library {
     name: "testables",
     srcs: ["src/**/*.java"],
diff --git a/tests/testables/tests/Android.bp b/tests/testables/tests/Android.bp
index e1a58be..ba323d3 100644
--- a/tests/testables/tests/Android.bp
+++ b/tests/testables/tests/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: "TestablesTests",
     platform_apis: true,
diff --git a/tests/utils/StubIME/Android.bp b/tests/utils/StubIME/Android.bp
index 668c92c..d86068c 100644
--- a/tests/utils/StubIME/Android.bp
+++ b/tests/utils/StubIME/Android.bp
@@ -14,6 +14,15 @@
 // 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: "StubIME",
     srcs: ["src/**/*.java"],
diff --git a/tests/utils/hostutils/Android.bp b/tests/utils/hostutils/Android.bp
index c9ad702..05f3c74 100644
--- a/tests/utils/hostutils/Android.bp
+++ b/tests/utils/hostutils/Android.bp
@@ -13,6 +13,15 @@
 // 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"],
+}
+
 java_library_host {
     name: "frameworks-base-hostutils",
 
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index a6625ab..af9786b 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 java_library {
     name: "frameworks-base-testutils",
 
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 1102624..4a1f96d 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -42,6 +42,8 @@
 
     private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
 
+    private boolean mUseRegisteredHandlers;
+
     public abstract class FutureIntent extends FutureTask<Intent> {
         public FutureIntent() {
             super(
@@ -61,17 +63,24 @@
     public class BroadcastInterceptor extends FutureIntent {
         private final BroadcastReceiver mReceiver;
         private final IntentFilter mFilter;
+        private final Handler mHandler;
 
-        public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter) {
+        public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter,
+                Handler handler) {
             mReceiver = receiver;
             mFilter = filter;
+            mHandler = mUseRegisteredHandlers ? handler : null;
         }
 
         public boolean dispatchBroadcast(Intent intent) {
             if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
                 if (mReceiver != null) {
                     final Context context = BroadcastInterceptingContext.this;
-                    mReceiver.onReceive(context, intent);
+                    if (mHandler == null) {
+                        mReceiver.onReceive(context, intent);
+                    } else {
+                        mHandler.post(() -> mReceiver.onReceive(context, intent));
+                    }
                     return false;
                 } else {
                     set(intent);
@@ -116,25 +125,38 @@
     }
 
     public FutureIntent nextBroadcastIntent(IntentFilter filter) {
-        final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
+        final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter, null);
         synchronized (mInterceptors) {
             mInterceptors.add(interceptor);
         }
         return interceptor;
     }
 
+    /**
+     * Whether to send broadcasts to registered handlers. By default, receivers are called
+     * synchronously by sendBroadcast. If this method is called with {@code true}, the receiver is
+     * instead called by a runnable posted to the Handler specified when the receiver was
+     * registered. This method applies only to future registrations, already-registered receivers
+     * are unaffected.
+     */
+    public void setUseRegisteredHandlers(boolean use) {
+        synchronized (mInterceptors) {
+            mUseRegisteredHandlers = use;
+        }
+    }
+
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-        synchronized (mInterceptors) {
-            mInterceptors.add(new BroadcastInterceptor(receiver, filter));
-        }
-        return null;
+        return registerReceiver(receiver, filter, null, null);
     }
 
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
             String broadcastPermission, Handler scheduler) {
-        return registerReceiver(receiver, filter);
+        synchronized (mInterceptors) {
+            mInterceptors.add(new BroadcastInterceptor(receiver, filter, scheduler));
+        }
+        return null;
     }
 
     @Override
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index c04ddd7..41f73cd 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -2,6 +2,15 @@
 // Build FrameworksVcnTests package
 //########################################################################
 
+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: "FrameworksVcnTests",
     srcs: [
@@ -21,7 +30,6 @@
         "services.core",
     ],
     libs: [
-        "android.net.ipsec.ike.stubs.module_lib",
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
diff --git a/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
new file mode 100644
index 0000000..36f5e41
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.net.vcn;
+
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.SaProposal;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnControlPlaneIkeConfigTest {
+    private static final IkeSessionParams IKE_PARAMS;
+    private static final TunnelModeChildSessionParams CHILD_PARAMS;
+
+    static {
+        IkeSaProposal ikeProposal =
+                new IkeSaProposal.Builder()
+                        .addEncryptionAlgorithm(
+                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+                        .addDhGroup(DH_GROUP_2048_BIT_MODP)
+                        .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC)
+                        .build();
+
+        Context mockContext = mock(Context.class);
+        ConnectivityManager mockConnectManager = mock(ConnectivityManager.class);
+        doReturn(mockConnectManager)
+                .when(mockContext)
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        doReturn(mock(Network.class)).when(mockConnectManager).getActiveNetwork();
+
+        final String serverHostname = "192.0.2.100";
+        final String testLocalId = "test.client.com";
+        final String testRemoteId = "test.server.com";
+        final byte[] psk = "psk".getBytes();
+
+        IKE_PARAMS =
+                new IkeSessionParams.Builder(mockContext)
+                        .setServerHostname(serverHostname)
+                        .addSaProposal(ikeProposal)
+                        .setLocalIdentification(new IkeFqdnIdentification(testLocalId))
+                        .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId))
+                        .setAuthPsk(psk)
+                        .build();
+
+        ChildSaProposal childProposal =
+                new ChildSaProposal.Builder()
+                        .addEncryptionAlgorithm(
+                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+                        .build();
+        CHILD_PARAMS =
+                new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build();
+    }
+
+    // Package private for use in VcnGatewayConnectionConfigTest
+    static VcnControlPlaneIkeConfig buildTestConfig() {
+        return new VcnControlPlaneIkeConfig(IKE_PARAMS, CHILD_PARAMS);
+    }
+
+    @Test
+    public void testGetters() {
+        final VcnControlPlaneIkeConfig config = buildTestConfig();
+        assertEquals(IKE_PARAMS, config.getIkeSessionParams());
+        assertEquals(CHILD_PARAMS, config.getChildSessionParams());
+    }
+
+    @Test
+    public void testConstructConfigWithoutIkeParams() {
+        try {
+            new VcnControlPlaneIkeConfig(null, CHILD_PARAMS);
+            fail("Expect to fail because ikeParams was null");
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    @Test
+    public void testBuilderConfigWithoutChildParams() {
+        try {
+            new VcnControlPlaneIkeConfig(IKE_PARAMS, null);
+            fail("Expect to fail because childParams was null");
+        } catch (NullPointerException expected) {
+        }
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 86a1591..5b17aad 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
 import android.net.NetworkCapabilities;
@@ -57,14 +58,24 @@
             };
     public static final int MAX_MTU = 1360;
 
+    public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG =
+            VcnControlPlaneIkeConfigTest.buildTestConfig();
+
     // Public for use in VcnGatewayConnectionTest
     public static VcnGatewayConnectionConfig buildTestConfig() {
-        final VcnGatewayConnectionConfig.Builder builder =
-                new VcnGatewayConnectionConfig.Builder()
-                        .setRetryInterval(RETRY_INTERVALS_MS)
-                        .setMaxMtu(MAX_MTU);
+        return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
+    }
 
-        for (int caps : EXPOSED_CAPS) {
+    private static VcnGatewayConnectionConfig.Builder newBuilder() {
+        return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG);
+    }
+
+    // Public for use in VcnGatewayConnectionTest
+    public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
+        final VcnGatewayConnectionConfig.Builder builder =
+                newBuilder().setRetryInterval(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
+
+        for (int caps : exposedCaps) {
             builder.addExposedCapability(caps);
         }
 
@@ -76,9 +87,19 @@
     }
 
     @Test
+    public void testBuilderRequiresNonNullControlPlaneConfig() {
+        try {
+            new VcnGatewayConnectionConfig.Builder(null).build();
+
+            fail("Expected exception due to invalid control plane config");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    @Test
     public void testBuilderRequiresNonEmptyExposedCaps() {
         try {
-            new VcnGatewayConnectionConfig.Builder()
+            newBuilder()
                     .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                     .build();
 
@@ -90,9 +111,7 @@
     @Test
     public void testBuilderRequiresNonEmptyUnderlyingCaps() {
         try {
-            new VcnGatewayConnectionConfig.Builder()
-                    .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                    .build();
+            newBuilder().addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
 
             fail("Expected exception due to invalid required underlying capabilities");
         } catch (IllegalArgumentException e) {
@@ -102,7 +121,7 @@
     @Test
     public void testBuilderRequiresNonNullRetryInterval() {
         try {
-            new VcnGatewayConnectionConfig.Builder().setRetryInterval(null);
+            newBuilder().setRetryInterval(null);
             fail("Expected exception due to invalid retryIntervalMs");
         } catch (IllegalArgumentException e) {
         }
@@ -111,7 +130,7 @@
     @Test
     public void testBuilderRequiresNonEmptyRetryInterval() {
         try {
-            new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]);
+            newBuilder().setRetryInterval(new long[0]);
             fail("Expected exception due to invalid retryIntervalMs");
         } catch (IllegalArgumentException e) {
         }
@@ -120,8 +139,7 @@
     @Test
     public void testBuilderRequiresValidMtu() {
         try {
-            new VcnGatewayConnectionConfig.Builder()
-                    .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
+            newBuilder().setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
             fail("Expected exception due to invalid mtu");
         } catch (IllegalArgumentException e) {
         }
@@ -139,6 +157,9 @@
         Arrays.sort(underlyingCaps);
         assertArrayEquals(UNDERLYING_CAPS, underlyingCaps);
 
+        assertEquals(CONTROL_PLANE_CONFIG, config.getControlPlaneConfig());
+        assertFalse(CONTROL_PLANE_CONFIG == config.getControlPlaneConfig());
+
         assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs());
         assertEquals(MAX_MTU, config.getMaxMtu());
     }
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index f9db408..ce8a898 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -22,28 +22,40 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
+import android.net.vcn.VcnManager.VcnStatusCallback;
+import android.net.vcn.VcnManager.VcnStatusCallbackBinder;
 import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+import android.os.ParcelUuid;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import java.net.UnknownHostException;
+import java.util.UUID;
 import java.util.concurrent.Executor;
 
 public class VcnManagerTest {
+    private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
+    private static final int[] UNDERLYING_NETWORK_CAPABILITIES = {
+        NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET
+    };
     private static final Executor INLINE_EXECUTOR = Runnable::run;
 
     private IVcnManagementService mMockVcnManagementService;
     private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
+    private VcnStatusCallback mMockStatusCallback;
 
     private Context mContext;
     private VcnManager mVcnManager;
@@ -52,6 +64,7 @@
     public void setUp() {
         mMockVcnManagementService = mock(IVcnManagementService.class);
         mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
+        mMockStatusCallback = mock(VcnStatusCallback.class);
 
         mContext = getContext();
         mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
@@ -65,7 +78,7 @@
                 ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
         verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
 
-        assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        assertTrue(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
 
         IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
         listenerWrapper.onPolicyChanged();
@@ -78,7 +91,7 @@
 
         mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
-        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
         verify(mMockVcnManagementService)
                 .addVcnUnderlyingNetworkPolicyListener(
                         any(IVcnUnderlyingNetworkPolicyListener.class));
@@ -88,7 +101,7 @@
     public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
         mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
-        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
         verify(mMockVcnManagementService, never())
                 .addVcnUnderlyingNetworkPolicyListener(
                         any(IVcnUnderlyingNetworkPolicyListener.class));
@@ -132,4 +145,74 @@
     public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
         mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
     }
+
+    @Test
+    public void testRegisterVcnStatusCallback() throws Exception {
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+
+        verify(mMockVcnManagementService)
+                .registerVcnStatusCallback(eq(SUB_GROUP), notNull(), any());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testRegisterVcnStatusCallbackAlreadyRegistered() throws Exception {
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testRegisterVcnStatusCallbackNullSubscriptionGroup() throws Exception {
+        mVcnManager.registerVcnStatusCallback(null, INLINE_EXECUTOR, mMockStatusCallback);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testRegisterVcnStatusCallbackNullExecutor() throws Exception {
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, null, mMockStatusCallback);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testRegisterVcnStatusCallbackNullCallback() throws Exception {
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, null);
+    }
+
+    @Test
+    public void testUnregisterVcnStatusCallback() throws Exception {
+        mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+
+        mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
+
+        verify(mMockVcnManagementService).unregisterVcnStatusCallback(any());
+    }
+
+    @Test
+    public void testUnregisterUnknownVcnStatusCallback() throws Exception {
+        mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
+
+        verifyNoMoreInteractions(mMockVcnManagementService);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testUnregisterNullVcnStatusCallback() throws Exception {
+        mVcnManager.unregisterVcnStatusCallback(null);
+    }
+
+    @Test
+    public void testVcnStatusCallbackBinder() throws Exception {
+        IVcnStatusCallback cbBinder =
+                new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
+
+        cbBinder.onEnteredSafeMode();
+        verify(mMockStatusCallback).onEnteredSafeMode();
+
+        cbBinder.onGatewayConnectionError(
+                UNDERLYING_NETWORK_CAPABILITIES,
+                VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
+                UnknownHostException.class.getName(),
+                "exception_message");
+        verify(mMockStatusCallback)
+                .onGatewayConnectionError(
+                        eq(UNDERLYING_NETWORK_CAPABILITIES),
+                        eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
+                        any(UnknownHostException.class));
+    }
 }
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
index 3ba0a1f..a674425 100644
--- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -46,6 +46,6 @@
 
     @Test
     public void testParcelUnparcel() {
-        assertParcelSane(SAMPLE_NETWORK_POLICY, 2);
+        assertParcelSane(SAMPLE_NETWORK_POLICY, 1);
     }
 }
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
new file mode 100644
index 0000000..2110d6e
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.net.vcn;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.TelephonyNetworkSpecifier;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnUnderlyingNetworkSpecifierTest {
+    private static final int[] TEST_SUB_IDS = new int[] {1, 2, 3, 5};
+
+    @Test
+    public void testGetSubIds() {
+        final VcnUnderlyingNetworkSpecifier specifier =
+                new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+
+        assertEquals(TEST_SUB_IDS, specifier.getSubIds());
+    }
+
+    @Test
+    public void testParceling() {
+        final VcnUnderlyingNetworkSpecifier specifier =
+                new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+        assertParcelSane(specifier, 1);
+    }
+
+    @Test
+    public void testCanBeSatisfiedByTelephonyNetworkSpecifier() {
+        final TelephonyNetworkSpecifier telSpecifier =
+                new TelephonyNetworkSpecifier(TEST_SUB_IDS[0]);
+
+        final VcnUnderlyingNetworkSpecifier specifier =
+                new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+        assertTrue(specifier.canBeSatisfiedBy(telSpecifier));
+    }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index e7d334e..45b2381 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,12 +16,17 @@
 
 package com.android.server;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
 import static com.android.server.vcn.VcnTestUtils.setupSystemService;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -38,9 +43,11 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -48,6 +55,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkCapabilities.Transport;
 import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnConfigTest;
@@ -66,6 +74,9 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.LocationPermissionChecker;
+import com.android.server.VcnManagementService.VcnCallback;
+import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
 import com.android.server.vcn.TelephonySubscriptionTracker;
 import com.android.server.vcn.Vcn;
 import com.android.server.vcn.VcnContext;
@@ -105,6 +116,7 @@
             Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
 
     private static final int TEST_SUBSCRIPTION_ID = 1;
+    private static final int TEST_SUBSCRIPTION_ID_2 = 2;
     private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
             new SubscriptionInfo(
                     TEST_SUBSCRIPTION_ID /* id */,
@@ -141,11 +153,17 @@
             mock(PersistableBundleUtils.LockingReadWriteHelper.class);
     private final TelephonySubscriptionTracker mSubscriptionTracker =
             mock(TelephonySubscriptionTracker.class);
+    private final LocationPermissionChecker mLocationPermissionChecker =
+            mock(LocationPermissionChecker.class);
+
+    private final ArgumentCaptor<VcnCallback> mVcnCallbackCaptor =
+            ArgumentCaptor.forClass(VcnCallback.class);
 
     private final VcnManagementService mVcnMgmtSvc;
 
     private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
             mock(IVcnUnderlyingNetworkPolicyListener.class);
+    private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class);
     private final IBinder mMockIBinder = mock(IBinder.class);
 
     public VcnManagementServiceTest() throws Exception {
@@ -162,6 +180,7 @@
 
         doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
 
+        doReturn(mMockContext).when(mVcnContext).getContext();
         doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
         doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
         doReturn(mVcnContext)
@@ -179,12 +198,15 @@
         doReturn(mConfigReadWriteHelper)
                 .when(mMockDeps)
                 .newPersistableBundleLockingReadWriteHelper(any());
+        doReturn(mLocationPermissionChecker)
+                .when(mMockDeps)
+                .newLocationPermissionChecker(eq(mMockContext));
 
         // Setup VCN instance generation
         doAnswer((invocation) -> {
             // Mock-within a doAnswer is safe, because it doesn't actually run nested.
             return mock(Vcn.class);
-        }).when(mMockDeps).newVcn(any(), any(), any());
+        }).when(mMockDeps).newVcn(any(), any(), any(), any(), any());
 
         final PersistableBundle bundle =
                 PersistableBundleUtils.fromMap(
@@ -197,6 +219,7 @@
         mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
 
         doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+        doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
 
         // Make sure the profiles are loaded.
         mTestLooper.dispatchAll();
@@ -304,14 +327,17 @@
 
     @Test
     public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
-        verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG));
+        TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+        verify(mMockDeps)
+                .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
     }
 
     @Test
     public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
 
@@ -319,6 +345,7 @@
         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
         mTestLooper.dispatchAll();
         verify(vcn).teardownAsynchronously();
+        verify(mMockPolicyListener).onPolicyChanged();
     }
 
     @Test
@@ -389,6 +416,7 @@
             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
             fail("Expected security exception for non system user");
         } catch (SecurityException expected) {
+            verify(mMockPolicyListener, never()).onPolicyChanged();
         }
     }
 
@@ -400,6 +428,7 @@
             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
             fail("Expected security exception for missing carrier privileges");
         } catch (SecurityException expected) {
+            verify(mMockPolicyListener, never()).onPolicyChanged();
         }
     }
 
@@ -409,6 +438,7 @@
             mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
             fail("Expected exception due to mismatched packages in config and method call");
         } catch (IllegalArgumentException expected) {
+            verify(mMockPolicyListener, never()).onPolicyChanged();
         }
     }
 
@@ -473,7 +503,13 @@
         verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
 
         // Verify Vcn is started
-        verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG));
+        verify(mMockDeps)
+                .newVcn(
+                        eq(mVcnContext),
+                        eq(TEST_UUID_2),
+                        eq(TEST_VCN_CONFIG),
+                        eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT),
+                        any());
 
         // Verify Vcn is updated if it was previously started
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -521,58 +557,120 @@
     }
 
     private void verifyMergedNetworkCapabilities(
-            NetworkCapabilities mergedCapabilities, @Transport int transportType) {
+            NetworkCapabilities mergedCapabilities,
+            @Transport int transportType,
+            boolean isVcnManaged,
+            boolean isRestricted) {
         assertTrue(mergedCapabilities.hasTransport(transportType));
-        assertFalse(
+        assertEquals(
+                !isVcnManaged,
                 mergedCapabilities.hasCapability(
                         NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
+        assertEquals(
+                !isRestricted,
+                mergedCapabilities.hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+    }
+
+    private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
+        setUpVcnSubscription(subId, subGrp);
+        final Vcn vcn = startAndGetVcnInstance(subGrp);
+        doReturn(isVcnActive).when(vcn).isActive();
+    }
+
+    private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
+            int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
+        setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
+
+        final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder();
+        ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+        if (transport == TRANSPORT_CELLULAR) {
+            ncBuilder
+                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID));
+        } else if (transport == TRANSPORT_WIFI) {
+            WifiInfo wifiInfo = mock(WifiInfo.class);
+            when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
+            when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
+
+            ncBuilder
+                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                    .setTransportInfo(wifiInfo);
+        } else {
+            throw new IllegalArgumentException("Unknown transport");
+        }
+
+        return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
     }
 
     @Test
-    public void testGetUnderlyingNetworkPolicyTransportCell() throws Exception {
-        setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
-
-        NetworkCapabilities nc =
-                new NetworkCapabilities.Builder()
-                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
-                        .build();
-
-        VcnUnderlyingNetworkPolicy policy =
-                mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+    public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
+        final VcnUnderlyingNetworkPolicy policy =
+                startVcnAndGetPolicyForTransport(
+                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
 
         assertFalse(policy.isTeardownRequested());
         verifyMergedNetworkCapabilities(
-                policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR);
+                policy.getMergedNetworkCapabilities(),
+                TRANSPORT_CELLULAR,
+                true /* isVcnManaged */,
+                false /* isRestricted */);
     }
 
     @Test
-    public void testGetUnderlyingNetworkPolicyTransportWifi() throws Exception {
-        setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
-
-        WifiInfo wifiInfo = mock(WifiInfo.class);
-        when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
-        when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
-        NetworkCapabilities nc =
-                new NetworkCapabilities.Builder()
-                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                        .setTransportInfo(wifiInfo)
-                        .build();
-
-        VcnUnderlyingNetworkPolicy policy =
-                mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+    public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
+        final VcnUnderlyingNetworkPolicy policy =
+                startVcnAndGetPolicyForTransport(
+                        TEST_SUBSCRIPTION_ID,
+                        TEST_UUID_2,
+                        false /* isActive */,
+                        TRANSPORT_CELLULAR);
 
         assertFalse(policy.isTeardownRequested());
         verifyMergedNetworkCapabilities(
-                policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI);
+                policy.getMergedNetworkCapabilities(),
+                NetworkCapabilities.TRANSPORT_CELLULAR,
+                false /* isVcnManaged */,
+                false /* isRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
+        final VcnUnderlyingNetworkPolicy policy =
+                startVcnAndGetPolicyForTransport(
+                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
+
+        assertFalse(policy.isTeardownRequested());
+        verifyMergedNetworkCapabilities(
+                policy.getMergedNetworkCapabilities(),
+                NetworkCapabilities.TRANSPORT_WIFI,
+                true /* isVcnManaged */,
+                true /* isRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
+        final VcnUnderlyingNetworkPolicy policy =
+                startVcnAndGetPolicyForTransport(
+                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+        assertFalse(policy.isTeardownRequested());
+        verifyMergedNetworkCapabilities(
+                policy.getMergedNetworkCapabilities(),
+                NetworkCapabilities.TRANSPORT_WIFI,
+                false /* isVcnManaged */,
+                true /* isRestricted */);
     }
 
     @Test
     public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
+        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
+
         NetworkCapabilities nc =
                 new NetworkCapabilities.Builder()
                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
+                        .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+                        .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2))
                         .build();
 
         VcnUnderlyingNetworkPolicy policy =
@@ -591,4 +689,170 @@
 
         mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
     }
+
+    @Test
+    public void testSubscriptionSnapshotUpdateNotifiesVcn() {
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+        final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
+        final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
+
+        TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+
+        verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
+    }
+
+    @Test
+    public void testAddNewVcnUpdatesPolicyListener() throws Exception {
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
+    @Test
+    public void testRemoveVcnUpdatesPolicyListener() throws Exception {
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
+    private void verifyVcnCallback(
+            @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
+            throws Exception {
+        verify(mMockDeps)
+                .newVcn(
+                        eq(mVcnContext),
+                        eq(subGroup),
+                        eq(TEST_VCN_CONFIG),
+                        eq(snapshot),
+                        mVcnCallbackCaptor.capture());
+
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
+        vcnCallback.onEnteredSafeMode();
+
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
+    @Test
+    public void testVcnCallbackOnEnteredSafeMode() throws Exception {
+        TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+
+        verifyVcnCallback(TEST_UUID_1, snapshot);
+    }
+
+    private void triggerVcnStatusCallbackOnEnteredSafeMode(
+            @NonNull ParcelUuid subGroup,
+            @NonNull String pkgName,
+            int uid,
+            boolean hasPermissionsforSubGroup,
+            boolean hasLocationPermission)
+            throws Exception {
+        TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
+
+        doReturn(hasPermissionsforSubGroup)
+                .when(snapshot)
+                .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
+
+        doReturn(hasLocationPermission)
+                .when(mLocationPermissionChecker)
+                .checkLocationPermission(eq(pkgName), any(), eq(uid), any());
+
+        mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
+
+        // Trigger systemReady() to set up LocationPermissionChecker
+        mVcnMgmtSvc.systemReady();
+
+        verifyVcnCallback(subGroup, snapshot);
+    }
+
+    @Test
+    public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
+        triggerVcnStatusCallbackOnEnteredSafeMode(
+                TEST_UUID_1,
+                TEST_PACKAGE_NAME,
+                TEST_UID,
+                true /* hasPermissionsforSubGroup */,
+                true /* hasLocationPermission */);
+
+        verify(mMockStatusCallback, times(1)).onEnteredSafeMode();
+    }
+
+    @Test
+    public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
+        triggerVcnStatusCallbackOnEnteredSafeMode(
+                TEST_UUID_1,
+                TEST_PACKAGE_NAME,
+                TEST_UID,
+                false /* hasPermissionsforSubGroup */,
+                true /* hasLocationPermission */);
+
+        verify(mMockStatusCallback, never()).onEnteredSafeMode();
+    }
+
+    @Test
+    public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
+        triggerVcnStatusCallbackOnEnteredSafeMode(
+                TEST_UUID_1,
+                TEST_PACKAGE_NAME,
+                TEST_UID,
+                true /* hasPermissionsforSubGroup */,
+                false /* hasLocationPermission */);
+
+        verify(mMockStatusCallback, never()).onEnteredSafeMode();
+    }
+
+    @Test
+    public void testRegisterVcnStatusCallback() throws Exception {
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+        Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
+        VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
+
+        assertNotNull(cbInfo);
+        assertEquals(TEST_UUID_1, cbInfo.mSubGroup);
+        assertEquals(mMockStatusCallback, cbInfo.mCallback);
+        assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
+        assertEquals(TEST_UID, cbInfo.mUid);
+        verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testRegisterVcnStatusCallbackDuplicate() {
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+    }
+
+    @Test
+    public void testUnregisterVcnStatusCallback() {
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+        Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
+        VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
+
+        mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
+        assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
+        verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt());
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testRegisterVcnStatusCallbackInvalidPackage() {
+        doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME);
+
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+    }
+
+    @Test
+    public void testUnregisterVcnStatusCallbackNeverRegistered() {
+        mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
+
+        assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 48e068d..1d459a3 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -42,8 +42,9 @@
 import android.os.ParcelUuid;
 import android.os.test.TestLooper;
 import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
+import android.util.ArraySet;
 
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
 import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
@@ -58,13 +59,19 @@
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 public class UnderlyingNetworkTrackerTest {
     private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
     private static final int INITIAL_SUB_ID_1 = 1;
     private static final int INITIAL_SUB_ID_2 = 2;
+    private static final int UPDATED_SUB_ID = 3;
+
+    private static final Set<Integer> INITIAL_SUB_IDS =
+            new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2));
+    private static final Set<Integer> UPDATED_SUB_IDS =
+            new ArraySet<>(Arrays.asList(UPDATED_SUB_ID));
 
     private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES =
             new NetworkCapabilities.Builder()
@@ -90,7 +97,7 @@
     @Mock private Context mContext;
     @Mock private VcnNetworkProvider mVcnNetworkProvider;
     @Mock private ConnectivityManager mConnectivityManager;
-    @Mock private SubscriptionManager mSubscriptionManager;
+    @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
     @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
     @Mock private Network mNetwork;
 
@@ -113,23 +120,14 @@
                 mConnectivityManager,
                 Context.CONNECTIVITY_SERVICE,
                 ConnectivityManager.class);
-        setupSystemService(
-                mContext,
-                mSubscriptionManager,
-                Context.TELEPHONY_SUBSCRIPTION_SERVICE,
-                SubscriptionManager.class);
 
-        List<SubscriptionInfo> initialSubInfos =
-                Arrays.asList(
-                        getSubscriptionInfoForSubId(INITIAL_SUB_ID_1),
-                        getSubscriptionInfoForSubId(INITIAL_SUB_ID_2));
-        when(mSubscriptionManager.getSubscriptionsInGroup(eq(SUB_GROUP)))
-                .thenReturn(initialSubInfos);
+        when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
 
         mUnderlyingNetworkTracker =
                 new UnderlyingNetworkTracker(
                         mVcnContext,
                         SUB_GROUP,
+                        mSubscriptionSnapshot,
                         Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
                         mNetworkTrackerCb);
     }
@@ -154,23 +152,45 @@
                         eq(getWifiRequest()),
                         any(),
                         any(NetworkBringupCallback.class));
-        verify(mConnectivityManager)
-                .requestBackgroundNetwork(
-                        eq(getCellRequestForSubId(INITIAL_SUB_ID_1)),
-                        any(),
-                        any(NetworkBringupCallback.class));
-        verify(mConnectivityManager)
-                .requestBackgroundNetwork(
-                        eq(getCellRequestForSubId(INITIAL_SUB_ID_2)),
-                        any(),
-                        any(NetworkBringupCallback.class));
+        verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
+
         verify(mConnectivityManager)
                 .requestBackgroundNetwork(
                         eq(getRouteSelectionRequest()),
                         any(),
                         any(RouteSelectionCallback.class));
+    }
 
-        verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP));
+    private void verifyBackgroundCellRequests(
+            TelephonySubscriptionSnapshot snapshot,
+            ParcelUuid subGroup,
+            Set<Integer> expectedSubIds) {
+        verify(snapshot).getAllSubIdsInGroup(eq(subGroup));
+
+        for (final int subId : expectedSubIds) {
+            verify(mConnectivityManager)
+                    .requestBackgroundNetwork(
+                            eq(getCellRequestForSubId(subId)),
+                            any(),
+                            any(NetworkBringupCallback.class));
+        }
+    }
+
+    @Test
+    public void testUpdateSubscriptionSnapshot() {
+        // Verify initial cell background requests filed
+        verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
+
+        TelephonySubscriptionSnapshot subscriptionUpdate =
+                mock(TelephonySubscriptionSnapshot.class);
+        when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS);
+
+        mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
+
+        // verify that initially-filed bringup requests are unregistered
+        verify(mConnectivityManager, times(INITIAL_SUB_IDS.size()))
+                .unregisterNetworkCallback(any(NetworkBringupCallback.class));
+        verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS);
     }
 
     private NetworkRequest getWifiRequest() {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
new file mode 100644
index 0000000..69c21b9
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -0,0 +1,293 @@
+/*
+ * 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.vcn;
+
+import static android.net.IpSecManager.DIRECTION_IN;
+import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeInternalException;
+import android.net.ipsec.ike.exceptions.TemporaryFailureException;
+import android.net.vcn.VcnManager.VcnErrorCode;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.Collections;
+
+/** Tests for VcnGatewayConnection.ConnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
+    private VcnIkeSession mIkeSession;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+
+        mIkeSession = mGatewayConnection.buildIkeSession();
+        mGatewayConnection.setIkeSession(mIkeSession);
+
+        mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testEnterStateCreatesNewIkeSession() throws Exception {
+        verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testEnterStateDoesNotCancelSafeModeAlarm() {
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+    }
+
+    @Test
+    public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession, never()).close();
+        verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+    }
+
+    @Test
+    public void testNewNetworkTriggersMigration() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession, never()).close();
+        verify(mIkeSession).setNetwork(TEST_UNDERLYING_NETWORK_RECORD_2.network);
+    }
+
+    @Test
+    public void testSameNetworkDoesNotTriggerMigration() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testCreatedTransformsAreApplied() throws Exception {
+        for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
+            getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
+            mTestLooper.dispatchAll();
+
+            verify(mIpSecSvc)
+                    .applyTunnelModeTransform(
+                            eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
+        }
+
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testMigratedTransformsAreApplied() throws Exception {
+        getChildSessionCallback()
+                .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
+        mTestLooper.dispatchAll();
+
+        for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
+            verify(mIpSecSvc)
+                    .applyTunnelModeTransform(
+                            eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
+        }
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testChildOpenedRegistersNetwork() throws Exception {
+        // Verify scheduled but not canceled when entering ConnectedState
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+        final VcnChildSessionConfiguration mMockChildSessionConfig =
+                mock(VcnChildSessionConfiguration.class);
+        doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
+                .when(mMockChildSessionConfig)
+                .getInternalAddresses();
+        doReturn(Collections.singletonList(TEST_DNS_ADDR))
+                .when(mMockChildSessionConfig)
+                .getInternalDnsServers();
+
+        getChildSessionCallback().onOpened(mMockChildSessionConfig);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+        final ArgumentCaptor<LinkProperties> lpCaptor =
+                ArgumentCaptor.forClass(LinkProperties.class);
+        final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+                ArgumentCaptor.forClass(NetworkCapabilities.class);
+        verify(mConnMgr)
+                .registerNetworkAgent(
+                        any(),
+                        any(),
+                        lpCaptor.capture(),
+                        ncCaptor.capture(),
+                        anyInt(),
+                        any(),
+                        anyInt());
+        verify(mIpSecSvc)
+                .addAddressToTunnelInterface(
+                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+        final LinkProperties lp = lpCaptor.getValue();
+        assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
+        assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+
+        final NetworkCapabilities nc = ncCaptor.getValue();
+        assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
+        assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+        for (int cap : mConfig.getAllExposedCapabilities()) {
+            assertTrue(nc.hasCapability(cap));
+        }
+
+        // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
+        // canceled
+        mGatewayConnection.mNetworkAgent.onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
+        verify(mSafeModeTimeoutAlarm).cancel();
+    }
+
+    @Test
+    public void testChildSessionClosedTriggersDisconnect() throws Exception {
+        // Verify scheduled but not canceled when entering ConnectedState
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+        getChildSessionCallback().onClosed();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+        // Since network never validated, verify mSafeModeTimeoutAlarm not canceled
+        verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
+
+        // The child session was closed without exception, so verify that the GatewayStatusCallback
+        // was not notified
+        verifyNoMoreInteractions(mGatewayStatusCallback);
+    }
+
+    @Test
+    public void testChildSessionClosedExceptionallyNotifiesGatewayStatusCallback()
+            throws Exception {
+        final IkeInternalException exception = new IkeInternalException(mock(IOException.class));
+        getChildSessionCallback().onClosedExceptionally(exception);
+        mTestLooper.dispatchAll();
+
+        verify(mGatewayStatusCallback)
+                .onGatewayConnectionError(
+                        eq(mConfig.getRequiredUnderlyingCapabilities()),
+                        eq(VCN_ERROR_CODE_INTERNAL_ERROR),
+                        any(),
+                        any());
+    }
+
+    @Test
+    public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+        // Verify scheduled but not canceled when entering ConnectedState
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+        getIkeSessionCallback().onClosed();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession).close();
+
+        // Since network never validated, verify mSafeModeTimeoutAlarm not canceled
+        verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
+
+        // IkeSession closed with no error, so verify that the GatewayStatusCallback was not
+        // notified
+        verifyNoMoreInteractions(mGatewayStatusCallback);
+    }
+
+    private void verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+            IkeException cause, @VcnErrorCode int expectedErrorType) {
+        getIkeSessionCallback().onClosedExceptionally(cause);
+        mTestLooper.dispatchAll();
+
+        verify(mIkeSession).close();
+
+        verify(mGatewayStatusCallback)
+                .onGatewayConnectionError(
+                        eq(mConfig.getRequiredUnderlyingCapabilities()),
+                        eq(expectedErrorType),
+                        any(),
+                        any());
+    }
+
+    @Test
+    public void testIkeSessionClosedExceptionallyAuthenticationFailure() throws Exception {
+        verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+                new AuthenticationFailedException("vcn test"), VCN_ERROR_CODE_CONFIG_ERROR);
+    }
+
+    @Test
+    public void testIkeSessionClosedExceptionallyDnsFailure() throws Exception {
+        verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+                new IkeInternalException(new UnknownHostException()), VCN_ERROR_CODE_NETWORK_ERROR);
+    }
+
+    @Test
+    public void testIkeSessionClosedExceptionallyInternalFailure() throws Exception {
+        verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+                new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index d936183..17ae19e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -61,6 +61,7 @@
 
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
         verify(mIkeSession).kill();
+        verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
     }
 
     @Test
@@ -73,6 +74,7 @@
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
         verify(mIkeSession).close();
         verify(mIkeSession, never()).kill();
+        verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
     }
 
     @Test
@@ -92,6 +94,7 @@
 
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
         verify(mIkeSession).close();
+        verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
     }
 
     @Test
@@ -101,5 +104,11 @@
 
         assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
         verify(mIkeSession).close();
+        verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+    }
+
+    @Test
+    public void testSafeModeTimeoutNotifiesCallback() {
+        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 4ecd215..9ea641f 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -16,12 +16,18 @@
 
 package com.android.server.vcn;
 
+import static android.net.IpSecManager.IpSecTunnelInterface;
+
+import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 
+import android.net.IpSecManager;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -37,14 +43,26 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+        final IpSecTunnelInterface tunnelIface =
+                mContext.getSystemService(IpSecManager.class)
+                        .createIpSecTunnelInterface(
+                                DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
+        mGatewayConnection.setTunnelInterface(tunnelIface);
+
+        // Don't need to transition to DisconnectedState because it is the starting state
         mTestLooper.dispatchAll();
     }
 
     @Test
     public void testEnterWhileNotRunningTriggersQuit() throws Exception {
         final VcnGatewayConnection vgc =
-                new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+                new VcnGatewayConnection(
+                        mVcnContext,
+                        TEST_SUB_GRP,
+                        TEST_SUBSCRIPTION_SNAPSHOT,
+                        mConfig,
+                        mGatewayStatusCallback,
+                        mDeps);
 
         vgc.setIsRunning(false);
         vgc.transitionTo(vgc.mDisconnectedState);
@@ -61,6 +79,7 @@
         mTestLooper.dispatchAll();
 
         assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
     }
 
     @Test
@@ -71,6 +90,7 @@
         mTestLooper.dispatchAll();
 
         assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
     }
 
     @Test
@@ -80,5 +100,6 @@
 
         assertNull(mGatewayConnection.getCurrentState());
         verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+        verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index d0fec55..7385204 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -16,9 +16,9 @@
 
 package com.android.server.vcn;
 
-import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import androidx.test.filters.SmallTest;
@@ -28,8 +28,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.concurrent.TimeUnit;
-
 /** Tests for VcnGatewayConnection.DisconnectedState */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -40,6 +38,9 @@
 
         mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession());
 
+        // ensure that mGatewayConnection has an underlying Network before entering
+        // DisconnectingState
+        mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_2);
         mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState);
         mTestLooper.dispatchAll();
     }
@@ -49,12 +50,22 @@
         getIkeSessionCallback().onClosed();
         mTestLooper.dispatchAll();
 
-        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+        verify(mMockIkeSession).close();
+        verify(mMockIkeSession, never()).kill();
+        verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
     }
 
     @Test
     public void testTimeoutExpired() throws Exception {
-        mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
+        Runnable delayedEvent =
+                verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+        // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
+        // (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
+        // since verifyTeardownTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
+        // with the correct delay.
+        delayedEvent.run();
         mTestLooper.dispatchAll();
 
         verify(mMockIkeSession).kill();
@@ -67,5 +78,11 @@
 
         // Should do nothing; already tearing down.
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+    }
+
+    @Test
+    public void testSafeModeTimeoutNotifiesCallback() {
+        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
new file mode 100644
index 0000000..5b0850b
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.vcn;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.RetryTimeoutState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
+    private long mFirstRetryInterval;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mFirstRetryInterval = mConfig.getRetryInterval()[0];
+
+        mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testNewNetworkTriggerRetry() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+        verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+    }
+
+    @Test
+    public void testSameNetworkDoesNotTriggerRetry() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+        verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */);
+    }
+
+    @Test
+    public void testNullNetworkTriggersDisconnect() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+    }
+
+    @Test
+    public void testTimeoutElapsingTriggersRetry() throws Exception {
+        final Runnable delayedEvent =
+                verifyRetryTimeoutAlarmAndGetCallback(
+                        mFirstRetryInterval, false /* expectCanceled */);
+
+        // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
+        // (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
+        // since verifyRetryTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
+        // with the correct delay.
+        delayedEvent.run();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+        verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+    }
+
+    @Test
+    public void testSafeModeTimeoutNotifiesCallback() {
+        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index d741e5c..748c792 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -16,20 +16,36 @@
 
 package com.android.server.vcn;
 
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
-import android.annotation.NonNull;
-import android.content.Context;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.net.LinkProperties;
+import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnTransportInfo;
+import android.net.wifi.WifiInfo;
 import android.os.ParcelUuid;
-import android.os.test.TestLooper;
+import android.os.Process;
 import android.telephony.SubscriptionInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -41,7 +57,9 @@
 /** Tests for TelephonySubscriptionTracker */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class VcnGatewayConnectionTest {
+public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
+    private static final int TEST_UID = Process.myUid();
+
     private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
     private static final int TEST_SIM_SLOT_INDEX = 1;
     private static final int TEST_SUBSCRIPTION_ID_1 = 2;
@@ -57,26 +75,89 @@
         TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
     }
 
-    @NonNull private final Context mContext;
-    @NonNull private final TestLooper mTestLooper;
-    @NonNull private final VcnNetworkProvider mVcnNetworkProvider;
-    @NonNull private final VcnGatewayConnection.Dependencies mDeps;
+    private WifiInfo mWifiInfo;
 
-    public VcnGatewayConnectionTest() {
-        mContext = mock(Context.class);
-        mTestLooper = new TestLooper();
-        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
-        mDeps = mock(VcnGatewayConnection.Dependencies.class);
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mWifiInfo = mock(WifiInfo.class);
+    }
+
+    private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
+        final NetworkCapabilities underlyingCaps = new NetworkCapabilities();
+        underlyingCaps.addTransportType(transportType);
+        underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED);
+        underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING);
+
+        if (transportType == TRANSPORT_WIFI) {
+            underlyingCaps.setTransportInfo(mWifiInfo);
+            underlyingCaps.setOwnerUid(TEST_UID);
+        } else if (transportType == TRANSPORT_CELLULAR) {
+            underlyingCaps.setAdministratorUids(new int[] {TEST_UID});
+            underlyingCaps.setNetworkSpecifier(
+                    new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
+        }
+
+        UnderlyingNetworkRecord record =
+                new UnderlyingNetworkRecord(
+                        new Network(0), underlyingCaps, new LinkProperties(), false);
+        final NetworkCapabilities vcnCaps =
+                VcnGatewayConnection.buildNetworkCapabilities(
+                        VcnGatewayConnectionConfigTest.buildTestConfig(), record);
+
+        assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
+        assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
+        assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+        assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
+        assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
+
+        final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
+        if (transportType == TRANSPORT_WIFI) {
+            assertEquals(mWifiInfo, info.getWifiInfo());
+        } else if (transportType == TRANSPORT_CELLULAR) {
+            assertEquals(TEST_SUBSCRIPTION_ID_1, info.getSubId());
+        }
     }
 
     @Test
-    public void testBuildNetworkCapabilities() throws Exception {
-        final NetworkCapabilities caps =
-                VcnGatewayConnection.buildNetworkCapabilities(
-                        VcnGatewayConnectionConfigTest.buildTestConfig());
+    public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
+        verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI);
+    }
 
-        for (int exposedCapability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
-            assertTrue(caps.hasCapability(exposedCapability));
-        }
+    @Test
+    public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
+        verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR);
+    }
+
+    @Test
+    public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
+        verifyWakeLockSetUp();
+
+        final TelephonySubscriptionSnapshot updatedSnapshot =
+                mock(TelephonySubscriptionSnapshot.class);
+        mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot);
+
+        verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot));
+        verifyWakeLockAcquired();
+
+        mTestLooper.dispatchAll();
+
+        verifyWakeLockReleased();
+    }
+
+    @Test
+    public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+
+        verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+
+        verify(mDisconnectRequestAlarm).cancel();
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 4d92fb9..a660735 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -20,15 +20,26 @@
 import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
 import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.InetAddresses;
+import android.net.IpSecConfig;
 import android.net.IpSecManager;
+import android.net.IpSecTransform;
 import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -37,18 +48,38 @@
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.os.ParcelUuid;
+import android.os.PowerManager;
 import android.os.test.TestLooper;
 
+import com.android.internal.util.State;
+import com.android.internal.util.WakeupMessage;
 import com.android.server.IpSecService;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock;
 
 import org.junit.Before;
 import org.mockito.ArgumentCaptor;
 
+import java.net.InetAddress;
+import java.util.Collections;
 import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 public class VcnGatewayConnectionTestBase {
     protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
-    protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
+    protected static final InetAddress TEST_DNS_ADDR =
+            InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+    protected static final LinkAddress TEST_INTERNAL_ADDR =
+            new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+
+    protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
+    protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
+    protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
+    protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3;
+    protected static final int TEST_SUB_ID = 5;
+    protected static final long ELAPSED_REAL_TIME = 123456789L;
     protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
     protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
             new UnderlyingNetworkRecord(
@@ -63,15 +94,26 @@
                     new LinkProperties(),
                     false /* blocked */);
 
+    protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
+            new TelephonySubscriptionSnapshot(
+                    Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP);
+
     @NonNull protected final Context mContext;
     @NonNull protected final TestLooper mTestLooper;
     @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
     @NonNull protected final VcnContext mVcnContext;
     @NonNull protected final VcnGatewayConnectionConfig mConfig;
+    @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback;
     @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
     @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+    @NonNull protected final VcnWakeLock mWakeLock;
+    @NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
+    @NonNull protected final WakeupMessage mDisconnectRequestAlarm;
+    @NonNull protected final WakeupMessage mRetryTimeoutAlarm;
+    @NonNull protected final WakeupMessage mSafeModeTimeoutAlarm;
 
     @NonNull protected final IpSecService mIpSecSvc;
+    @NonNull protected final ConnectivityManager mConnMgr;
 
     protected VcnIkeSession mMockIkeSession;
     protected VcnGatewayConnection mGatewayConnection;
@@ -82,19 +124,43 @@
         mVcnNetworkProvider = mock(VcnNetworkProvider.class);
         mVcnContext = mock(VcnContext.class);
         mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+        mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class);
         mDeps = mock(VcnGatewayConnection.Dependencies.class);
         mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+        mWakeLock = mock(VcnWakeLock.class);
+        mTeardownTimeoutAlarm = mock(WakeupMessage.class);
+        mDisconnectRequestAlarm = mock(WakeupMessage.class);
+        mRetryTimeoutAlarm = mock(WakeupMessage.class);
+        mSafeModeTimeoutAlarm = mock(WakeupMessage.class);
 
         mIpSecSvc = mock(IpSecService.class);
         setupIpSecManager(mContext, mIpSecSvc);
 
+        mConnMgr = mock(ConnectivityManager.class);
+        VcnTestUtils.setupSystemService(
+                mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
         doReturn(mContext).when(mVcnContext).getContext();
         doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
         doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
 
         doReturn(mUnderlyingNetworkTracker)
                 .when(mDeps)
-                .newUnderlyingNetworkTracker(any(), any(), any(), any());
+                .newUnderlyingNetworkTracker(any(), any(), any(), any(), any());
+        doReturn(mWakeLock)
+                .when(mDeps)
+                .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
+
+        setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
+        setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
+        setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
+        setUpWakeupMessage(mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM);
+
+        doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
+    }
+
+    private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) {
+        doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any());
     }
 
     @Before
@@ -109,7 +175,18 @@
         mMockIkeSession = mock(VcnIkeSession.class);
         doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any());
 
-        mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+        mGatewayConnection =
+                new VcnGatewayConnection(
+                        mVcnContext,
+                        TEST_SUB_GRP,
+                        TEST_SUBSCRIPTION_SNAPSHOT,
+                        mConfig,
+                        mGatewayStatusCallback,
+                        mDeps);
+    }
+
+    protected IpSecTransform makeDummyIpSecTransform() throws Exception {
+        return new IpSecTransform(mContext, new IpSecConfig());
     }
 
     protected IkeSessionCallback getIkeSessionCallback() {
@@ -119,10 +196,86 @@
         return captor.getValue();
     }
 
-    protected ChildSessionCallback getChildSessionCallback() {
+    protected VcnChildSessionCallback getChildSessionCallback() {
         ArgumentCaptor<ChildSessionCallback> captor =
                 ArgumentCaptor.forClass(ChildSessionCallback.class);
         verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
-        return captor.getValue();
+        return (VcnChildSessionCallback) captor.getValue();
+    }
+
+    protected void verifyWakeLockSetUp() {
+        verify(mDeps).newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
+        verifyNoMoreInteractions(mWakeLock);
+    }
+
+    protected void verifyWakeLockAcquired() {
+        verify(mWakeLock).acquire();
+        verifyNoMoreInteractions(mWakeLock);
+    }
+
+    protected void verifyWakeLockReleased() {
+        verify(mWakeLock).release();
+        verifyNoMoreInteractions(mWakeLock);
+    }
+
+    private Runnable verifyWakeupMessageSetUpAndGetCallback(
+            @NonNull String tag,
+            @NonNull WakeupMessage msg,
+            long delayInMillis,
+            boolean expectCanceled) {
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(tag), runnableCaptor.capture());
+
+        verify(mDeps, atLeastOnce()).getElapsedRealTime();
+        verify(msg).schedule(ELAPSED_REAL_TIME + delayInMillis);
+        verify(msg, expectCanceled ? times(1) : never()).cancel();
+
+        return runnableCaptor.getValue();
+    }
+
+    protected Runnable verifyTeardownTimeoutAlarmAndGetCallback(boolean expectCanceled) {
+        return verifyWakeupMessageSetUpAndGetCallback(
+                VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM,
+                mTeardownTimeoutAlarm,
+                TimeUnit.SECONDS.toMillis(VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS),
+                expectCanceled);
+    }
+
+    protected Runnable verifyDisconnectRequestAlarmAndGetCallback(boolean expectCanceled) {
+        return verifyWakeupMessageSetUpAndGetCallback(
+                VcnGatewayConnection.DISCONNECT_REQUEST_ALARM,
+                mDisconnectRequestAlarm,
+                TimeUnit.SECONDS.toMillis(
+                        VcnGatewayConnection.NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS),
+                expectCanceled);
+    }
+
+    protected Runnable verifyRetryTimeoutAlarmAndGetCallback(
+            long delayInMillis, boolean expectCanceled) {
+        return verifyWakeupMessageSetUpAndGetCallback(
+                VcnGatewayConnection.RETRY_TIMEOUT_ALARM,
+                mRetryTimeoutAlarm,
+                delayInMillis,
+                expectCanceled);
+    }
+
+    protected Runnable verifySafeModeTimeoutAlarmAndGetCallback(boolean expectCanceled) {
+        return verifyWakeupMessageSetUpAndGetCallback(
+                VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM,
+                mSafeModeTimeoutAlarm,
+                TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS),
+                expectCanceled);
+    }
+
+    protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
+        // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
+        // state)
+        final Runnable delayedEvent =
+                verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+        delayedEvent.run();
+        mTestLooper.dispatchAll();
+
+        verify(mGatewayStatusCallback).onEnteredSafeMode();
+        assertEquals(expectedState, mGatewayConnection.getCurrentState());
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
new file mode 100644
index 0000000..9d33682
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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 com.android.server.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.NetworkRequest;
+import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+
+import com.android.server.VcnManagementService.VcnCallback;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Set;
+import java.util.UUID;
+
+public class VcnTest {
+    private static final String PKG_NAME = VcnTest.class.getPackage().getName();
+    private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
+    private static final int NETWORK_SCORE = 0;
+    private static final int PROVIDER_ID = 5;
+
+    private Context mContext;
+    private VcnContext mVcnContext;
+    private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+    private VcnNetworkProvider mVcnNetworkProvider;
+    private VcnCallback mVcnCallback;
+    private Vcn.Dependencies mDeps;
+
+    private ArgumentCaptor<VcnGatewayStatusCallback> mGatewayStatusCallbackCaptor;
+
+    private TestLooper mTestLooper;
+    private VcnGatewayConnectionConfig mGatewayConnectionConfig;
+    private VcnConfig mConfig;
+    private Vcn mVcn;
+
+    @Before
+    public void setUp() {
+        mContext = mock(Context.class);
+        mVcnContext = mock(VcnContext.class);
+        mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
+        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+        mVcnCallback = mock(VcnCallback.class);
+        mDeps = mock(Vcn.Dependencies.class);
+
+        mTestLooper = new TestLooper();
+
+        doReturn(PKG_NAME).when(mContext).getOpPackageName();
+        doReturn(mContext).when(mVcnContext).getContext();
+        doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+        doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+        // Setup VcnGatewayConnection instance generation
+        doAnswer((invocation) -> {
+            // Mock-within a doAnswer is safe, because it doesn't actually run nested.
+            return mock(VcnGatewayConnection.class);
+        }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any());
+
+        mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
+
+        final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
+        for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+            configBuilder.addGatewayConnectionConfig(
+                    VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability));
+        }
+        configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig());
+        mConfig = configBuilder.build();
+
+        mVcn =
+                new Vcn(
+                        mVcnContext,
+                        TEST_SUB_GROUP,
+                        mConfig,
+                        mSubscriptionSnapshot,
+                        mVcnCallback,
+                        mDeps);
+    }
+
+    private NetworkRequestListener verifyAndGetRequestListener() {
+        ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
+                ArgumentCaptor.forClass(NetworkRequestListener.class);
+        verify(mVcnNetworkProvider).registerListener(mNetworkRequestListenerCaptor.capture());
+
+        return mNetworkRequestListenerCaptor.getValue();
+    }
+
+    private void startVcnGatewayWithCapabilities(
+            NetworkRequestListener requestListener, int... netCapabilities) {
+        final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+        for (final int netCapability : netCapabilities) {
+            requestBuilder.addCapability(netCapability);
+        }
+
+        requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        startVcnGatewayWithCapabilities(
+                requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS);
+
+        final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
+        assertFalse(gatewayConnections.isEmpty());
+
+        final TelephonySubscriptionSnapshot updatedSnapshot =
+                mock(TelephonySubscriptionSnapshot.class);
+
+        mVcn.updateSubscriptionSnapshot(updatedSnapshot);
+        mTestLooper.dispatchAll();
+
+        for (final VcnGatewayConnection gateway : gatewayConnections) {
+            verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
+        }
+    }
+
+    @Test
+    public void testGatewayEnteringSafeModeNotifiesVcn() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+            startVcnGatewayWithCapabilities(requestListener, capability);
+        }
+
+        // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp.
+        // Expect one VcnGatewayConnection per capability.
+        final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length;
+
+        final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
+        assertEquals(numExpectedGateways, gatewayConnections.size());
+        verify(mDeps, times(numExpectedGateways))
+                .newVcnGatewayConnection(
+                        eq(mVcnContext),
+                        eq(TEST_SUB_GROUP),
+                        eq(mSubscriptionSnapshot),
+                        any(),
+                        mGatewayStatusCallbackCaptor.capture());
+
+        // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down
+        // all Gateways
+        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+        statusCallback.onEnteredSafeMode();
+        mTestLooper.dispatchAll();
+
+        assertFalse(mVcn.isActive());
+        for (final VcnGatewayConnection gatewayConnection : gatewayConnections) {
+            verify(gatewayConnection).teardownAsynchronously();
+        }
+        verify(mVcnNetworkProvider).unregisterListener(requestListener);
+        verify(mVcnCallback).onEnteredSafeMode();
+    }
+}
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index a594e5b..c75ba71 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -19,6 +19,23 @@
 // targets here.
 // ==========================================================
 
+package {
+    default_applicable_licenses: ["frameworks_base_tools_aapt_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_tools_aapt_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "aapt_defaults",
 
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index ade0dc4..5c5b3c3 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -14,6 +14,15 @@
 // 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"],
+}
+
 toolSources = [
     "cmd/Command.cpp",
     "cmd/Compile.cpp",
diff --git a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp
index 79fb573..bfd3508 100644
--- a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp
+++ b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AaptAutoVersionTest",
     sdk_version: "current",
diff --git a/tools/aapt2/integration-tests/BasicTest/Android.bp b/tools/aapt2/integration-tests/BasicTest/Android.bp
index a94a01f..7db9d26 100644
--- a/tools/aapt2/integration-tests/BasicTest/Android.bp
+++ b/tools/aapt2/integration-tests/BasicTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AaptBasicTest",
     sdk_version: "current",
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk
index 7bf8cf8..c084849 100644
--- a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk
@@ -20,9 +20,12 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_AAPT_NAMESPACES := true
 LOCAL_MODULE := AaptTestMergeOnly_LeafLib
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
 LOCAL_SDK_VERSION := current
 LOCAL_MODULE_TAGS := tests
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_MIN_SDK_VERSION := 21
 LOCAL_AAPT_FLAGS := --merge-only
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk
index ba781c5..699ad79 100644
--- a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk
@@ -20,9 +20,12 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_AAPT_NAMESPACES := true
 LOCAL_MODULE := AaptTestMergeOnly_LocalLib
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
 LOCAL_SDK_VERSION := current
 LOCAL_MODULE_TAGS := tests
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_MIN_SDK_VERSION := 21
 LOCAL_AAPT_FLAGS := --merge-only
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
index c723d90..dd41702 100644
--- a/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
@@ -20,6 +20,9 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_AAPT_NAMESPACES := true
 LOCAL_MODULE := AaptTestNamespace_LibOne
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
 LOCAL_SDK_VERSION := current
 LOCAL_MODULE_TAGS := tests
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
index 90a7f62..0d11bcb 100644
--- a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
@@ -20,6 +20,9 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_AAPT_NAMESPACES := true
 LOCAL_MODULE := AaptTestNamespace_LibTwo
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
 LOCAL_SDK_VERSION := current
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
diff --git a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp
index 9aadff3..80404ee 100644
--- a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AaptTestStaticLib_App",
diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp
index 4c81813..a84da43 100644
--- a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp
+++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp
@@ -14,6 +14,15 @@
 // 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_library {
     name: "AaptTestStaticLib_LibOne",
     sdk_version: "current",
diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp
index 7c4f7ed..d386c3a 100644
--- a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp
+++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp
@@ -14,6 +14,15 @@
 // 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_library {
     name: "AaptTestStaticLib_LibTwo",
     sdk_version: "current",
diff --git a/tools/aapt2/integration-tests/SymlinkTest/Android.bp b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
index 68e6148..1e8cf86 100644
--- a/tools/aapt2/integration-tests/SymlinkTest/Android.bp
+++ b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
@@ -14,6 +14,15 @@
 // 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: "AaptSymlinkTest",
     sdk_version: "current",
diff --git a/tools/bit/Android.bp b/tools/bit/Android.bp
index a806271..f6aa0fb 100644
--- a/tools/bit/Android.bp
+++ b/tools/bit/Android.bp
@@ -17,6 +17,15 @@
 // ==========================================================
 // Build the host executable: bit
 // ==========================================================
+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_binary_host {
     name: "bit",
 
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
index 677bee2..e53ba3e 100644
--- a/tools/codegen/Android.bp
+++ b/tools/codegen/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_binary_host {
     name: "codegen_cli",
     manifest: "manifest.txt",
diff --git a/tools/dump-coverage/Android.bp b/tools/dump-coverage/Android.bp
index 94356eb..f381773 100644
--- a/tools/dump-coverage/Android.bp
+++ b/tools/dump-coverage/Android.bp
@@ -15,6 +15,15 @@
 //
 
 // Build variants {target,host} x {32,64}
+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 {
     name: "libdumpcoverage",
     srcs: ["dump_coverage.cc"],
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
deleted file mode 100755
index 28ff606..0000000
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ /dev/null
@@ -1,383 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Generate API lists for non-SDK API enforcement."""
-import argparse
-from collections import defaultdict, namedtuple
-import functools
-import os
-import re
-import sys
-
-# Names of flags recognized by the `hiddenapi` tool.
-FLAG_SDK = 'sdk'
-FLAG_UNSUPPORTED = 'unsupported'
-FLAG_BLOCKED = 'blocked'
-FLAG_MAX_TARGET_O = 'max-target-o'
-FLAG_MAX_TARGET_P = 'max-target-p'
-FLAG_MAX_TARGET_Q = 'max-target-q'
-FLAG_MAX_TARGET_R = 'max-target-r'
-FLAG_CORE_PLATFORM_API = 'core-platform-api'
-FLAG_PUBLIC_API = 'public-api'
-FLAG_SYSTEM_API = 'system-api'
-FLAG_TEST_API = 'test-api'
-
-# List of all known flags.
-FLAGS_API_LIST = [
-    FLAG_SDK,
-    FLAG_UNSUPPORTED,
-    FLAG_BLOCKED,
-    FLAG_MAX_TARGET_O,
-    FLAG_MAX_TARGET_P,
-    FLAG_MAX_TARGET_Q,
-    FLAG_MAX_TARGET_R,
-]
-ALL_FLAGS = FLAGS_API_LIST + [
-    FLAG_CORE_PLATFORM_API,
-    FLAG_PUBLIC_API,
-    FLAG_SYSTEM_API,
-    FLAG_TEST_API,
-]
-
-FLAGS_API_LIST_SET = set(FLAGS_API_LIST)
-ALL_FLAGS_SET = set(ALL_FLAGS)
-
-# Option specified after one of FLAGS_API_LIST to indicate that
-# only known and otherwise unassigned entries should be assign the
-# given flag.
-# For example, the max-target-P list is checked in as it was in P,
-# but signatures have changes since then. The flag instructs this
-# script to skip any entries which do not exist any more.
-FLAG_IGNORE_CONFLICTS = "ignore-conflicts"
-
-# Option specified after one of FLAGS_API_LIST to express that all
-# apis within a given set of packages should be assign the given flag.
-FLAG_PACKAGES = "packages"
-
-# Option specified after one of FLAGS_API_LIST to indicate an extra
-# tag that should be added to the matching APIs.
-FLAG_TAG = "tag"
-
-# Regex patterns of fields/methods used in serialization. These are
-# considered public API despite being hidden.
-SERIALIZATION_PATTERNS = [
-    r'readObject\(Ljava/io/ObjectInputStream;\)V',
-    r'readObjectNoData\(\)V',
-    r'readResolve\(\)Ljava/lang/Object;',
-    r'serialVersionUID:J',
-    r'serialPersistentFields:\[Ljava/io/ObjectStreamField;',
-    r'writeObject\(Ljava/io/ObjectOutputStream;\)V',
-    r'writeReplace\(\)Ljava/lang/Object;',
-]
-
-# Single regex used to match serialization API. It combines all the
-# SERIALIZATION_PATTERNS into a single regular expression.
-SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$')
-
-# Predicates to be used with filter_apis.
-HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
-IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
-
-
-class StoreOrderedOptions(argparse.Action):
-    """An argparse action that stores a number of option arguments in the order that
-    they were specified.
-    """
-    def __call__(self, parser, args, values, option_string = None):
-        items = getattr(args, self.dest, None)
-        if items is None:
-            items = []
-        items.append([option_string.lstrip('-'), values])
-        setattr(args, self.dest, items)
-
-def get_args():
-    """Parses command line arguments.
-
-    Returns:
-        Namespace: dictionary of parsed arguments
-    """
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--output', required=True)
-    parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE',
-        help='CSV files to be merged into output')
-
-    for flag in ALL_FLAGS:
-        parser.add_argument('--' + flag, dest='ordered_flags', metavar='TXT_FILE',
-            action=StoreOrderedOptions, help='lists of entries with flag "' + flag + '"')
-    parser.add_argument('--' + FLAG_IGNORE_CONFLICTS, dest='ordered_flags', nargs=0,
-        action=StoreOrderedOptions, help='Indicates that only known and otherwise unassigned '
-        'entries should be assign the given flag. Must follow a list of entries and applies '
-        'to the preceding such list.')
-    parser.add_argument('--' + FLAG_PACKAGES, dest='ordered_flags', nargs=0,
-        action=StoreOrderedOptions, help='Indicates that the previous list of entries '
-        'is a list of packages. All members in those packages will be given the flag. '
-        'Must follow a list of entries and applies to the preceding such list.')
-    parser.add_argument('--' + FLAG_TAG, dest='ordered_flags', nargs=1,
-        action=StoreOrderedOptions, help='Adds an extra tag to the previous list of entries. '
-        'Must follow a list of entries and applies to the preceding such list.')
-
-    return parser.parse_args()
-
-
-def read_lines(filename):
-    """Reads entire file and return it as a list of lines.
-
-    Lines which begin with a hash are ignored.
-
-    Args:
-        filename (string): Path to the file to read from.
-
-    Returns:
-        Lines of the file as a list of string.
-    """
-    with open(filename, 'r') as f:
-        lines = f.readlines();
-    lines = filter(lambda line: not line.startswith('#'), lines)
-    lines = map(lambda line: line.strip(), lines)
-    return set(lines)
-
-
-def write_lines(filename, lines):
-    """Writes list of lines into a file, overwriting the file if it exists.
-
-    Args:
-        filename (string): Path to the file to be writting into.
-        lines (list): List of strings to write into the file.
-    """
-    lines = map(lambda line: line + '\n', lines)
-    with open(filename, 'w') as f:
-        f.writelines(lines)
-
-
-def extract_package(signature):
-    """Extracts the package from a signature.
-
-    Args:
-        signature (string): JNI signature of a method or field.
-
-    Returns:
-        The package name of the class containing the field/method.
-    """
-    full_class_name = signature.split(";->")[0]
-    # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy
-    if (full_class_name[0] != "L"):
-        raise ValueError("Expected to start with 'L': %s" % full_class_name)
-    full_class_name = full_class_name[1:]
-    # If full_class_name doesn't contain '/', then package_name will be ''.
-    package_name = full_class_name.rpartition("/")[0]
-    return package_name.replace('/', '.')
-
-
-class FlagsDict:
-    def __init__(self):
-        self._dict_keyset = set()
-        self._dict = defaultdict(set)
-
-    def _check_entries_set(self, keys_subset, source):
-        assert isinstance(keys_subset, set)
-        assert keys_subset.issubset(self._dict_keyset), (
-            "Error: {} specifies signatures not present in code:\n"
-            "{}"
-            "Please visit go/hiddenapi for more information.").format(
-                source, "".join(map(lambda x: "  " + str(x) + "\n", keys_subset - self._dict_keyset)))
-
-    def _check_flags_set(self, flags_subset, source):
-        assert isinstance(flags_subset, set)
-        assert flags_subset.issubset(ALL_FLAGS_SET), (
-            "Error processing: {}\n"
-            "The following flags were not recognized: \n"
-            "{}\n"
-            "Please visit go/hiddenapi for more information.").format(
-                source, "\n".join(flags_subset - ALL_FLAGS_SET))
-
-    def filter_apis(self, filter_fn):
-        """Returns APIs which match a given predicate.
-
-        This is a helper function which allows to filter on both signatures (keys) and
-        flags (values). The built-in filter() invokes the lambda only with dict's keys.
-
-        Args:
-            filter_fn : Function which takes two arguments (signature/flags) and returns a boolean.
-
-        Returns:
-            A set of APIs which match the predicate.
-        """
-        return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset))
-
-    def get_valid_subset_of_unassigned_apis(self, api_subset):
-        """Sanitizes a key set input to only include keys which exist in the dictionary
-        and have not been assigned any API list flags.
-
-        Args:
-            entries_subset (set/list): Key set to be sanitized.
-
-        Returns:
-            Sanitized key set.
-        """
-        assert isinstance(api_subset, set)
-        return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
-
-    def generate_csv(self):
-        """Constructs CSV entries from a dictionary.
-
-        Old versions of flags are used to generate the file.
-
-        Returns:
-            List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
-        """
-        lines = []
-        for api in self._dict:
-          flags = sorted(self._dict[api])
-          lines.append(",".join([api] + flags))
-        return sorted(lines)
-
-    def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
-        """Parses CSV entries and merges them into a given dictionary.
-
-        The expected CSV format is:
-            <api signature>,<flag1>,<flag2>,...,<flagN>
-
-        Args:
-            csv_lines (list of strings): Lines read from a CSV file.
-            source (string): Origin of `csv_lines`. Will be printed in error messages.
-
-        Throws:
-            AssertionError if parsed flags are invalid.
-        """
-        # Split CSV lines into arrays of values.
-        csv_values = [ line.split(',') for line in csv_lines ]
-
-        # Update the full set of API signatures.
-        self._dict_keyset.update([ csv[0] for csv in csv_values ])
-
-        # Check that all flags are known.
-        csv_flags = set()
-        for csv in csv_values:
-          csv_flags.update(csv[1:])
-        self._check_flags_set(csv_flags, source)
-
-        # Iterate over all CSV lines, find entry in dict and append flags to it.
-        for csv in csv_values:
-            flags = csv[1:]
-            if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
-                flags.append(FLAG_SDK)
-            self._dict[csv[0]].update(flags)
-
-    def assign_flag(self, flag, apis, source="<unknown>", tag = None):
-        """Assigns a flag to given subset of entries.
-
-        Args:
-            flag (string): One of ALL_FLAGS.
-            apis (set): Subset of APIs to receive the flag.
-            source (string): Origin of `entries_subset`. Will be printed in error messages.
-
-        Throws:
-            AssertionError if parsed API signatures of flags are invalid.
-        """
-        # Check that all APIs exist in the dict.
-        self._check_entries_set(apis, source)
-
-        # Check that the flag is known.
-        self._check_flags_set(set([ flag ]), source)
-
-        # Iterate over the API subset, find each entry in dict and assign the flag to it.
-        for api in apis:
-            self._dict[api].add(flag)
-            if tag:
-                self._dict[api].add(tag)
-
-
-FlagFile = namedtuple('FlagFile', ('flag', 'file', 'ignore_conflicts', 'packages', 'tag'))
-
-def parse_ordered_flags(ordered_flags):
-    r = []
-    currentflag, file, ignore_conflicts, packages, tag = None, None, False, False, None
-    for flag_value in ordered_flags:
-        flag, value = flag_value[0], flag_value[1]
-        if flag in ALL_FLAGS_SET:
-            if currentflag:
-                r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
-                ignore_conflicts, packages, tag = False, False, None
-            currentflag = flag
-            file = value
-        else:
-            if currentflag is None:
-                raise argparse.ArgumentError('--%s is only allowed after one of %s' % (
-                    flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET])))
-            if flag == FLAG_IGNORE_CONFLICTS:
-                ignore_conflicts = True
-            elif flag == FLAG_PACKAGES:
-                packages = True
-            elif flag == FLAG_TAG:
-                tag = value[0]
-
-
-    if currentflag:
-        r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
-    return r
-
-
-def main(argv):
-    # Parse arguments.
-    args = vars(get_args())
-    flagfiles = parse_ordered_flags(args['ordered_flags'])
-
-    # Initialize API->flags dictionary.
-    flags = FlagsDict()
-
-    # Merge input CSV files into the dictionary.
-    # Do this first because CSV files produced by parsing API stubs will
-    # contain the full set of APIs. Subsequent additions from text files
-    # will be able to detect invalid entries, and/or filter all as-yet
-    # unassigned entries.
-    for filename in args["csv"]:
-        flags.parse_and_merge_csv(read_lines(filename), filename)
-
-    # Combine inputs which do not require any particular order.
-    # (1) Assign serialization API to SDK.
-    flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
-
-    # (2) Merge text files with a known flag into the dictionary.
-    for info in flagfiles:
-        if (not info.ignore_conflicts) and (not info.packages):
-            flags.assign_flag(info.flag, read_lines(info.file), info.file, info.tag)
-
-    # Merge text files where conflicts should be ignored.
-    # This will only assign the given flag if:
-    # (a) the entry exists, and
-    # (b) it has not been assigned any other flag.
-    # Because of (b), this must run after all strict assignments have been performed.
-    for info in flagfiles:
-        if info.ignore_conflicts:
-            valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(info.file))
-            flags.assign_flag(info.flag, valid_entries, filename, info.tag)
-
-    # All members in the specified packages will be assigned the appropriate flag.
-    for info in flagfiles:
-        if info.packages:
-            packages_needing_list = set(read_lines(info.file))
-            should_add_signature_to_list = lambda sig,lists: extract_package(
-                sig) in packages_needing_list and not lists
-            valid_entries = flags.filter_apis(should_add_signature_to_list)
-            flags.assign_flag(info.flag, valid_entries, info.file, info.tag)
-
-    # Mark all remaining entries as blocked.
-    flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
-
-    # Write output.
-    write_lines(args["output"], flags.generate_csv())
-
-if __name__ == "__main__":
-    main(sys.argv)
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
deleted file mode 100755
index 82d117f..0000000
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the 'License');
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an 'AS IS' BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Unit tests for Hidden API list generation."""
-import unittest
-from generate_hiddenapi_lists import *
-
-class TestHiddenapiListGeneration(unittest.TestCase):
-
-    def test_filter_apis(self):
-        # Initialize flags so that A and B are put on the whitelist and
-        # C, D, E are left unassigned. Try filtering for the unassigned ones.
-        flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
-                        'C', 'D', 'E'])
-        filter_set = flags.filter_apis(lambda api, flags: not flags)
-        self.assertTrue(isinstance(filter_set, set))
-        self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
-
-    def test_get_valid_subset_of_unassigned_keys(self):
-        # Create flags where only A is unassigned.
-        flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
-        flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
-        self.assertEqual(flags.generate_csv(),
-            [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ])
-
-        # Check three things:
-        # (1) B is selected as valid unassigned
-        # (2) A is not selected because it is assigned 'whitelist'
-        # (3) D is not selected because it is not a valid key
-        self.assertEqual(
-            flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
-
-    def test_parse_and_merge_csv(self):
-        flags = FlagsDict()
-
-        # Test empty CSV entry.
-        self.assertEqual(flags.generate_csv(), [])
-
-        # Test new additions.
-        flags.parse_and_merge_csv([
-            'A,' + FLAG_UNSUPPORTED,
-            'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
-            'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
-            'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
-            'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
-        ])
-        self.assertEqual(flags.generate_csv(), [
-            'A,' + FLAG_UNSUPPORTED,
-            'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O,
-            'C,' + FLAG_SYSTEM_API + ',' + FLAG_SDK,
-            'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
-            'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
-        ])
-
-        # Test unknown flag.
-        with self.assertRaises(AssertionError):
-            flags.parse_and_merge_csv([ 'Z,foo' ])
-
-    def test_assign_flag(self):
-        flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
-
-        # Test new additions.
-        flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
-        self.assertEqual(flags.generate_csv(),
-            [ 'A,' + FLAG_UNSUPPORTED + "," + FLAG_SDK, 'B,' + FLAG_UNSUPPORTED ])
-
-        # Test invalid API signature.
-        with self.assertRaises(AssertionError):
-            flags.assign_flag(FLAG_SDK, set([ 'C' ]))
-
-        # Test invalid flag.
-        with self.assertRaises(AssertionError):
-            flags.assign_flag('foo', set([ 'A' ]))
-
-    def test_extract_package(self):
-        signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
-        expected_package = 'com.foo.bar'
-        self.assertEqual(extract_package(signature), expected_package)
-
-        signature = 'Lcom/foo1/bar/MyClass;->method2()V'
-        expected_package = 'com.foo1.bar'
-        self.assertEqual(extract_package(signature), expected_package)
-
-        signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
-        expected_package = 'com.foo_bar.baz'
-        self.assertEqual(extract_package(signature), expected_package)
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
deleted file mode 100755
index 6a5b0e1..0000000
--- a/tools/hiddenapi/merge_csv.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
-Merge multiple CSV files, possibly with different columns.
-"""
-
-import argparse
-import csv
-import io
-
-from zipfile import ZipFile
-
-args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
-args_parser.add_argument('--header', help='Comma separated field names; '
-                                          'if missing determines the header from input files.')
-args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
-args_parser.add_argument('--output', help='Output file for merged CSV.',
-                         default='-', type=argparse.FileType('w'))
-args_parser.add_argument('files', nargs=argparse.REMAINDER)
-args = args_parser.parse_args()
-
-
-def dict_reader(input):
-    return csv.DictReader(input, delimiter=',', quotechar='|')
-
-
-if args.zip_input and len(args.files) > 0:
-    raise ValueError('Expecting either a single ZIP with CSV files'
-                     ' or a list of CSV files as input; not both.')
-
-csv_readers = []
-if len(args.files) > 0:
-    for file in args.files:
-        csv_readers.append(dict_reader(open(file, 'r')))
-elif args.zip_input:
-    with ZipFile(args.zip_input) as zip:
-        for entry in zip.namelist():
-            if entry.endswith('.uau'):
-                csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
-
-headers = set()
-if args.header:
-    fieldnames = args.header.split(',')
-else:
-    # Build union of all columns from source files:
-    for reader in csv_readers:
-        headers = headers.union(reader.fieldnames)
-    fieldnames = sorted(headers)
-
-# Concatenate all files to output:
-writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
-                        dialect='unix', fieldnames=fieldnames)
-writer.writeheader()
-for reader in csv_readers:
-    for row in reader:
-        writer.writerow(row)
diff --git a/tools/incident_report/Android.bp b/tools/incident_report/Android.bp
index f2d0d0f..fe519c7 100644
--- a/tools/incident_report/Android.bp
+++ b/tools/incident_report/Android.bp
@@ -17,6 +17,15 @@
 // ==========================================================
 // Build the host executable: incident_report
 // ==========================================================
+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_binary_host {
     name: "incident_report",
 
diff --git a/tools/incident_section_gen/Android.bp b/tools/incident_section_gen/Android.bp
index 0c7797e..8227b60 100644
--- a/tools/incident_section_gen/Android.bp
+++ b/tools/incident_section_gen/Android.bp
@@ -17,6 +17,15 @@
 // ==========================================================
 // Build the host executable: incident-section-gen
 // ==========================================================
+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_binary_host {
     name: "incident-section-gen",
     cflags: [
diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp
index 7b2ca9a..cabe139 100644
--- a/tools/lock_agent/Android.bp
+++ b/tools/lock_agent/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 {
     name: "liblockagent",
     host_supported: false,
diff --git a/tools/locked_region_code_injection/Android.bp b/tools/locked_region_code_injection/Android.bp
index 5f81a2e..98c0e69 100644
--- a/tools/locked_region_code_injection/Android.bp
+++ b/tools/locked_region_code_injection/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_binary_host {
     name: "lockedregioncodeinjection",
     manifest: "manifest.txt",
diff --git a/tools/obbtool/Android.bp b/tools/obbtool/Android.bp
index f879658..1c50d18 100644
--- a/tools/obbtool/Android.bp
+++ b/tools/obbtool/Android.bp
@@ -4,6 +4,15 @@
 // Opaque Binary Blob (OBB) Tool
 //
 
+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_binary_host {
     name: "obbtool",
 
diff --git a/tools/powermodel/Android.bp b/tools/powermodel/Android.bp
index f597aab..35c1356 100644
--- a/tools/powermodel/Android.bp
+++ b/tools/powermodel/Android.bp
@@ -1,4 +1,13 @@
 
+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_host {
     name: "powermodel",
     srcs: [
@@ -23,4 +32,3 @@
         "mockito",
     ],
 }
-
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index aaa6d76..73caac6 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/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"],
+}
+
 java_test_host {
     name: "PreloadCheck",
     srcs: ["src/**/*.java"],
diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp
index f40d8ba..2a866c4 100644
--- a/tools/preload-check/device/Android.bp
+++ b/tools/preload-check/device/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"],
+}
+
 java_test_helper_library {
     name: "preload-check-device",
     host_supported: false,
diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp
index 809ee47..fad015a 100644
--- a/tools/preload/Android.bp
+++ b/tools/preload/Android.bp
@@ -1,3 +1,13 @@
+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
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library_host {
     name: "preload",
     srcs: [
diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp
index 6f12015..ba36061 100644
--- a/tools/preload/loadclass/Android.bp
+++ b/tools/preload/loadclass/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_test {
     name: "loadclass",
     srcs: ["**/*.java"],
diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp
index 58a7d34..1e50976 100644
--- a/tools/processors/staledataclass/Android.bp
+++ b/tools/processors/staledataclass/Android.bp
@@ -1,4 +1,13 @@
 
+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_plugin {
     name: "staledataclass-annotation-processor",
     processor_class: "android.processor.staledataclass.StaleDataclassProcessor",
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 069e61f..ea9974f 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/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_plugin {
     name: "view-inspector-annotation-processor",
 
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index ce551bd..56351e3 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/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_host {
     name: "protologtool-lib",
     srcs: [
diff --git a/tools/sdkparcelables/Android.bp b/tools/sdkparcelables/Android.bp
index 00fb8aa..9d773e4 100644
--- a/tools/sdkparcelables/Android.bp
+++ b/tools/sdkparcelables/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_binary_host {
     name: "sdkparcelables",
     manifest: "manifest.txt",
diff --git a/tools/split-select/Android.bp b/tools/split-select/Android.bp
index ee822b7..c12fc6a 100644
--- a/tools/split-select/Android.bp
+++ b/tools/split-select/Android.bp
@@ -19,6 +19,15 @@
 // targets here.
 // ==========================================================
 
+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_defaults {
     name: "split-select_defaults",
 
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 1390f63..1ec83a3 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -17,6 +17,15 @@
 // ==========================================================
 // Build the host executable: protoc-gen-javastream
 // ==========================================================
+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_defaults {
     name: "protoc-gen-stream-defaults",
     srcs: [
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 819e75b..9fcf034 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -4,6 +4,15 @@
 // Keymap validation tool.
 //
 
+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_binary_host {
     name: "validatekeymaps",
 
diff --git a/wifi/java/Android.bp b/wifi/java/Android.bp
index b35b4be..225e750 100644
--- a/wifi/java/Android.bp
+++ b/wifi/java/Android.bp
@@ -16,6 +16,15 @@
 // updatable), and are generally only called by the Wifi module.
 
 // necessary since we only want the `path` property to only refer to these files
+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-wifi-non-updatable-sources-internal",
     srcs: ["src/**/*.java"],
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 3f5cacf..c9105f7 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/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: "FrameworksWifiNonUpdatableApiTests",