Merge "OWNERS for InlineSuggestion* in view/inputmethod"
diff --git a/Android.bp b/Android.bp
index 402cf1c..6a0bdc3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -574,6 +574,7 @@
     ],
     sdk_version: "core_platform",
     static_libs: [
+        "bouncycastle-repackaged-unbundled",
         "framework-internal-utils",
         // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
         // in favor of an API stubs dependency in java_library "framework" below.
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 64ee09c..6afed7a 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -113,7 +113,7 @@
         last_released: {
             api_file: ":android-non-updatable.api.public.latest",
             removed_api_file: ":android-non-updatable-removed.api.public.latest",
-            baseline_file: ":public-api-incompatibilities-with-last-released",
+            baseline_file: ":android-incompatibilities.api.public.latest",
         },
         api_lint: {
             enabled: true,
@@ -165,7 +165,7 @@
         last_released: {
             api_file: ":android-non-updatable.api.system.latest",
             removed_api_file: ":android-non-updatable-removed.api.system.latest",
-            baseline_file: ":system-api-incompatibilities-with-last-released"
+            baseline_file: ":android-incompatibilities.api.system.latest"
         },
         api_lint: {
             enabled: true,
diff --git a/apct-tests/perftests/core/src/android/os/OWNERS b/apct-tests/perftests/core/src/android/os/OWNERS
new file mode 100644
index 0000000..a1719c9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/OWNERS
@@ -0,0 +1 @@
+per-file PackageParsingPerfTest.kt = file:/services/core/java/com/android/server/pm/OWNERS
\ No newline at end of file
diff --git a/apex/Android.bp b/apex/Android.bp
index 0a535a8..1876110 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_visibility: [":__subpackages__"],
+}
+
 mainline_stubs_args =
     "--error UnhiddenSystemApi " +
     "--hide BroadcastBehavior " +
+    "--hide CallbackInterface " +
     "--hide DeprecationMismatch " +
     "--hide HiddenSuperclass " +
     "--hide HiddenTypedefConstant " +
@@ -96,6 +101,10 @@
         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],
 
@@ -135,6 +144,13 @@
         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.
@@ -146,6 +162,10 @@
         enabled: true,
         sdk_version: "module_current",
     },
+    defaults_visibility: [
+        ":__subpackages__",
+        "//packages/modules:__subpackages__",
+    ],
 }
 
 stubs_defaults {
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 2469351..3499553 100644
--- a/apex/blobstore/framework/Android.bp
+++ b/apex/blobstore/framework/Android.bp
@@ -19,6 +19,7 @@
         "java/**/*.aidl"
     ],
     path: "java",
+    visibility: ["//frameworks/base"],
 }
 
 java_library {
diff --git a/apex/blobstore/service/Android.bp b/apex/blobstore/service/Android.bp
index 22b0cbe..f6cbac1 100644
--- a/apex/blobstore/service/Android.bp
+++ b/apex/blobstore/service/Android.bp
@@ -25,4 +25,9 @@
         "services.core",
         "services.usage",
     ],
+    visibility: [
+        // These are required until blobstore is properly unbundled.
+        "//frameworks/base/services",
+        "//frameworks/base/services/tests/mockingservicestests",
+    ],
 }
diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp
index ec07426..23f5614f 100644
--- a/apex/jobscheduler/framework/Android.bp
+++ b/apex/jobscheduler/framework/Android.bp
@@ -8,6 +8,7 @@
         "java/android/os/IDeviceIdleController.aidl",
     ],
     path: "java",
+    visibility: ["//frameworks/base"],
 }
 
 java_library {
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 69a9fd8..6ddba69 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -13,4 +13,12 @@
         "framework",
         "services.core",
     ],
+    visibility: [
+        "//frameworks/base/apex/jobscheduler:__subpackages__",
+        // These are required until jobscheduler is properly unbundled.
+        "//frameworks/base/services",
+        "//frameworks/base/services/tests/mockingservicestests",
+        "//frameworks/base/services/tests/servicestests",
+        "//frameworks/base/tests/JobSchedulerPerfTests",
+    ],
 }
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
new file mode 100644
index 0000000..5f1bd37
--- /dev/null
+++ b/apex/media/Android.bp
@@ -0,0 +1,20 @@
+// 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 {
+    default_visibility: [
+        ":__subpackages__",
+        "//frameworks/av/apex",
+        "//frameworks/av/apex/testing",
+    ],
+}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index ce4b030..0ff6d44 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -49,6 +49,10 @@
         "test_com.android.media",
     ],
     min_sdk_version: "29",
+    visibility: [
+        "//frameworks/av/apex:__subpackages__",
+        "//frameworks/base", // For framework-all
+    ],
 }
 
 filegroup {
@@ -58,6 +62,7 @@
         ":mediasession2-java-srcs",
         ":mediasession2-aidl-srcs",
     ],
+    visibility: ["//frameworks/base"],
 }
 
 filegroup {
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
deleted file mode 100644
index e30df05..0000000
--- a/apex/permission/Android.bp
+++ /dev/null
@@ -1,43 +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.
-
-apex {
-    name: "com.android.permission",
-    defaults: ["com.android.permission-defaults"],
-    manifest: "apex_manifest.json",
-}
-
-apex_defaults {
-    name: "com.android.permission-defaults",
-    updatable: true,
-    min_sdk_version: "30",
-    key: "com.android.permission.key",
-    certificate: ":com.android.permission.certificate",
-    java_libs: [
-        "framework-permission",
-        "service-permission",
-    ],
-    apps: ["PermissionController"],
-}
-
-apex_key {
-    name: "com.android.permission.key",
-    public_key: "com.android.permission.avbpubkey",
-    private_key: "com.android.permission.pem",
-}
-
-android_app_certificate {
-    name: "com.android.permission.certificate",
-    certificate: "com.android.permission",
-}
diff --git a/apex/permission/OWNERS b/apex/permission/OWNERS
deleted file mode 100644
index 957e10a..0000000
--- a/apex/permission/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-svetoslavganov@google.com
-moltmann@google.com
-eugenesusla@google.com
-zhanghai@google.com
-evanseverson@google.com
-ntmyren@google.com
diff --git a/apex/permission/TEST_MAPPING b/apex/permission/TEST_MAPPING
deleted file mode 100644
index 6e67ce9..0000000
--- a/apex/permission/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit" : [
-    {
-      "name" : "PermissionApexTests"
-    }
-  ]
-}
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
deleted file mode 100644
index 7960598..0000000
--- a/apex/permission/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.permission",
-  "version": 300000000
-}
diff --git a/apex/permission/com.android.permission.avbpubkey b/apex/permission/com.android.permission.avbpubkey
deleted file mode 100644
index 9eaf852..0000000
--- a/apex/permission/com.android.permission.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.pem b/apex/permission/com.android.permission.pem
deleted file mode 100644
index 3d584be..0000000
--- a/apex/permission/com.android.permission.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKgIBAAKCAgEA6snt4eqoz85xiL9Sf6w1S1b9FgSHK05zYTh2JYPvQKQ3yeZp
-E6avJ6FN6XcbmkDzSd658BvUGDBSPhOlzuUO4BsoKBuLMxP6TxIQXFKidzDqY0vQ
-4qkS++bdIhUjwBP3OSZ3Czu0BiihK8GC75Abr//EyCyObGIGGfHEGANiOgrpP4X5
-+OmLzQLCjk4iE1kg+U6cRSRI/XLaoWC0TvIIuzxznrQ6r5GmzgTOwyBWyIB+bj73
-bmsweHTU+w9Y7kGOx4hO3XCLIhoBWEw0EbuW9nZmQ4sZls5Jo/CbyJlCclF11yVo
-SCf2LG/T+9pah5NOmDQ1kPbU+0iKZIV4YFHGTIhyGDE/aPOuUT05ziCGDifgHr0u
-SG1x/RLqsVh/POvNxnvP9cQFMQ08BvbEJaTTgB785iwKsvdqCfmng/SAyxSetmzP
-StXVB3fh1OoZ8vunRbQYxnmUxycVqaA96zmBx2wLvbvzKo7pZFDE6nbhnT5+MRAM
-z/VIK89W26uB4gj8sBFslqZjT0jPqsAZuvDm7swOtMwIcEolyGJuFLqlhN7UwMz2
-9y8+IpYixR+HvD1TZI9NtmuCmv3kPrWgoMZg6yvaBayTIr8RdYzi6FO/C1lLiraz
-48dH3sXWRa8cgw6VcSUwYrEBIc3sotdsupO1iOjcFybIwaee0YTZJfjvbqkCAwEA
-AQKCAgEArRnfdpaJi1xLPGTCMDsIt9kUku0XswgN7PmxsYsKFAB+2S40/jYAIRm9
-1YjpItsMA8RgFfSOdJ77o6TctCMQyo17F8bm4+uwuic5RLfv7Cx2QmsdQF8jDfFx
-y7UGPJD7znjbf76uxXOjEB2FqZX3s9TAgkzHXIUQtoQW7RVhkCWHPjxKxgd5+NY2
-FrDoUpd9xhD9CcTsw1+wbRZdGW88nL6/B50dP2AFORM2VYo8MWr6y9FEn3YLsGOC
-uu7fxBk1aUrHyl81VRkTMMROB1zkuiUk1FtzrEm+5U15rXXBFYOVe9+qeLhtuOlh
-wueDoz0pzvF/JLe24uTik6YL0Ae6SD0pFXQ2KDrdH3cUHLok3r76/yGzaDNTFjS2
-2WbQ8dEJV8veNHk8gjGpFTJIsBUlcZpmUCDHlfvVMb3+2ahQ+28piQUt5t3zqJdZ
-NDqsOHzY6BRPc+Wm85Xii/lWiQceZSee/b1Enu+nchsyXhSenBfC6bIGZReyMI0K
-KKKuVhyR6OSOiR5ZdZ/NyXGqsWy05fn/h0X9hnpETsNaNYNKWvpHLfKll+STJpf7
-AZquJPIclQyiq5NONx6kfPztoCLkKV/zOgIj3Sx5oSZq+5gpO91nXWVwkTbqK1d1
-004q2Mah6UQyAk1XGQc2pHx7ouVcWawjU30vZ4C015Hv2lm/gVkCggEBAPltATYS
-OqOSL1YAtIHPiHxMjNAgUdglq8JiJFXVfkocGU9eNub3Ed3sSWu6GB9Myu/sSKje
-bJ5DZqxJnvB2Fqmu9I9OunLGFSD0aXs4prwsQ1Rm5FcbImtrxcciASdkoo8Pj0z4
-vk2r2NZD3VtER5Uh+YjSDkxcS9gBStXUpCL6gj69UpOxMmWqZVjyHatVB4lEvYJl
-N82uT7N7QVNL1DzcZ9z4C4r7ks1Pm7ka12s5m/oaAlAMdVeofiPJe1xA9zRToSr4
-tIbMkOeXFLVRLuji/7XsOgal5Rl59p+OwLshX5cswPVOMrH6zt+hbsJ5q8M5dqnX
-VAOBK7KNQ/EKZwcCggEBAPD6KVvyCim46n5EbcEqCkO7gevwZkw/9vLwmM5YsxTh
-z9FQkPO0iB7mwbX8w04I91Pre4NdfcgMG0pP1b13Sb4KHBchqW1a+TCs3kSGC6gn
-1SxmXHnA9jRxAkrWlGkoAQEz+aP61cXiiy2tXpQwJ8xQCKprfoqWZwhkCtEVU6CE
-S7v9cscOHIqgNxx4WoceMmq4EoihHAZzHxTcNVbByckMjb2XQJ0iNw3lDP4ddvc+
-a4HzHfHkhzeQ5ZNc8SvWU8z80aSCOKRsSD3aUTZzxhZ4O2tZSW7v7p+FpvVee7bC
-g8YCfszTdpVUMlLRLjScimAcovcFLSvtyupinxWg4M8CggEAN9YGEmOsSte7zwXj
-YrfhtumwEBtcFwX/2Ej+F1Tuq4p0xAa0RaoDjumJWhtTsRYQy/raHSuFpzwxbNoi
-QXQ+CIhI6RfXtz/OlQ0B2/rHoJJMFEXgUfuaDfAXW0eqeHYXyezSyIlamKqipPyW
-Pgsf9yue39keKEv1EorfhNTQVaA8rezV4oglXwrxGyNALw2e3UTNI7ai8mFWKDis
-XAg6n9E7UwUYGGnO6DUtCBgRJ0jDOQ6/e8n+LrxiWIKPIgzNCiK6jpMUXqTGv4Fb
-umdNGAdQ9RnHt5tFmRlrczaSwJFtA7uaCpAR2zPpQbiywchZAiAIB2dTwGEXNiZX
-kksg2wKCAQEA6pNad3qhkgPDoK6T+Jkn7M82paoaqtcJWWwEE7oceZNnbWZz9Agl
-CY+vuawXonrv5+0vCq2Tp4zBdBFLC2h3jFrjBVFrUFxifpOIukOSTVqZFON/2bWQ
-9XOcu6UuSz7522Xw+UNPnZXtzcUacD6AP08ZYGvLfrTyDyTzspyED5k48ALEHCkM
-d5WGkFxII4etpF0TDZVnZo/iDbhe49k4yFFEGO6Ho26PESOLBkNAb2V/2bwDxlij
-l9+g21Z6HiZA5SamHPH2mXgeyrcen1cL2QupK9J6vVcqfnboE6qp2zp2c+Yx8MlY
-gfy4EA44YFaSDQVTTgrn8f9Eq+zc130H2QKCAQEAqOKgv68nIPdDSngNyCVyWego
-boFiDaEJoBBg8FrBjTJ6wFLrNAnXmbvfTtgNmNAzF1cUPJZlIIsHgGrMCfpehbXq
-WQQIw+E+yFbTGLxseGRfsLrV0CsgnAoOVeod+yIHmqc3livaUbrWhL1V2f6Ue+sE
-7YLp/iP43NaMfA4kYk2ep7+ZJoEVkCjHJJaHWgAG3RynPJHkTJlSgu7wLYvGc9uE
-ZsEFUM46lX02t7rrtMfasVGrUy1c2xOxFb4v1vG6iEZ7+YWeq5o3AkxUwEGn+mG4
-/3p+k4AaTXJDXgyZ0Sv6CkGuPHenAYG4cswcUUEf/G4Ag77x6LBNMgycJBxUJA==
------END RSA PRIVATE KEY-----
diff --git a/apex/permission/com.android.permission.pk8 b/apex/permission/com.android.permission.pk8
deleted file mode 100644
index d51673d..0000000
--- a/apex/permission/com.android.permission.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.x509.pem b/apex/permission/com.android.permission.x509.pem
deleted file mode 100644
index 4b146c9..0000000
--- a/apex/permission/com.android.permission.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGKzCCBBOgAwIBAgIUezo3fQeVZsmLpm/dkpGWJ/G/MN8wDQYJKoZIhvcNAQEL
-BQAwgaMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMR8wHQYDVQQDDBZjb20uYW5kcm9pZC5wZXJtaXNzaW9uMSIwIAYJKoZIhvcN
-AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MTAwOTIxMzExOVoYDzQ3NTcw
-OTA0MjEzMTE5WjCBozELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
-FjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNV
-BAsMB0FuZHJvaWQxHzAdBgNVBAMMFmNvbS5hbmRyb2lkLnBlcm1pc3Npb24xIjAg
-BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCxefguRJ7E6tBCTEOeU2HJEGs6AQQapLz9hMed0aaJ
-Qr7aTQiYJEk+sG4+jPYbjpxa8JDDzJHp+4g7DjfSb+dvT9n84A8lWaI/yRXTZTQN
-Hu5m/bgHhi0LbySpiaFyodXBKUAnOhZyGPtYjtBFywFylueub8ryc1Z6UxxU7udH
-1mkIr7sE48Qkq5SyjFROE96iFmYA+vS/JXOfS0NBHiMB4GBxx4V7kXpvrTI7hhZG
-HiyhKvNh7wyHIhO9nDEw1rwtAH6CsL3YkQEVBeAU98m+0Au+qStLYkKHh2l8zT4W
-7sVK1VSqfB+VqOUmeIGdzlBfqMsoXD+FJz6KnIdUHIwjFDjL7Xr+hd+7xve+Q3S+
-U3Blk/U6atY8PM09wNfilG+SvwcKk5IgriDcu3rWKgIFxbUUaxLrDW7pLlu6wt/d
-GGtKK+Bc0jF+9Z901Tl33i5xhc5yOktT0btkKs7lSeE6VzP/Nk5g0SuzixmuRoh9
-f5Ge41N2ZCEHNXx3wZeVZwHIIPfYrL7Yql1Xoxbfs4ETFk6ChzVQcvjfDQQuK58J
-uNc+TOCoI/qflXwGCwpuHl0ier8V5Z4tpMUl5rWyVR/QGRtLPvs2lLuxczDw1OXq
-wEVtCMn9aNnd4y7R9PZ52hi53HAvDjpWefrLYi+Q04J6iGFQ1qAFBClK9DquBvmR
-swIDAQABo1MwUTAdBgNVHQ4EFgQULpfus5s5SrqLkoUKyPXA0D1iHPMwHwYDVR0j
-BBgwFoAULpfus5s5SrqLkoUKyPXA0D1iHPMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
-hkiG9w0BAQsFAAOCAgEAjxQG5EFv8V/9yV2glI53VOmlWMjfEgvUjd39s/XLyPlr
-OzPOKSB0NFo8To3l4l+MsManxPK8y0OyfEVKbWVz9onv0ovo5MVokBmV/2G0jmsV
-B4e9yjOq+DmqIvY/Qh63Ywb97sTgcFI8620MhQDbh2IpEGv4ZNV0H6rgXmgdSCBw
-1EjBoYfFpN5aMgZjeyzZcq+d1IapdWqdhuEJQkMvoYS4WIumNIJlEXPQRoq/F5Ih
-nszdbKI/jVyiGFa2oeZ3rja1Y6GCRU8TYEoKx1pjS8uQDOEDTwsG/QnUe9peEj0V
-SsCkIidJWTomAmq9Tub9vpBe1zuTpuRAwxwR0qwgSxozV1Mvow1dJ19oFtHX0yD6
-ZjCpRn5PW9kMvSWSlrcrFs1NJf0j1Cvf7bHpkEDqLqpMnnh9jaFQq3nzDY+MWcIR
-jDcgQpI+AiE2/qtauZnFEVhbce49nCnk9+5bpTTIZJdzqeaExe5KXHwEtZLaEDh4
-atLY9LuEvPsjmDIMOR6hycD9FvwGXhJOQBjESIWFwigtSb1Yud9n6201jw3MLJ4k
-+WhkbmZgWy+xc+Mdm5H3XyB1lvHaHGkxu+QB9KyQuVQKwbUVcbwZIfTFPN6Zr/dS
-ZXJqAbBhG/dBgF0LazuLaPVpibi+a3Y+tb9b8eXGkz4F97PWZIEDkELQ+9KOvhc=
------END CERTIFICATE-----
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
deleted file mode 100644
index 1a2d5d5..0000000
--- a/apex/permission/framework/Android.bp
+++ /dev/null
@@ -1,48 +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.
-
-filegroup {
-    name: "framework-permission-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-    ],
-    path: "java",
-}
-
-java_sdk_library {
-    name: "framework-permission",
-    defaults: ["framework-module-defaults"],
-
-    // Restrict access to implementation library.
-    impl_library_visibility: [
-        "//frameworks/base/apex/permission:__subpackages__",
-        "//packages/modules/Permission:__subpackages__",
-    ],
-
-    srcs: [
-        ":framework-permission-sources",
-    ],
-
-    apex_available: [
-        "com.android.permission",
-        "test_com.android.permission",
-    ],
-    permitted_packages: [
-        "android.permission",
-        "android.app.role",
-    ],
-    hostdex: true,
-    installable: true,
-}
diff --git a/apex/permission/framework/api/current.txt b/apex/permission/framework/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-current.txt b/apex/permission/framework/api/module-lib-current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-removed.txt b/apex/permission/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/removed.txt b/apex/permission/framework/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-current.txt b/apex/permission/framework/api/system-current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-removed.txt b/apex/permission/framework/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/java/android/permission/PermissionState.java b/apex/permission/framework/java/android/permission/PermissionState.java
deleted file mode 100644
index e810db8..0000000
--- a/apex/permission/framework/java/android/permission/PermissionState.java
+++ /dev/null
@@ -1,22 +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.permission;
-
-/**
- * @hide
- */
-public class PermissionState {}
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
deleted file mode 100644
index cc6f201..0000000
--- a/apex/permission/service/Android.bp
+++ /dev/null
@@ -1,45 +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.
-
-filegroup {
-    name: "service-permission-sources",
-    srcs: [
-        "java/**/*.java",
-    ],
-    path: "java",
-}
-
-java_sdk_library {
-    name: "service-permission",
-    defaults: ["framework-system-server-module-defaults"],
-    impl_library_visibility: [
-        "//frameworks/base/apex/permission/tests",
-        "//frameworks/base/services/tests/mockingservicestests",
-        "//frameworks/base/services/tests/servicestests",
-        "//packages/modules/Permission/tests",
-    ],
-    srcs: [
-        ":service-permission-sources",
-    ],
-    libs: [
-        "framework-permission",
-    ],
-    apex_available: [
-        "com.android.permission",
-        "test_com.android.permission",
-    ],
-    installable: true,
-    // We don't have last-api tracking files for the public part of this jar's API.
-    unsafe_ignore_missing_latest_api: true,
-}
diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/service/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/api/removed.txt b/apex/permission/service/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/service/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt
deleted file mode 100644
index c76cc32..0000000
--- a/apex/permission/service/api/system-server-current.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-// Signature format: 2.0
-package com.android.permission.persistence {
-
-  public interface RuntimePermissionsPersistence {
-    method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RuntimePermissionsState {
-    ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
-    method @Nullable public String getFingerprint();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
-    method public int getVersion();
-    field public static final int NO_VERSION = -1; // 0xffffffff
-  }
-
-  public static final class RuntimePermissionsState.PermissionState {
-    ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
-    method public int getFlags();
-    method @NonNull public String getName();
-    method public boolean isGranted();
-  }
-
-}
-
-package com.android.role.persistence {
-
-  public interface RolesPersistence {
-    method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RolesState {
-    ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
-    method @Nullable public String getPackagesHash();
-    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
-    method public int getVersion();
-  }
-
-}
-
diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/permission/service/api/system-server-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
deleted file mode 100644
index 569a78c..0000000
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ /dev/null
@@ -1,40 +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 com.android.permission.persistence;
-
-import android.annotation.NonNull;
-
-/**
- * Utility class for IO.
- *
- * @hide
- */
-public class IoUtils {
-
-    private IoUtils() {}
-
-    /**
-     * Close 'closeable' ignoring any exceptions.
-     */
-    public static void closeQuietly(@NonNull AutoCloseable closeable) {
-        try {
-            closeable.close();
-        } catch (Exception ignored) {
-            // Ignored.
-        }
-    }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
deleted file mode 100644
index aedba29..0000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ /dev/null
@@ -1,74 +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 com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RuntimePermissionsPersistence {
-
-    /**
-     * Read the runtime permissions from persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param user the user to read for
-     * @return the runtime permissions read
-     */
-    @Nullable
-    RuntimePermissionsState readForUser(@NonNull UserHandle user);
-
-    /**
-     * Write the runtime permissions to persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param runtimePermissions the runtime permissions to write
-     * @param user the user to write for
-     */
-    void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
-            @NonNull UserHandle user);
-
-    /**
-     * Delete the runtime permissions from persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param user the user to delete for
-     */
-    void deleteForUser(@NonNull UserHandle user);
-
-    /**
-     * Create a new instance of {@link RuntimePermissionsPersistence} implementation.
-     *
-     * @return the new instance.
-     */
-    @NonNull
-    static RuntimePermissionsPersistence createInstance() {
-        return new RuntimePermissionsPersistenceImpl();
-    }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
deleted file mode 100644
index e43f59a..0000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ /dev/null
@@ -1,265 +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 com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Persistence implementation for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPersistence {
-
-    private static final String LOG_TAG = RuntimePermissionsPersistenceImpl.class.getSimpleName();
-
-    private static final String APEX_MODULE_NAME = "com.android.permission";
-
-    private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
-
-    private static final String TAG_PACKAGE = "package";
-    private static final String TAG_PERMISSION = "permission";
-    private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
-    private static final String TAG_SHARED_USER = "shared-user";
-
-    private static final String ATTRIBUTE_FINGERPRINT = "fingerprint";
-    private static final String ATTRIBUTE_FLAGS = "flags";
-    private static final String ATTRIBUTE_GRANTED = "granted";
-    private static final String ATTRIBUTE_NAME = "name";
-    private static final String ATTRIBUTE_VERSION = "version";
-
-    @Nullable
-    @Override
-    public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
-        File file = getFile(user);
-        try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(inputStream, null);
-            return parseXml(parser);
-        } catch (FileNotFoundException e) {
-            Log.i(LOG_TAG, "runtime-permissions.xml not found");
-            return null;
-        } catch (XmlPullParserException | IOException e) {
-            throw new IllegalStateException("Failed to read runtime-permissions.xml: " + file , e);
-        }
-    }
-
-    @NonNull
-    private static RuntimePermissionsState parseXml(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_RUNTIME_PERMISSIONS)) {
-                return parseRuntimePermissions(parser);
-            }
-        }
-        throw new IllegalStateException("Missing <" + TAG_RUNTIME_PERMISSIONS
-                + "> in runtime-permissions.xml");
-    }
-
-    @NonNull
-    private static RuntimePermissionsState parseRuntimePermissions(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        String versionValue = parser.getAttributeValue(null, ATTRIBUTE_VERSION);
-        int version = versionValue != null ? Integer.parseInt(versionValue)
-                : RuntimePermissionsState.NO_VERSION;
-        String fingerprint = parser.getAttributeValue(null, ATTRIBUTE_FINGERPRINT);
-
-        Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
-                new ArrayMap<>();
-        Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
-                new ArrayMap<>();
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            switch (parser.getName()) {
-                case TAG_PACKAGE: {
-                    String packageName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                    List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
-                            parser);
-                    packagePermissions.put(packageName, permissions);
-                    break;
-                }
-                case TAG_SHARED_USER: {
-                    String sharedUserName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                    List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
-                            parser);
-                    sharedUserPermissions.put(sharedUserName, permissions);
-                    break;
-                }
-            }
-        }
-
-        return new RuntimePermissionsState(version, fingerprint, packagePermissions,
-                sharedUserPermissions);
-    }
-
-    @NonNull
-    private static List<RuntimePermissionsState.PermissionState> parsePermissions(
-            @NonNull XmlPullParser parser) throws IOException, XmlPullParserException {
-        List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_PERMISSION)) {
-                String name = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                boolean granted = Boolean.parseBoolean(parser.getAttributeValue(null,
-                        ATTRIBUTE_GRANTED));
-                int flags = Integer.parseInt(parser.getAttributeValue(null,
-                        ATTRIBUTE_FLAGS), 16);
-                RuntimePermissionsState.PermissionState permission =
-                        new RuntimePermissionsState.PermissionState(name, granted, flags);
-                permissions.add(permission);
-            }
-        }
-        return permissions;
-    }
-
-    @Override
-    public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
-            @NonNull UserHandle user) {
-        File file = getFile(user);
-        AtomicFile atomicFile = new AtomicFile(file);
-        FileOutputStream outputStream = null;
-        try {
-            outputStream = atomicFile.startWrite();
-
-            XmlSerializer serializer = Xml.newSerializer();
-            serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-            serializer.startDocument(null, true);
-
-            serializeRuntimePermissions(serializer, runtimePermissions);
-
-            serializer.endDocument();
-            atomicFile.finishWrite(outputStream);
-        } catch (Exception e) {
-            Log.wtf(LOG_TAG, "Failed to write runtime-permissions.xml, restoring backup: " + file,
-                    e);
-            atomicFile.failWrite(outputStream);
-        } finally {
-            IoUtils.closeQuietly(outputStream);
-        }
-    }
-
-    private static void serializeRuntimePermissions(@NonNull XmlSerializer serializer,
-            @NonNull RuntimePermissionsState runtimePermissions) throws IOException {
-        serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
-
-        int version = runtimePermissions.getVersion();
-        serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
-        String fingerprint = runtimePermissions.getFingerprint();
-        if (fingerprint != null) {
-            serializer.attribute(null, ATTRIBUTE_FINGERPRINT, fingerprint);
-        }
-
-        for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
-                : runtimePermissions.getPackagePermissions().entrySet()) {
-            String packageName = entry.getKey();
-            List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
-            serializer.startTag(null, TAG_PACKAGE);
-            serializer.attribute(null, ATTRIBUTE_NAME, packageName);
-            serializePermissions(serializer, permissions);
-            serializer.endTag(null, TAG_PACKAGE);
-        }
-
-        for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
-                : runtimePermissions.getSharedUserPermissions().entrySet()) {
-            String sharedUserName = entry.getKey();
-            List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
-            serializer.startTag(null, TAG_SHARED_USER);
-            serializer.attribute(null, ATTRIBUTE_NAME, sharedUserName);
-            serializePermissions(serializer, permissions);
-            serializer.endTag(null, TAG_SHARED_USER);
-        }
-
-        serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
-    }
-
-    private static void serializePermissions(@NonNull XmlSerializer serializer,
-            @NonNull List<RuntimePermissionsState.PermissionState> permissions) throws IOException {
-        int permissionsSize = permissions.size();
-        for (int i = 0; i < permissionsSize; i++) {
-            RuntimePermissionsState.PermissionState permissionState = permissions.get(i);
-
-            serializer.startTag(null, TAG_PERMISSION);
-            serializer.attribute(null, ATTRIBUTE_NAME, permissionState.getName());
-            serializer.attribute(null, ATTRIBUTE_GRANTED, Boolean.toString(
-                    permissionState.isGranted() && (permissionState.getFlags()
-                            & PackageManager.FLAG_PERMISSION_ONE_TIME) == 0));
-            serializer.attribute(null, ATTRIBUTE_FLAGS, Integer.toHexString(
-                    permissionState.getFlags()));
-            serializer.endTag(null, TAG_PERMISSION);
-        }
-    }
-
-    @Override
-    public void deleteForUser(@NonNull UserHandle user) {
-        getFile(user).delete();
-    }
-
-    @NonNull
-    private static File getFile(@NonNull UserHandle user) {
-        ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
-        File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
-        return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
-    }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
deleted file mode 100644
index c6bfc6d..0000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ /dev/null
@@ -1,222 +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 com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * State of all runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RuntimePermissionsState {
-
-    /**
-     * Special value for {@link #mVersion} to indicate that no version was read.
-     */
-    public static final int NO_VERSION = -1;
-
-    /**
-     * The version of the runtime permissions.
-     */
-    private final int mVersion;
-
-    /**
-     * The fingerprint of the runtime permissions.
-     */
-    @Nullable
-    private final String mFingerprint;
-
-    /**
-     * The runtime permissions by packages.
-     */
-    @NonNull
-    private final Map<String, List<PermissionState>> mPackagePermissions;
-
-    /**
-     * The runtime permissions by shared users.
-     */
-    @NonNull
-    private final Map<String, List<PermissionState>> mSharedUserPermissions;
-
-    /**
-     * Create a new instance of this class.
-     *
-     * @param version the version of the runtime permissions
-     * @param fingerprint the fingerprint of the runtime permissions
-     * @param packagePermissions the runtime permissions by packages
-     * @param sharedUserPermissions the runtime permissions by shared users
-     */
-    public RuntimePermissionsState(int version, @Nullable String fingerprint,
-            @NonNull Map<String, List<PermissionState>> packagePermissions,
-            @NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
-        mVersion = version;
-        mFingerprint = fingerprint;
-        mPackagePermissions = packagePermissions;
-        mSharedUserPermissions = sharedUserPermissions;
-    }
-
-    /**
-     * Get the version of the runtime permissions.
-     *
-     * @return the version of the runtime permissions
-     */
-    public int getVersion() {
-        return mVersion;
-    }
-
-    /**
-     * Get the fingerprint of the runtime permissions.
-     *
-     * @return the fingerprint of the runtime permissions
-     */
-    @Nullable
-    public String getFingerprint() {
-        return mFingerprint;
-    }
-
-    /**
-     * Get the runtime permissions by packages.
-     *
-     * @return the runtime permissions by packages
-     */
-    @NonNull
-    public Map<String, List<PermissionState>> getPackagePermissions() {
-        return mPackagePermissions;
-    }
-
-    /**
-     * Get the runtime permissions by shared users.
-     *
-     * @return the runtime permissions by shared users
-     */
-    @NonNull
-    public Map<String, List<PermissionState>> getSharedUserPermissions() {
-        return mSharedUserPermissions;
-    }
-
-    @Override
-    public boolean equals(Object object) {
-        if (this == object) {
-            return true;
-        }
-        if (object == null || getClass() != object.getClass()) {
-            return false;
-        }
-        RuntimePermissionsState that = (RuntimePermissionsState) object;
-        return mVersion == that.mVersion
-                && Objects.equals(mFingerprint, that.mFingerprint)
-                && Objects.equals(mPackagePermissions, that.mPackagePermissions)
-                && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
-    }
-
-    /**
-     * State of a single permission.
-     */
-    public static final class PermissionState {
-
-        /**
-         * The name of the permission.
-         */
-        @NonNull
-        private final String mName;
-
-        /**
-         * Whether the permission is granted.
-         */
-        private final boolean mGranted;
-
-        /**
-         * The flags of the permission.
-         */
-        private final int mFlags;
-
-        /**
-         * Create a new instance of this class.
-         *
-         * @param name the name of the permission
-         * @param granted whether the permission is granted
-         * @param flags the flags of the permission
-         */
-        public PermissionState(@NonNull String name, boolean granted, int flags) {
-            mName = name;
-            mGranted = granted;
-            mFlags = flags;
-        }
-
-        /**
-         * Get the name of the permission.
-         *
-         * @return the name of the permission
-         */
-        @NonNull
-        public String getName() {
-            return mName;
-        }
-
-        /**
-         * Get whether the permission is granted.
-         *
-         * @return whether the permission is granted
-         */
-        public boolean isGranted() {
-            return mGranted;
-        }
-
-        /**
-         * Get the flags of the permission.
-         *
-         * @return the flags of the permission
-         */
-        public int getFlags() {
-            return mFlags;
-        }
-
-        @Override
-        public boolean equals(Object object) {
-            if (this == object) {
-                return true;
-            }
-            if (object == null || getClass() != object.getClass()) {
-                return false;
-            }
-            PermissionState that = (PermissionState) object;
-            return mGranted == that.mGranted
-                    && mFlags == that.mFlags
-                    && Objects.equals(mName, that.mName);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mName, mGranted, mFlags);
-        }
-    }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
deleted file mode 100644
index 2e5a28a..0000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ /dev/null
@@ -1,73 +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 com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RolesPersistence {
-
-    /**
-     * Read the roles from persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param user the user to read for
-     * @return the roles read
-     */
-    @Nullable
-    RolesState readForUser(@NonNull UserHandle user);
-
-    /**
-     * Write the roles to persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param roles the roles to write
-     * @param user the user to write for
-     */
-    void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
-
-    /**
-     * Delete the roles from persistence.
-     *
-     * This will perform I/O operations synchronously.
-     *
-     * @param user the user to delete for
-     */
-    void deleteForUser(@NonNull UserHandle user);
-
-    /**
-     * Create a new instance of {@link RolesPersistence} implementation.
-     *
-     * @return the new instance.
-     */
-    @NonNull
-    static RolesPersistence createInstance() {
-        return new RolesPersistenceImpl();
-    }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
deleted file mode 100644
index f66257f..0000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ /dev/null
@@ -1,218 +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 com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.permission.persistence.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Persistence implementation for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RolesPersistenceImpl implements RolesPersistence {
-
-    private static final String LOG_TAG = RolesPersistenceImpl.class.getSimpleName();
-
-    private static final String APEX_MODULE_NAME = "com.android.permission";
-
-    private static final String ROLES_FILE_NAME = "roles.xml";
-
-    private static final String TAG_ROLES = "roles";
-    private static final String TAG_ROLE = "role";
-    private static final String TAG_HOLDER = "holder";
-
-    private static final String ATTRIBUTE_VERSION = "version";
-    private static final String ATTRIBUTE_NAME = "name";
-    private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
-
-    @Nullable
-    @Override
-    public RolesState readForUser(@NonNull UserHandle user) {
-        File file = getFile(user);
-        try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(inputStream, null);
-            return parseXml(parser);
-        } catch (FileNotFoundException e) {
-            Log.i(LOG_TAG, "roles.xml not found");
-            return null;
-        } catch (XmlPullParserException | IOException e) {
-            throw new IllegalStateException("Failed to read roles.xml: " + file , e);
-        }
-    }
-
-    @NonNull
-    private static RolesState parseXml(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_ROLES)) {
-                return parseRoles(parser);
-            }
-        }
-        throw new IllegalStateException("Missing <" + TAG_ROLES + "> in roles.xml");
-    }
-
-    @NonNull
-    private static RolesState parseRoles(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        int version = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
-        String packagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
-
-        Map<String, Set<String>> roles = new ArrayMap<>();
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_ROLE)) {
-                String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                Set<String> roleHolders = parseRoleHolders(parser);
-                roles.put(roleName, roleHolders);
-            }
-        }
-
-        return new RolesState(version, packagesHash, roles);
-    }
-
-    @NonNull
-    private static Set<String> parseRoleHolders(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        Set<String> roleHolders = new ArraySet<>();
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_HOLDER)) {
-                String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                roleHolders.add(roleHolder);
-            }
-        }
-        return roleHolders;
-    }
-
-    @Override
-    public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
-        File file = getFile(user);
-        AtomicFile atomicFile = new AtomicFile(file);
-        FileOutputStream outputStream = null;
-        try {
-            outputStream = atomicFile.startWrite();
-
-            XmlSerializer serializer = Xml.newSerializer();
-            serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-            serializer.startDocument(null, true);
-
-            serializeRoles(serializer, roles);
-
-            serializer.endDocument();
-            atomicFile.finishWrite(outputStream);
-        } catch (Exception e) {
-            Log.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup: " + file,
-                    e);
-            atomicFile.failWrite(outputStream);
-        } finally {
-            IoUtils.closeQuietly(outputStream);
-        }
-    }
-
-    private static void serializeRoles(@NonNull XmlSerializer serializer,
-            @NonNull RolesState roles) throws IOException {
-        serializer.startTag(null, TAG_ROLES);
-
-        int version = roles.getVersion();
-        serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
-        String packagesHash = roles.getPackagesHash();
-        if (packagesHash != null) {
-            serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
-        }
-
-        for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) {
-            String roleName = entry.getKey();
-            Set<String> roleHolders = entry.getValue();
-
-            serializer.startTag(null, TAG_ROLE);
-            serializer.attribute(null, ATTRIBUTE_NAME, roleName);
-            serializeRoleHolders(serializer, roleHolders);
-            serializer.endTag(null, TAG_ROLE);
-        }
-
-        serializer.endTag(null, TAG_ROLES);
-    }
-
-    private static void serializeRoleHolders(@NonNull XmlSerializer serializer,
-            @NonNull Set<String> roleHolders) throws IOException {
-        for (String roleHolder : roleHolders) {
-            serializer.startTag(null, TAG_HOLDER);
-            serializer.attribute(null, ATTRIBUTE_NAME, roleHolder);
-            serializer.endTag(null, TAG_HOLDER);
-        }
-    }
-
-    @Override
-    public void deleteForUser(@NonNull UserHandle user) {
-        getFile(user).delete();
-    }
-
-    @NonNull
-    private static File getFile(@NonNull UserHandle user) {
-        ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
-        File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
-        return new File(dataDirectory, ROLES_FILE_NAME);
-    }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
deleted file mode 100644
index f61efa0..0000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ /dev/null
@@ -1,115 +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 com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * State of all roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RolesState {
-
-    /**
-     * The version of the roles.
-     */
-    private final int mVersion;
-
-    /**
-     * The hash of all packages in the system.
-     */
-    @Nullable
-    private final String mPackagesHash;
-
-    /**
-     * The roles.
-     */
-    @NonNull
-    private final Map<String, Set<String>> mRoles;
-
-    /**
-     * Create a new instance of this class.
-     *
-     * @param version the version of the roles
-     * @param packagesHash the hash of all packages in the system
-     * @param roles the roles
-     */
-    public RolesState(int version, @Nullable String packagesHash,
-            @NonNull Map<String, Set<String>> roles) {
-        mVersion = version;
-        mPackagesHash = packagesHash;
-        mRoles = roles;
-    }
-
-    /**
-     * Get the version of the roles.
-     *
-     * @return the version of the roles
-     */
-    public int getVersion() {
-        return mVersion;
-    }
-
-    /**
-     * Get the hash of all packages in the system.
-     *
-     * @return the hash of all packages in the system
-     */
-    @Nullable
-    public String getPackagesHash() {
-        return mPackagesHash;
-    }
-
-    /**
-     * Get the roles.
-     *
-     * @return the roles
-     */
-    @NonNull
-    public Map<String, Set<String>> getRoles() {
-        return mRoles;
-    }
-
-    @Override
-    public boolean equals(Object object) {
-        if (this == object) {
-            return true;
-        }
-        if (object == null || getClass() != object.getClass()) {
-            return false;
-        }
-        RolesState that = (RolesState) object;
-        return mVersion == that.mVersion
-                && Objects.equals(mPackagesHash, that.mPackagesHash)
-                && Objects.equals(mRoles, that.mRoles);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mVersion, mPackagesHash, mRoles);
-    }
-}
diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp
deleted file mode 100644
index 63bf0a0..0000000
--- a/apex/permission/testing/Android.bp
+++ /dev/null
@@ -1,25 +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.
-
-apex_test {
-    name: "test_com.android.permission",
-    visibility: [
-        "//system/apex/tests",
-    ],
-    defaults: ["com.android.permission-defaults"],
-    manifest: "test_manifest.json",
-    file_contexts: ":com.android.permission-file_contexts",
-    // Test APEX, should never be installed
-    installable: false,
-}
diff --git a/apex/permission/testing/test_manifest.json b/apex/permission/testing/test_manifest.json
deleted file mode 100644
index bc19a9e..0000000
--- a/apex/permission/testing/test_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.permission",
-  "version": 2147483647
-}
diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp
deleted file mode 100644
index 271e328..0000000
--- a/apex/permission/tests/Android.bp
+++ /dev/null
@@ -1,37 +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.
-
-android_test {
-    name: "PermissionApexTests",
-    sdk_version: "test_current",
-    srcs: [
-        "java/**/*.kt",
-    ],
-    static_libs: [
-        "service-permission.impl",
-        "androidx.test.rules",
-        "androidx.test.ext.junit",
-        "androidx.test.ext.truth",
-        "mockito-target-extended-minus-junit4",
-    ],
-    jni_libs: [
-        "libdexmakerjvmtiagent",
-        "libstaticjvmtiagent",
-    ],
-    compile_multilib: "both",
-    test_suites: [
-        "general-tests",
-        "mts",
-    ],
-}
diff --git a/apex/permission/tests/AndroidManifest.xml b/apex/permission/tests/AndroidManifest.xml
deleted file mode 100644
index 57ee641..0000000
--- a/apex/permission/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-  ~ Copyright (C) 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<manifest
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.permission.test">
-
-    <!-- The application has to be debuggable for static mocking to work. -->
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation
-        android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.permission.test"
-        android:label="Permission APEX Tests" />
-</manifest>
diff --git a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt b/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
deleted file mode 100644
index 2987da0..0000000
--- a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
+++ /dev/null
@@ -1,110 +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 com.android.permission.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RuntimePermissionsPersistenceTest {
-    private val context = InstrumentationRegistry.getInstrumentation().context
-
-    private lateinit var mockDataDirectory: File
-
-    private lateinit var mockitoSession: MockitoSession
-    @Mock
-    lateinit var apexEnvironment: ApexEnvironment
-
-    private val persistence = RuntimePermissionsPersistence.createInstance()
-    private val permissionState = RuntimePermissionsState.PermissionState("permission", true, 3)
-    private val state = RuntimePermissionsState(
-        1, "fingerprint", mapOf("package" to listOf(permissionState)),
-        mapOf("sharedUser" to listOf(permissionState))
-    )
-    private val user = Process.myUserHandle()
-
-    @Before
-    fun createMockDataDirectory() {
-        mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
-        mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
-    }
-
-    @Before
-    fun mockApexEnvironment() {
-        initMocks(this)
-        mockitoSession = mockitoSession()
-            .mockStatic(ApexEnvironment::class.java)
-            .strictness(Strictness.LENIENT)
-            .startMocking()
-        `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
-        `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
-            File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
-        }
-    }
-
-    @After
-    fun finishMockingApexEnvironment() {
-        mockitoSession.finishMocking()
-    }
-
-    @Test
-    fun testReadWrite() {
-        persistence.writeForUser(state, user)
-        val persistedState = persistence.readForUser(user)
-
-        assertThat(persistedState).isEqualTo(state)
-        assertThat(persistedState!!.version).isEqualTo(state.version)
-        assertThat(persistedState.fingerprint).isEqualTo(state.fingerprint)
-        assertThat(persistedState.packagePermissions).isEqualTo(state.packagePermissions)
-        val persistedPermissionState = persistedState.packagePermissions.values.first().first()
-        assertThat(persistedPermissionState.name).isEqualTo(permissionState.name)
-        assertThat(persistedPermissionState.isGranted).isEqualTo(permissionState.isGranted)
-        assertThat(persistedPermissionState.flags).isEqualTo(permissionState.flags)
-        assertThat(persistedState.sharedUserPermissions).isEqualTo(state.sharedUserPermissions)
-    }
-
-    @Test
-    fun testDelete() {
-        persistence.writeForUser(state, user)
-        persistence.deleteForUser(user)
-        val persistedState = persistence.readForUser(user)
-
-        assertThat(persistedState).isNull()
-    }
-
-    companion object {
-        private const val APEX_MODULE_NAME = "com.android.permission"
-    }
-}
diff --git a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt b/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
deleted file mode 100644
index f9d9d5a..0000000
--- a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ /dev/null
@@ -1,101 +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 com.android.role.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RolesPersistenceTest {
-    private val context = InstrumentationRegistry.getInstrumentation().context
-
-    private lateinit var mockDataDirectory: File
-
-    private lateinit var mockitoSession: MockitoSession
-    @Mock
-    lateinit var apexEnvironment: ApexEnvironment
-
-    private val persistence = RolesPersistence.createInstance()
-    private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2")))
-    private val user = Process.myUserHandle()
-
-    @Before
-    fun createMockDataDirectory() {
-        mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
-        mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
-    }
-
-    @Before
-    fun mockApexEnvironment() {
-        initMocks(this)
-        mockitoSession = mockitoSession()
-            .mockStatic(ApexEnvironment::class.java)
-            .strictness(Strictness.LENIENT)
-            .startMocking()
-        `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
-        `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
-            File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
-        }
-    }
-
-    @After
-    fun finishMockingApexEnvironment() {
-        mockitoSession.finishMocking()
-    }
-
-    @Test
-    fun testReadWrite() {
-        persistence.writeForUser(state, user)
-        val persistedState = persistence.readForUser(user)
-
-        assertThat(persistedState).isEqualTo(state)
-        assertThat(persistedState!!.version).isEqualTo(state.version)
-        assertThat(persistedState.packagesHash).isEqualTo(state.packagesHash)
-        assertThat(persistedState.roles).isEqualTo(state.roles)
-    }
-
-    @Test
-    fun testDelete() {
-        persistence.writeForUser(state, user)
-        persistence.deleteForUser(user)
-        val persistedState = persistence.readForUser(user)
-
-        assertThat(persistedState).isNull()
-    }
-
-    companion object {
-        private const val APEX_MODULE_NAME = "com.android.permission"
-    }
-}
diff --git a/boot/Android.bp b/boot/Android.bp
new file mode 100644
index 0000000..dd4066a
--- /dev/null
+++ b/boot/Android.bp
@@ -0,0 +1,18 @@
+// 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.
+
+boot_image {
+    name: "framework-boot-image",
+    image_name: "boot",
+}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 2c7ee21..854982f 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -92,6 +92,8 @@
 static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
 static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
 static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
+static const char PROGRESS_FONT_ASSET[] = "images/progress_font.png";
+static const char PROGRESS_FONT_ZIP_NAME[] = "progress_font.png";
 static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
 static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
 static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
@@ -107,6 +109,7 @@
 static const int TEXT_CENTER_VALUE = INT_MAX;
 static const int TEXT_MISSING_VALUE = INT_MIN;
 static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
+static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress";
 static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
 static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
 static constexpr size_t TEXT_POS_LEN_MAX = 16;
@@ -891,6 +894,18 @@
     drawText(out, font, false, &x, &y);
 }
 
+void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos) {
+    static constexpr int PERCENT_LENGTH = 5;
+
+    char percentBuff[PERCENT_LENGTH];
+    // ';' has the ascii code just after ':', and the font resource contains '%'
+    // for that ascii code.
+    sprintf(percentBuff, "%d;", percent);
+    int x = xPos;
+    int y = yPos;
+    drawText(percentBuff, font, false, &x, &y);
+}
+
 bool BootAnimation::parseAnimationDesc(Animation& animation)  {
     String8 desString;
 
@@ -910,6 +925,7 @@
         int height = 0;
         int count = 0;
         int pause = 0;
+        int progress = 0;
         int framesToFadeCount = 0;
         char path[ANIM_ENTRY_NAME_MAX];
         char color[7] = "000000"; // default to black if unspecified
@@ -919,11 +935,17 @@
 
         int nextReadPos;
 
-        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
-            // SLOGD("> w=%d, h=%d, fps=%d", width, height, fps);
+        int topLineNumbers = sscanf(l, "%d %d %d %d", &width, &height, &fps, &progress);
+        if (topLineNumbers == 3 || topLineNumbers == 4) {
+            // SLOGD("> w=%d, h=%d, fps=%d, progress=%d", width, height, fps, progress);
             animation.width = width;
             animation.height = height;
             animation.fps = fps;
+            if (topLineNumbers == 4) {
+              animation.progressEnabled = (progress != 0);
+            } else {
+              animation.progressEnabled = false;
+            }
         } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
                           &pathType, &count, &pause, path, &nextReadPos) >= 4) {
             if (pathType == 'f') {
@@ -1000,6 +1022,14 @@
                 continue;
             }
 
+            if (entryName == PROGRESS_FONT_ZIP_NAME) {
+                FileMap* map = zip->createEntryFileMap(entry);
+                if (map) {
+                    animation.progressFont.map = map;
+                }
+                continue;
+            }
+
             for (size_t j = 0; j < pcount; j++) {
                 if (path == animation.parts[j].path) {
                     uint16_t method;
@@ -1131,6 +1161,8 @@
         mClockEnabled = clockFontInitialized;
     }
 
+    initFont(&mAnimation->progressFont, PROGRESS_FONT_ASSET);
+
     if (mClockEnabled && !updateIsTimeAccurate()) {
         mTimeCheckThread = new TimeCheckThread(this);
         mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
@@ -1166,6 +1198,7 @@
             elapsedRealtime());
 
     int fadedFramesCount = 0;
+    int lastDisplayedProgress = 0;
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
         const size_t fcount = part.frames.size();
@@ -1191,6 +1224,12 @@
                     part.backgroundColor[2],
                     1.0f);
 
+            // For the last animation, if we have progress indicator from
+            // the system, display it.
+            int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
+            bool displayProgress = animation.progressEnabled &&
+                (i == (pcount -1)) && currentProgress != 0;
+
             for (size_t j=0 ; j<fcount ; j++) {
                 if (shouldStopPlayingPart(part, fadedFramesCount)) break;
 
@@ -1248,6 +1287,23 @@
                     drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
                 }
 
+                if (displayProgress) {
+                    int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
+                    // In case the new progress jumped suddenly, still show an
+                    // increment of 1.
+                    if (lastDisplayedProgress != 100) {
+                      // Artificially sleep 1/10th a second to slow down the animation.
+                      usleep(100000);
+                      if (lastDisplayedProgress < newProgress) {
+                        lastDisplayedProgress++;
+                      }
+                    }
+                    // Put the progress percentage right below the animation.
+                    int posY = animation.height / 3;
+                    int posX = TEXT_CENTER_VALUE;
+                    drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY);
+                }
+
                 handleViewport(frameDuration);
 
                 eglSwapBuffers(mDisplay, mSurface);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index aee3853..b52222c 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -100,11 +100,13 @@
         int fps;
         int width;
         int height;
+        bool progressEnabled;
         Vector<Part> parts;
         String8 audioConf;
         String8 fileName;
         ZipFileRO* zip;
         Font clockFont;
+        Font progressFont;
     };
 
     // All callbacks will be called from this class's internal thread.
@@ -168,6 +170,7 @@
     bool movie();
     void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
     void drawClock(const Font& font, const int xPos, const int yPos);
+    void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
     void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
                    const Animation::Part& part, int fadedFramesCount);
     bool validClock(const Animation::Part& part);
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index f9b83c9..1678053 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -22,11 +22,14 @@
 
 The first line defines the general parameters of the animation:
 
-    WIDTH HEIGHT FPS
+    WIDTH HEIGHT FPS [PROGRESS]
 
   * **WIDTH:** animation width (pixels)
   * **HEIGHT:** animation height (pixels)
   * **FPS:** frames per second, e.g. 60
+  * **PROGRESS:** whether to show a progress percentage on the last part
+      + The percentage will be displayed with an x-coordinate of 'c', and a
+        y-coordinate set to 1/3 of the animation height.
 
 It is followed by a number of rows of the form:
 
@@ -77,6 +80,11 @@
   * Each row is divided in half: regular weight glyphs on the top half, bold glyphs on the bottom
   * For a NxM image each character glyph will be N/16 pixels wide and M/(12*2) pixels high
 
+## progress_font.png
+
+The file used to draw the boot progress in percentage on top of the boot animation. The font format
+follows the same specification as the one described for clock_font.png.
+
 ## loading and playing frames
 
 Each part is scanned and loaded directly from the zip archive. Within a part directory, every file
diff --git a/core/api/current.txt b/core/api/current.txt
index acd3389..8e70bc5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1142,6 +1142,7 @@
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
+    field public static final int requireDeviceScreenOn = 16844312; // 0x1010618
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
@@ -9139,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;
@@ -12133,6 +12134,8 @@
     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_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";
@@ -25086,8 +25089,6 @@
     method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @NonNull @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
@@ -25097,12 +25098,6 @@
     field public static final int DIRECTION_OUT = 1; // 0x1
   }
 
-  public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-    method public void close();
-    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-  }
-
   public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
   }
 
@@ -29649,6 +29644,8 @@
     field @Deprecated public static final String RADIO;
     field @Deprecated public static final String SERIAL;
     field @NonNull public static final String SKU;
+    field @NonNull public static final String SOC_MANUFACTURER;
+    field @NonNull public static final String SOC_MODEL;
     field public static final String[] SUPPORTED_32_BIT_ABIS;
     field public static final String[] SUPPORTED_64_BIT_ABIS;
     field public static final String[] SUPPORTED_ABIS;
@@ -36183,9 +36180,10 @@
 package android.security.keystore {
 
   public class BackendBusyException extends java.security.ProviderException {
-    ctor public BackendBusyException();
-    ctor public BackendBusyException(@NonNull String);
-    ctor public BackendBusyException(@NonNull String, @NonNull Throwable);
+    ctor public BackendBusyException(long);
+    ctor public BackendBusyException(long, @NonNull String);
+    ctor public BackendBusyException(long, @NonNull String, @NonNull Throwable);
+    method public long getBackOffHintMillis();
   }
 
   public class KeyExpiredException extends java.security.InvalidKeyException {
@@ -36209,6 +36207,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();
@@ -36245,6 +36244,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);
@@ -36267,6 +36267,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();
@@ -36323,6 +36324,7 @@
     field public static final int ORIGIN_IMPORTED = 2; // 0x2
     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_DECRYPT = 2; // 0x2
     field public static final int PURPOSE_ENCRYPT = 1; // 0x1
     field public static final int PURPOSE_SIGN = 4; // 0x4
@@ -36335,6 +36337,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 {
@@ -36344,6 +36347,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();
@@ -36369,6 +36373,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);
@@ -38502,7 +38507,9 @@
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onStopRtt();
+    method public void onTrackedByNonUiService(boolean);
     method public void onUnhold();
+    method public void onUsingAlternativeUi(boolean);
     method public static String propertiesToString(int);
     method public final void putExtras(@NonNull android.os.Bundle);
     method public final void removeExtras(java.util.List<java.lang.String>);
@@ -38840,6 +38847,7 @@
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
     field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
     field @NonNull public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+    field public static final String EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE = "android.telecom.extra.ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE";
     field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
     field public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
@@ -41713,6 +41721,14 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.DownloadableSubscription> CREATOR;
   }
 
+  public static final class DownloadableSubscription.Builder {
+    ctor public DownloadableSubscription.Builder(@NonNull android.telephony.euicc.DownloadableSubscription);
+    ctor public DownloadableSubscription.Builder(@NonNull String);
+    method @NonNull public android.telephony.euicc.DownloadableSubscription build();
+    method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(@NonNull String);
+    method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(@NonNull String);
+  }
+
   public final class EuiccInfo implements android.os.Parcelable {
     ctor public EuiccInfo(@Nullable String);
     method public int describeContents();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 061d4cc..ab9799f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -10,7 +10,12 @@
 
 package android.net {
 
+  public final class ConnectivityFrameworkInitializer {
+    method public static void registerServiceWrappers();
+  }
+
   public class ConnectivityManager {
+    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);
   }
 
@@ -18,6 +23,14 @@
     method public int getResourceId();
   }
 
+  public final class NetworkAgentConfig implements android.os.Parcelable {
+    method @Nullable public String getSubscriberId();
+  }
+
+  public static final class NetworkAgentConfig.Builder {
+    method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+  }
+
   public final class NetworkCapabilities implements android.os.Parcelable {
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
@@ -48,6 +61,16 @@
     method public void teardownTestNetwork(@NonNull android.net.Network);
   }
 
+  public final class UnderlyingNetworkInfo implements android.os.Parcelable {
+    ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR;
+    field @NonNull public final String iface;
+    field public final int ownerUid;
+    field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
+  }
+
 }
 
 package android.os {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b4d6016..72fcc72 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1415,8 +1415,10 @@
 package android.apphibernation {
 
   public final class AppHibernationManager {
-    method public boolean isHibernating(@NonNull String);
-    method public void setHibernating(@NonNull String, boolean);
+    method public boolean isHibernatingForUser(@NonNull String);
+    method public boolean isHibernatingGlobally(@NonNull String);
+    method public void setHibernatingForUser(@NonNull String, boolean);
+    method public void setHibernatingGlobally(@NonNull String, boolean);
   }
 
 }
@@ -6131,11 +6133,15 @@
   }
 
   public final class IpSecManager {
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    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;
   }
 
   public static class IpSecTransform.Builder {
@@ -6280,6 +6286,7 @@
     method @Nullable public String getSsid();
     method @NonNull public int[] getTransportTypes();
     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
     field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
     field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
@@ -9256,6 +9263,33 @@
     field @Deprecated public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
+  public final class BluetoothCallQualityReport implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public int getNegativeAcknowledgementCount();
+    method @IntRange(from=0) public int getPacketsNotReceivedCount();
+    method @IntRange(from=0) public int getRetransmittedPacketsCount();
+    method @IntRange(from=0xffffff81, to=20) public int getRssiDbm();
+    method public long getSentTimestampMillis();
+    method public int getSnrDb();
+    method public boolean isChoppyVoice();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telecom.BluetoothCallQualityReport> CREATOR;
+    field public static final String EVENT_BLUETOOTH_CALL_QUALITY_REPORT = "android.telecom.event.BLUETOOTH_CALL_QUALITY_REPORT";
+    field public static final String EXTRA_BLUETOOTH_CALL_QUALITY_REPORT = "android.telecom.extra.BLUETOOTH_CALL_QUALITY_REPORT";
+  }
+
+  public static final class BluetoothCallQualityReport.Builder {
+    ctor public BluetoothCallQualityReport.Builder();
+    method @NonNull public android.telecom.BluetoothCallQualityReport build();
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setChoppyVoice(boolean);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setNegativeAcknowledgementCount(int);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setPacketsNotReceivedCount(int);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setRetransmittedPacketsCount(int);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setRssiDbm(int);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setSentTimestampMillis(long);
+    method @NonNull public android.telecom.BluetoothCallQualityReport.Builder setSnrDb(int);
+  }
+
   public final class Call {
     method @Deprecated public void addListener(android.telecom.Call.Listener);
     method public void enterBackgroundAudioProcessing();
@@ -10420,6 +10454,7 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
+    method public boolean isRadioInterfaceCapabilitySupported(@NonNull String);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired();
@@ -10493,6 +10528,7 @@
     field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
     field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
     field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
+    field public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE";
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -10907,12 +10943,8 @@
 
   public static final class DownloadableSubscription.Builder {
     ctor public DownloadableSubscription.Builder();
-    ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription);
-    method public android.telephony.euicc.DownloadableSubscription build();
-    method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(String);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(String);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(String);
+    method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(@NonNull java.util.List<android.telephony.UiccAccessRule>);
+    method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(@NonNull String);
   }
 
   public class EuiccCardManager {
@@ -11782,11 +11814,100 @@
     field public static final String RCS_PROFILE_2_3 = "UP_2.3";
   }
 
+  public final class RcsContactPresenceTuple implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.net.Uri getContactUri();
+    method @Nullable public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities getServiceCapabilities();
+    method @Nullable public String getServiceDescription();
+    method @NonNull public String getServiceId();
+    method @NonNull public String getServiceVersion();
+    method @NonNull public String getStatus();
+    method @Nullable public String getTimestamp();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
+    field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+    field public static final String SERVICE_ID_CHATBOT = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+    field public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+    field public static final String SERVICE_ID_CHATBOT_STANDALONE = " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+    field public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+    field public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+    field public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+    field public static final String SERVICE_ID_FT_OVER_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+    field public static final String SERVICE_ID_GEO_PUSH = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+    field public static final String SERVICE_ID_GEO_PUSH_VIA_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+    field public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
+    field public static final String SERVICE_ID_POST_CALL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+    field public static final String SERVICE_ID_SHARED_MAP = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+    field public static final String SERVICE_ID_SHARED_SKETCH = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+    field public static final String TUPLE_BASIC_STATUS_CLOSED = "closed";
+    field public static final String TUPLE_BASIC_STATUS_OPEN = "open";
+  }
+
+  public static final class RcsContactPresenceTuple.Builder {
+    ctor public RcsContactPresenceTuple.Builder(@NonNull String, @NonNull String, @NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple build();
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
+  }
+
+  public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getSupportedDuplexModes();
+    method @NonNull public java.util.List<java.lang.String> getUnsupportedDuplexModes();
+    method public boolean isAudioCapable();
+    method public boolean isVideoCapable();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities> CREATOR;
+    field public static final String DUPLEX_MODE_FULL = "full";
+    field public static final String DUPLEX_MODE_HALF = "half";
+    field public static final String DUPLEX_MODE_RECEIVE_ONLY = "receive-only";
+    field public static final String DUPLEX_MODE_SEND_ONLY = "send-only";
+  }
+
+  public static final class RcsContactPresenceTuple.ServiceCapabilities.Builder {
+    ctor public RcsContactPresenceTuple.ServiceCapabilities.Builder(boolean, boolean);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addSupportedDuplexMode(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addUnsupportedDuplexMode(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities build();
+  }
+
+  public final class RcsContactUceCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCapabilityMechanism();
+    method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String);
+    method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples();
+    method @NonNull public android.net.Uri getContactUri();
+    method public int getRequestResult();
+    method public int getSourceType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_MECHANISM_OPTIONS = 2; // 0x2
+    field public static final int CAPABILITY_MECHANISM_PRESENCE = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
+    field public static final int REQUEST_RESULT_FOUND = 3; // 0x3
+    field public static final int REQUEST_RESULT_NOT_FOUND = 2; // 0x2
+    field public static final int REQUEST_RESULT_NOT_ONLINE = 1; // 0x1
+    field public static final int REQUEST_RESULT_UNKNOWN = 0; // 0x0
+    field public static final int SOURCE_TYPE_CACHED = 1; // 0x1
+    field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0
+  }
+
+  public static final class RcsContactUceCapability.PresenceBuilder {
+    ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuples(@NonNull java.util.List<android.telephony.ims.RcsContactPresenceTuple>);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+  }
+
   public class RcsUceAdapter {
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnPublishStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
     field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6
@@ -11799,6 +11920,18 @@
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8; // 0x8
     field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0; // 0x0
+    field public static final int ERROR_FORBIDDEN = 6; // 0x6
+    field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+    field public static final int ERROR_INSUFFICIENT_MEMORY = 10; // 0xa
+    field public static final int ERROR_LOST_NETWORK = 11; // 0xb
+    field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+    field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+    field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+    field public static final int ERROR_NOT_FOUND = 7; // 0x7
+    field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+    field public static final int ERROR_REQUEST_TIMEOUT = 9; // 0x9
+    field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+    field public static final int ERROR_SERVER_UNAVAILABLE = 12; // 0xc
     field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
     field public static final int PUBLISH_STATE_OK = 1; // 0x1
     field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
@@ -11807,6 +11940,12 @@
     field public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3; // 0x3
   }
 
+  public static interface RcsUceAdapter.CapabilitiesCallback {
+    method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+    method public void onComplete();
+    method public void onError(int, long);
+  }
+
   public static interface RcsUceAdapter.OnPublishStateChangedListener {
     method public void onPublishStateChange(int);
   }
@@ -11850,6 +11989,7 @@
     field public static final String IPTYPE_IPV6 = "IPV6";
     field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
     field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+    field public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
     field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
     field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
     field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
@@ -11882,6 +12022,7 @@
     field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
     field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
     field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+    field public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
     field public static final String SIP_TRANSPORT_TCP = "TCP";
     field public static final String SIP_TRANSPORT_UDP = "UDP";
   }
@@ -12217,6 +12358,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 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
     field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
@@ -12235,6 +12377,14 @@
     method public void onNetworkResponse(@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 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;
+  }
+
   public interface SipDelegate {
     method public void closeDialog(@NonNull String);
     method public void notifyMessageReceiveError(@NonNull String, int);
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index e7b3e14..69d5c8d 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -50,7 +50,7 @@
  *
  * <p>
  * Application process could die for many reasons, for example {@link #REASON_LOW_MEMORY}
- * when it was killed by the ystem because it was running low on memory. Reason
+ * when it was killed by the system because it was running low on memory. Reason
  * of the death can be retrieved via {@link #getReason}. Besides the reason, there are a few other
  * auxiliary APIs like {@link #getStatus} and {@link #getImportance} to help the caller with
  * additional diagnostic information.
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index afa1560..e6aa7a7 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -47,8 +47,19 @@
 per-file *Zen* = file:/packages/SystemUI/OWNERS
 per-file *StatusBar* = file:/packages/SystemUI/OWNERS
 
+# PackageManager
+per-file ApplicationPackageManager.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolverService.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file LoadedApk.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageDeleteObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageInstallObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file EphemeralResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IEphemeralResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IInstantAppResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+
 # ResourcesManager
-per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
+per-file ResourcesManager.java = rtmitchell@google.com, toddke@google.com
 
 # VoiceInteraction
 per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 82e48bf..d151526 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -111,21 +111,16 @@
 import android.media.tv.TvInputManager;
 import android.media.tv.tunerresourcemanager.ITunerResourceManager;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
-import android.net.ConnectivityDiagnosticsManager;
-import android.net.ConnectivityManager;
+import android.net.ConnectivityFrameworkInitializer;
 import android.net.EthernetManager;
-import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
-import android.net.ITestNetworkManager;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.NetworkWatchlistManager;
-import android.net.TestNetworkManager;
 import android.net.TetheringManager;
-import android.net.VpnManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
@@ -154,7 +149,6 @@
 import android.os.IncidentManager;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.StatsFrameworkInitializer;
@@ -349,15 +343,6 @@
         // (which extends it).
         SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
 
-        registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
-                new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
-            @Override
-            public ConnectivityManager createService(Context context) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
-                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-                return new ConnectivityManager(context, service);
-            }});
-
         registerService(Context.NETD_SERVICE, IBinder.class, new StaticServiceFetcher<IBinder>() {
             @Override
             public IBinder createService() throws ServiceNotFoundException {
@@ -391,50 +376,6 @@
                 return new IpSecManager(ctx, service);
             }});
 
-        registerService(Context.VPN_MANAGEMENT_SERVICE, VpnManager.class,
-                new CachedServiceFetcher<VpnManager>() {
-            @Override
-            public VpnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
-                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-                return new VpnManager(ctx, service);
-            }});
-
-        registerService(Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
-                ConnectivityDiagnosticsManager.class,
-                new CachedServiceFetcher<ConnectivityDiagnosticsManager>() {
-            @Override
-            public ConnectivityDiagnosticsManager createService(ContextImpl ctx)
-                    throws ServiceNotFoundException {
-                // ConnectivityDiagnosticsManager is backed by ConnectivityService
-                IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
-                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-                return new ConnectivityDiagnosticsManager(ctx, service);
-            }});
-
-        registerService(
-                Context.TEST_NETWORK_SERVICE,
-                TestNetworkManager.class,
-                new StaticApplicationContextServiceFetcher<TestNetworkManager>() {
-                    @Override
-                    public TestNetworkManager createService(Context context)
-                            throws ServiceNotFoundException {
-                        IBinder csBinder =
-                                ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
-                        IConnectivityManager csMgr =
-                                IConnectivityManager.Stub.asInterface(csBinder);
-
-                        final IBinder tnBinder;
-                        try {
-                            tnBinder = csMgr.startOrGetTestNetworkService();
-                        } catch (RemoteException e) {
-                            throw new ServiceNotFoundException(Context.TEST_NETWORK_SERVICE);
-                        }
-                        ITestNetworkManager tnMgr = ITestNetworkManager.Stub.asInterface(tnBinder);
-                        return new TestNetworkManager(tnMgr);
-                    }
-                });
-
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
@@ -1355,6 +1296,7 @@
         try {
             // Note: the following functions need to be @SystemApis, once they become mainline
             // modules.
+            ConnectivityFrameworkInitializer.registerServiceWrappers();
             JobSchedulerFrameworkInitializer.registerServiceWrappers();
             BlobStoreManagerFrameworkInitializer.initialize();
             TelephonyFrameworkInitializer.registerServiceWrappers();
diff --git a/core/java/android/app/smartspace/OWNERS b/core/java/android/app/smartspace/OWNERS
new file mode 100644
index 0000000..19ef9d7
--- /dev/null
+++ b/core/java/android/app/smartspace/OWNERS
@@ -0,0 +1,2 @@
+srazdan@google.com
+alexmang@google.com
\ No newline at end of file
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1ddfe0d..1d5dc1d 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -28,7 +28,6 @@
 import android.net.ConnectivityManager;
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsService;
-import android.net.NetworkIdentity;
 import android.net.NetworkStack;
 import android.net.NetworkTemplate;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
@@ -47,6 +46,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.NetworkIdentityUtils;
 
 import java.util.Objects;
 
@@ -628,7 +628,7 @@
             default:
                 throw new IllegalArgumentException("Cannot create template for network type "
                         + networkType + ", subscriberId '"
-                        + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
+                        + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'.");
         }
         return template;
     }
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 8f1934c..7281d50 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -49,31 +49,61 @@
     }
 
     /**
-     * Returns true if the package is hibernating, false otherwise.
+     * Returns true if the package is hibernating for this context's user, false otherwise.
      *
      * @hide
      */
     @SystemApi
-    public boolean isHibernating(@NonNull String packageName) {
+    public boolean isHibernatingForUser(@NonNull String packageName) {
         try {
-            return mIAppHibernationService.isHibernating(packageName, mContext.getUserId());
+            return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Set whether the package is hibernating.
+     * Set whether the package is hibernating for this context's user.
      *
      * @hide
      */
     @SystemApi
-    public void setHibernating(@NonNull String packageName, boolean isHibernating) {
+    public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
         try {
-            mIAppHibernationService.setHibernating(packageName, mContext.getUserId(),
+            mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
                     isHibernating);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Returns true if app is hibernating globally / at the package level.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isHibernatingGlobally(@NonNull String packageName) {
+        try {
+            return mIAppHibernationService.isHibernatingGlobally(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set whether a package should be globally hibernating. This hibernates the package at a
+     * package level. User-level hibernation (e.g.. {@link #isHibernatingForUser} is independent
+     * from global hibernation.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
+        try {
+            mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
index db57ecb..6a068ee 100644
--- a/core/java/android/apphibernation/IAppHibernationService.aidl
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -21,6 +21,8 @@
  * @hide
  */
 interface IAppHibernationService {
-    boolean isHibernating(String packageName, int userId);
-    void setHibernating(String packageName, int userId, boolean isHibernating);
+    boolean isHibernatingForUser(String packageName, int userId);
+    void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
+    boolean isHibernatingGlobally(String packageName);
+    void setHibernatingGlobally(String packageName, boolean isHibernating);
 }
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 36076da..4fb5577 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -80,7 +80,7 @@
 
     /**
      * Intent used to broadcast the change in the Audio Connection state of the
-     * A2DP profile.
+     * HFP profile.
      *
      * <p>This intent will have 3 extras:
      * <ul>
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/integrity/OWNERS b/core/java/android/content/integrity/OWNERS
new file mode 100644
index 0000000..20c758a
--- /dev/null
+++ b/core/java/android/content/integrity/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 722021
+
+toddke@android.com
+toddke@google.com
+patb@google.com
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 31beb6e..742f48c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3224,6 +3224,24 @@
     @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";
+
     /** @hide */
     public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
 
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 0ef55f4..3730790 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -954,7 +954,10 @@
 
     /**
      * Returns whether the given functions are valid inputs to UsbManager.
-     * Currently the empty functions or any of MTP, PTP, RNDIS, MIDI are accepted.
+     * Currently the empty functions or any of MTP, PTP, RNDIS, MIDI, NCM are accepted.
+     *
+     * Only one function may be set at a time, except for RNDIS and NCM, which can be set together
+     * because from a user perspective they are the same function (tethering).
      *
      * @return Whether the mask is settable.
      *
@@ -962,7 +965,9 @@
      */
     public static boolean areSettableFunctions(long functions) {
         return functions == FUNCTION_NONE
-                || ((~SETTABLE_FUNCTIONS & functions) == 0 && Long.bitCount(functions) == 1);
+                || ((~SETTABLE_FUNCTIONS & functions) == 0
+                        && ((Long.bitCount(functions) == 1)
+                                || (functions == (FUNCTION_RNDIS | FUNCTION_NCM))));
     }
 
     /**
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index d5aede7..0baf11e 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -23,7 +23,7 @@
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProvider;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.os.IBinder;
@@ -70,7 +70,7 @@
          in Network[] defaultNetworks,
          in NetworkState[] networkStates,
          in String activeIface,
-         in VpnInfo[] vpnInfos);
+         in UnderlyingNetworkInfo[] underlyingNetworkInfos);
     /** Force update of statistics. */
     @UnsupportedAppUsage
     void forceUpdate();
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 60923f5..70bca30 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -707,7 +707,7 @@
     }
 
     /**
-     * This class represents an IpSecTunnelInterface.
+     * This class represents an IpSecTunnelInterface
      *
      * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
      * local endpoints for IPsec tunnels.
@@ -716,7 +716,9 @@
      * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
      * cannot be used in standalone mode within Android, the higher layers may use the tunnel
      * to create Network objects which are accessible to the Android system.
+     * @hide
      */
+    @SystemApi
     public static final class IpSecTunnelInterface implements AutoCloseable {
         private final String mOpPackageName;
         private final IIpSecService mService;
@@ -727,26 +729,23 @@
         private String mInterfaceName;
         private int mResourceId = INVALID_RESOURCE_ID;
 
-        /**
-         * Get the underlying SPI held by this object.
-         *
-         * @hide
-         */
-        @SystemApi
+        /** Get the underlying SPI held by this object. */
         @NonNull
         public String getInterfaceName() {
             return mInterfaceName;
         }
 
         /**
-         * Add an address to the IpSecTunnelInterface.
+         * Add an address to the IpSecTunnelInterface
          *
          * <p>Add an address which may be used as the local inner address for
          * tunneled traffic.
          *
          * @param address the local address for traffic inside the tunnel
          * @param prefixLen length of the InetAddress prefix
+         * @hide
          */
+        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -761,13 +760,15 @@
         }
 
         /**
-         * Remove an address from the IpSecTunnelInterface.
+         * Remove an address from the IpSecTunnelInterface
          *
-         * <p>Remove an address which was previously added to the IpSecTunnelInterface.
+         * <p>Remove an address which was previously added to the IpSecTunnelInterface
          *
          * @param address to be removed
          * @param prefixLen length of the InetAddress prefix
+         * @hide
          */
+        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -818,7 +819,7 @@
         }
 
         /**
-         * Delete an IpSecTunnelInterface.
+         * Delete an IpSecTunnelInterface
          *
          * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
          * resources. Any packets bound for this interface either inbound or outbound will
@@ -840,12 +841,7 @@
             }
         }
 
-
-        /**
-         * Check that the Interface was closed properly.
-         *
-         * @hide
-         */
+        /** Check that the Interface was closed properly. */
         @Override
         protected void finalize() throws Throwable {
             if (mCloseGuard != null) {
@@ -877,52 +873,17 @@
      * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
      *
      * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
-     * underlying network disconnects, and the {@link
-     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
+     * underlying network goes away, and the onLost() callback is received.
      *
-     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
-     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
-     *     This network should almost certainly be a physical network such as WiFi.
-     * @return a new {@link IpSecTunnelInterface} with the specified properties
-     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
-     *     error
-     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
-     *     reached the limit.
-     */
-    @NonNull
-    @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-    public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork)
-            throws ResourceUnavailableException, IOException {
-
-        // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link
-        // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be
-        // safely removed.
-        final InetAddress address = InetAddress.getLocalHost();
-        return createIpSecTunnelInterface(address, address, underlyingNetwork);
-    }
-
-    /**
-     * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
-     *
-     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
-     * underlying network disconnects, and the {@link
-     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
-     *
-     * @param localAddress The local address of the tunnel
-     * @param remoteAddress The local address of the tunnel
-     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
-     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
-     *     This network should almost certainly be a physical network such as WiFi.
-     * @return a new {@link IpSecTunnelInterface} with the specified properties
-     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
-     *     error
-     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
-     *     reached the limit.
+     * @param localAddress The local addres of the tunnel
+     * @param remoteAddress The local addres of the tunnel
+     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
+     *        This network should almost certainly be a network such as WiFi with an L2 address.
+     * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
+     * @throws IOException indicating that the socket could not be opened or bound
+     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
      * @hide
-     * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)}
      */
-    @Deprecated
     @SystemApi
     @NonNull
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@@ -946,14 +907,16 @@
      * <p>Applications should probably not use this API directly.
      *
      *
-     * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied
+     * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
      *        transform.
-     * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which
+     * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
      *        the transform will be used.
      * @param transform an {@link IpSecTransform} created in tunnel mode
-     * @throws IOException indicating that the transform could not be applied due to a lower-layer
-     *     error
+     * @throws IOException indicating that the transform could not be applied due to a lower
+     *         layer failure.
+     * @hide
      */
+    @SystemApi
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
     @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java
index 70c4a72..011a04c 100644
--- a/core/java/android/net/MatchAllNetworkSpecifier.java
+++ b/core/java/android/net/MatchAllNetworkSpecifier.java
@@ -31,17 +31,6 @@
  */
 @SystemApi
 public final class MatchAllNetworkSpecifier extends NetworkSpecifier implements Parcelable {
-    /**
-     * Utility method which verifies that the ns argument is not a MatchAllNetworkSpecifier and
-     * throws an IllegalArgumentException if it is.
-     * @hide
-     */
-    public static void checkNotMatchAllNetworkSpecifier(NetworkSpecifier ns) {
-        if (ns instanceof MatchAllNetworkSpecifier) {
-            throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
-        }
-    }
-
     /** @hide */
     @Override
     public boolean canBeSatisfiedBy(NetworkSpecifier other) {
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index b644ed5..521ed9b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -21,11 +21,12 @@
 import android.content.Context;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.os.Build;
 import android.service.NetworkIdentityProto;
 import android.telephony.Annotation.NetworkType;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.net.module.util.NetworkIdentityUtils;
+
 import java.util.Objects;
 
 /**
@@ -89,7 +90,8 @@
             builder.append(mSubType);
         }
         if (mSubscriberId != null) {
-            builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+            builder.append(", subscriberId=")
+                    .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
         }
         if (mNetworkId != null) {
             builder.append(", networkId=").append(mNetworkId);
@@ -110,7 +112,8 @@
         // Not dumping mSubType, subtypes are no longer supported.
 
         if (mSubscriberId != null) {
-            proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
+            proto.write(NetworkIdentityProto.SUBSCRIBER_ID,
+                    NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
         }
         proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
         proto.write(NetworkIdentityProto.ROAMING, mRoaming);
@@ -149,32 +152,6 @@
     }
 
     /**
-     * Scrub given IMSI on production builds.
-     */
-    public static String scrubSubscriberId(String subscriberId) {
-        if (Build.IS_ENG) {
-            return subscriberId;
-        } else if (subscriberId != null) {
-            // TODO: parse this as MCC+MNC instead of hard-coding
-            return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "...";
-        } else {
-            return "null";
-        }
-    }
-
-    /**
-     * Scrub given IMSI on production builds.
-     */
-    public static String[] scrubSubscriberId(String[] subscriberId) {
-        if (subscriberId == null) return null;
-        final String[] res = new String[subscriberId.length];
-        for (int i = 0; i < res.length; i++) {
-            res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]);
-        }
-        return res;
-    }
-
-    /**
      * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
      * assuming that any mobile networks are using the current IMSI. The subType if applicable,
      * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 713b688..e1ef8b5 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -30,7 +31,8 @@
 public class NetworkState implements Parcelable {
     private static final boolean VALIDATE_ROAMING_STATE = false;
 
-    public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
+    // TODO: remove and make members @NonNull.
+    public static final NetworkState EMPTY = new NetworkState();
 
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
@@ -40,9 +42,18 @@
     public final String subscriberId;
     public final String networkId;
 
-    public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, Network network, String subscriberId,
-            String networkId) {
+    private NetworkState() {
+        networkInfo = null;
+        linkProperties = null;
+        networkCapabilities = null;
+        network = null;
+        subscriberId = null;
+        networkId = null;
+    }
+
+    public NetworkState(@NonNull NetworkInfo networkInfo, @NonNull LinkProperties linkProperties,
+            @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+            String subscriberId, String networkId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
         this.networkCapabilities = networkCapabilities;
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 72be835..2322048 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.NetworkIdentityUtils;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -296,11 +297,11 @@
         builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
         if (mSubscriberId != null) {
             builder.append(", subscriberId=").append(
-                    NetworkIdentity.scrubSubscriberId(mSubscriberId));
+                    NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
         }
         if (mMatchSubscriberIds != null) {
             builder.append(", matchSubscriberIds=").append(
-                    Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
+                    Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
         }
         if (mNetworkId != null) {
             builder.append(", networkId=").append(mNetworkId);
diff --git a/core/java/android/net/VpnInfo.aidl b/core/java/android/net/UnderlyingNetworkInfo.aidl
similarity index 94%
rename from core/java/android/net/VpnInfo.aidl
rename to core/java/android/net/UnderlyingNetworkInfo.aidl
index 8bcaa81..a56f2f4 100644
--- a/core/java/android/net/VpnInfo.aidl
+++ b/core/java/android/net/UnderlyingNetworkInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.net;
 
-parcelable VpnInfo;
+parcelable UnderlyingNetworkInfo;
diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java
new file mode 100644
index 0000000..7bf9231
--- /dev/null
+++ b/core/java/android/net/UnderlyingNetworkInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A lightweight container used to carry information on the networks that underly a given
+ * virtual network.
+ *
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class UnderlyingNetworkInfo implements Parcelable {
+    /** The owner of this network. */
+    public final int ownerUid;
+    /** The interface name of this network. */
+    @NonNull
+    public final String iface;
+    /** The names of the interfaces underlying this network. */
+    @NonNull
+    public final List<String> underlyingIfaces;
+
+    public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
+            @NonNull List<String> underlyingIfaces) {
+        Objects.requireNonNull(iface);
+        Objects.requireNonNull(underlyingIfaces);
+        this.ownerUid = ownerUid;
+        this.iface = iface;
+        this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
+    }
+
+    private UnderlyingNetworkInfo(@NonNull Parcel in) {
+        this.ownerUid = in.readInt();
+        this.iface = in.readString();
+        this.underlyingIfaces = new ArrayList<>();
+        in.readList(this.underlyingIfaces, null /*classLoader*/);
+    }
+
+    @Override
+    public String toString() {
+        return "UnderlyingNetworkInfo{"
+                + "ownerUid=" + ownerUid
+                + ", iface='" + iface + '\''
+                + ", underlyingIfaces='" + underlyingIfaces.toString() + '\''
+                + '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(ownerUid);
+        dest.writeString(iface);
+        dest.writeList(underlyingIfaces);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
+            new Parcelable.Creator<UnderlyingNetworkInfo>() {
+        @NonNull
+        @Override
+        public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
+            return new UnderlyingNetworkInfo(in);
+        }
+
+        @NonNull
+        @Override
+        public UnderlyingNetworkInfo[] newArray(int size) {
+            return new UnderlyingNetworkInfo[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof UnderlyingNetworkInfo)) return false;
+        final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
+        return ownerUid == that.ownerUid
+                && Objects.equals(iface, that.iface)
+                && Objects.equals(underlyingIfaces, that.underlyingIfaces);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(ownerUid, iface, underlyingIfaces);
+    }
+}
diff --git a/core/java/android/net/VpnInfo.java b/core/java/android/net/VpnInfo.java
deleted file mode 100644
index cf58c57..0000000
--- a/core/java/android/net/VpnInfo.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 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.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * A lightweight container used to carry information of the ongoing VPN.
- * Internal use only.
- *
- * @hide
- */
-public class VpnInfo implements Parcelable {
-    public final int ownerUid;
-    @Nullable
-    public final String vpnIface;
-    @Nullable
-    public final String[] underlyingIfaces;
-
-    public VpnInfo(int ownerUid, @Nullable String vpnIface, @Nullable String[] underlyingIfaces) {
-        this.ownerUid = ownerUid;
-        this.vpnIface = vpnIface;
-        this.underlyingIfaces = underlyingIfaces;
-    }
-
-    private VpnInfo(@NonNull Parcel in) {
-        this.ownerUid = in.readInt();
-        this.vpnIface = in.readString();
-        this.underlyingIfaces = in.createStringArray();
-    }
-
-    @Override
-    public String toString() {
-        return "VpnInfo{"
-                + "ownerUid=" + ownerUid
-                + ", vpnIface='" + vpnIface + '\''
-                + ", underlyingIfaces='" + Arrays.toString(underlyingIfaces) + '\''
-                + '}';
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(ownerUid);
-        dest.writeString(vpnIface);
-        dest.writeStringArray(underlyingIfaces);
-    }
-
-    @NonNull
-    public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() {
-        @NonNull
-        @Override
-        public VpnInfo createFromParcel(@NonNull Parcel in) {
-            return new VpnInfo(in);
-        }
-
-        @NonNull
-        @Override
-        public VpnInfo[] newArray(int size) {
-            return new VpnInfo[size];
-        }
-    };
-}
diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java
index 250cff2..a22d41a 100644
--- a/core/java/android/net/http/SslCertificate.java
+++ b/core/java/android/net/http/SslCertificate.java
@@ -26,7 +26,7 @@
 import android.widget.TextView;
 
 import com.android.internal.util.HexDump;
-import com.android.org.bouncycastle.asn1.x509.X509Name;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
 
 import java.io.ByteArrayInputStream;
 import java.math.BigInteger;
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 80ac64b..4f293ee 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -16,8 +16,11 @@
 
 package android.net.vcn;
 
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
 import android.os.ParcelUuid;
 
 /**
@@ -29,4 +32,5 @@
 
     void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
     void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+    VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
 }
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 2d0a6d7..fa090f5 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -21,6 +21,8 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -62,10 +64,9 @@
  * @hide
  */
 @SystemService(Context.VCN_MANAGEMENT_SERVICE)
-public final class VcnManager {
+public class VcnManager {
     @NonNull private static final String TAG = VcnManager.class.getSimpleName();
 
-    /** @hide */
     @VisibleForTesting
     public static final Map<
                     VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
@@ -223,6 +224,37 @@
     }
 
     /**
+     * Queries the underlying network policy for a 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 VcnUnderlyingNetworkPolicyListener#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 for this Network.
+     * @param linkProperties the LinkProperties to be used in determining the Network policy for
+     *     this Network.
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+     * @return the VcnUnderlyingNetworkPolicy to be used for this Network.
+     * @hide
+     */
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties) {
+        requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+        requireNonNull(linkProperties, "linkProperties must not be null");
+
+        try {
+            return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
      * Server.
      *
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index d7c2e05..64ab074 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -97,6 +97,11 @@
     final boolean mRequiresDeviceUnlock;
 
     /**
+     * Whether this service should only be started when the device is screen on.
+     */
+    final boolean mRequiresDeviceScreenOn;
+
+    /**
      * The id of the service banner specified in XML.
      */
     final int mBannerResourceId;
@@ -119,6 +124,18 @@
             ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
+        this(info, onHost, description, staticAidGroups, dynamicAidGroups,
+                requiresUnlock, onHost ? true : false, bannerResource, uid,
+                settingsActivityName, offHost, staticOffHost);
+    }
+
+    /**
+     * @hide
+     */
+    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+            ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+            boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
+            String settingsActivityName, String offHost, String staticOffHost) {
         this.mService = info;
         this.mDescription = description;
         this.mStaticAidGroups = new HashMap<String, AidGroup>();
@@ -127,6 +144,7 @@
         this.mStaticOffHostName = staticOffHost;
         this.mOnHost = onHost;
         this.mRequiresDeviceUnlock = requiresUnlock;
+        this.mRequiresDeviceScreenOn = requiresScreenOn;
         for (AidGroup aidGroup : staticAidGroups) {
             this.mStaticAidGroups.put(aidGroup.category, aidGroup);
         }
@@ -183,6 +201,9 @@
                 mRequiresDeviceUnlock = sa.getBoolean(
                         com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
                         false);
+                mRequiresDeviceScreenOn = sa.getBoolean(
+                        com.android.internal.R.styleable.HostApduService_requireDeviceScreenOn,
+                        true);
                 mBannerResourceId = sa.getResourceId(
                         com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
                 mSettingsActivityName = sa.getString(
@@ -196,7 +217,12 @@
                 mService = info;
                 mDescription = sa.getString(
                         com.android.internal.R.styleable.OffHostApduService_description);
-                mRequiresDeviceUnlock = false;
+                mRequiresDeviceUnlock = sa.getBoolean(
+                        com.android.internal.R.styleable.OffHostApduService_requireDeviceUnlock,
+                        false);
+                mRequiresDeviceScreenOn = sa.getBoolean(
+                        com.android.internal.R.styleable.OffHostApduService_requireDeviceScreenOn,
+                        false);
                 mBannerResourceId = sa.getResourceId(
                         com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
                 mSettingsActivityName = sa.getString(
@@ -419,6 +445,13 @@
         return mRequiresDeviceUnlock;
     }
 
+    /**
+     * Returns whether this service should only be started when the device is screen on.
+     */
+    public boolean requiresScreenOn() {
+        return mRequiresDeviceScreenOn;
+    }
+
     @UnsupportedAppUsage
     public String getDescription() {
         return mDescription;
@@ -542,6 +575,7 @@
             dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
         }
         dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
+        dest.writeInt(mRequiresDeviceScreenOn ? 1 : 0);
         dest.writeInt(mBannerResourceId);
         dest.writeInt(mUid);
         dest.writeString(mSettingsActivityName);
@@ -568,11 +602,12 @@
                 source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
             }
             boolean requiresUnlock = source.readInt() != 0;
+            boolean requiresScreenOn = source.readInt() != 0;
             int bannerResource = source.readInt();
             int uid = source.readInt();
             String settingsActivityName = source.readString();
             return new ApduServiceInfo(info, onHost, description, staticAidGroups,
-                    dynamicAidGroups, requiresUnlock, bannerResource, uid,
+                    dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
                     settingsActivityName, offHostName, staticOffHostName);
         }
 
@@ -607,6 +642,8 @@
             }
         }
         pw.println("    Settings Activity: " + mSettingsActivityName);
+        pw.println("    Requires Device Unlock: " + mRequiresDeviceUnlock);
+        pw.println("    Requires Device ScreenOn: " + mRequiresDeviceScreenOn);
     }
 
     /**
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/Build.java b/core/java/android/os/Build.java
index 1076118..5ae53b5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -26,6 +26,7 @@
 import android.app.Application;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.sysprop.SocProperties;
 import android.sysprop.TelephonyProperties;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -87,6 +88,14 @@
     /** The end-user-visible name for the end product. */
     public static final String MODEL = getString("ro.product.model");
 
+    /** The manufacturer of the device's primary system-on-chip. */
+    @NonNull
+    public static final String SOC_MANUFACTURER = SocProperties.soc_manufacturer().orElse(UNKNOWN);
+
+    /** The model name of the device's primary system-on-chip. */
+    @NonNull
+    public static final String SOC_MODEL = SocProperties.soc_model().orElse(UNKNOWN);
+
     /** The system bootloader version number. */
     public static final String BOOTLOADER = getString("ro.bootloader");
 
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/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 71344f9..f853e67 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -288,6 +288,20 @@
     }
 
     /**
+     * Get service debug info.
+     * @return an array of information for each service (like listServices, but with PIDs)
+     * @hide
+     */
+    public static ServiceDebugInfo[] getServiceDebugInfo() {
+        try {
+            return getIServiceManager().getServiceDebugInfo();
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in getServiceDebugInfo", e);
+            return null;
+        }
+    }
+
+    /**
      * This is only intended to be called when the process is first being brought
      * up and bound by the activity manager. There is only one thread in the process
      * at that time, so no locking is done.
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index b70b6b5..60acc57 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -103,6 +103,10 @@
         throw new RemoteException();
     }
 
+    public ServiceDebugInfo[] getServiceDebugInfo() throws RemoteException {
+        return mServiceManager.getServiceDebugInfo();
+    }
+
     /**
      * Same as mServiceManager but used by apps.
      *
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 017f405..c39b8c5 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;
@@ -177,6 +178,7 @@
     public static final int KM_PURPOSE_SIGN = KeyPurpose.SIGN;
     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;
 
     // Key formats.
     public static final int KM_KEY_FORMAT_X509 = KeyFormat.X509;
diff --git a/core/java/android/service/dataloader/OWNERS b/core/java/android/service/dataloader/OWNERS
new file mode 100644
index 0000000..7f3906b
--- /dev/null
+++ b/core/java/android/service/dataloader/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/incremental/OWNERS
\ No newline at end of file
diff --git a/core/java/android/service/smartspace/OWNERS b/core/java/android/service/smartspace/OWNERS
new file mode 100644
index 0000000..19ef9d7
--- /dev/null
+++ b/core/java/android/service/smartspace/OWNERS
@@ -0,0 +1,2 @@
+srazdan@google.com
+alexmang@google.com
\ No newline at end of file
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 023d9ff2..20230e7 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -98,9 +98,17 @@
     public abstract boolean acceptThirdPartyCookies(WebView webview);
 
     /**
-     * Sets a cookie for the given URL. Any existing cookie with the same host,
-     * path and name will be replaced with the new cookie. The cookie being set
-     * will be ignored if it is expired.
+     * Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
+     * host, path and name will be replaced with the new cookie. The cookie being set
+     * will be ignored if it is expired. To set multiple cookies, your application should invoke
+     * this method multiple times.
+     *
+     * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
+     * response header defined by
+     * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
+     * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
+     * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
+     * consult the RFC specification for a list of valid attributes.
      *
      * <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
      * attribute, {@code url} must use the {@code "https://"} scheme.
@@ -112,13 +120,20 @@
     public abstract void setCookie(String url, String value);
 
     /**
-     * Sets a cookie for the given URL. Any existing cookie with the same host,
-     * path and name will be replaced with the new cookie. The cookie being set
-     * will be ignored if it is expired.
-     * <p>
-     * This method is asynchronous.
-     * If a {@link ValueCallback} is provided,
-     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+     * Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
+     * host, path and name will be replaced with the new cookie. The cookie being set
+     * will be ignored if it is expired. To set multiple cookies, your application should invoke
+     * this method multiple times.
+     *
+     * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
+     * response header defined by
+     * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
+     * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
+     * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
+     * consult the RFC specification for a list of valid attributes.
+     *
+     * <p>This method is asynchronous. If a {@link ValueCallback} is provided,
+     * {@link ValueCallback#onReceiveValue} will be called on the current
      * thread's {@link android.os.Looper} once the operation is complete.
      * The value provided to the callback indicates whether the cookie was set successfully.
      * You can pass {@code null} as the callback if you don't need to know when the operation
@@ -137,7 +152,10 @@
             callback);
 
     /**
-     * Gets the cookies for the given URL.
+     * Gets all the cookies for the given URL. This may return multiple key-value pairs if multiple
+     * cookies are associated with this URL, in which case each cookie will be delimited by {@code
+     * "; "} characters (semicolon followed by a space). Each key-value pair will be of the form
+     * {@code "key=value"}.
      *
      * @param url the URL for which the cookies are requested
      * @return value the cookies as a string, using the format of the 'Cookie'
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index e6a1661..beef982 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -129,7 +129,7 @@
     void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
     void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
     void noteWifiRadioPowerState(int powerState, long timestampNs, int uid);
-    void noteNetworkInterfaceType(String iface, int type);
+    void noteNetworkInterfaceForTransports(String iface, in int[] transportTypes);
     void noteNetworkStatsEnabled();
     void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 99692d0..7ade05c 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -5,3 +5,4 @@
 per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
 per-file IVoice* = file:/core/java/android/service/voice/OWNERS
 per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
+per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 8bfc28e..ae680e0 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -23,7 +23,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.SensorManager;
-import android.net.ConnectivityManager;
 import android.os.BatteryStats;
 import android.os.BatteryStats.Uid;
 import android.os.Build;
@@ -37,6 +36,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -148,12 +148,11 @@
     boolean mHasBluetoothPowerReporting = false;
 
     public static boolean checkWifiOnly(Context context) {
-        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        if (cm == null) {
+        final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+        if (tm == null) {
             return false;
         }
-        return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        return !tm.isDataCapable();
     }
 
     public static boolean checkHasWifiPowerReporting(BatteryStats stats, PowerProfile profile) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1071d9f..2d75b70 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.os;
 
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
 import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
 
@@ -32,7 +34,6 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.NetworkStats;
 import android.net.Uri;
@@ -101,6 +102,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
 
 import libcore.util.EmptyArray;
 
@@ -6099,11 +6101,12 @@
     }
 
     /** @hide */
-    public void noteNetworkInterfaceType(String iface, int networkType) {
+    public void noteNetworkInterfaceForTransports(String iface, int[] transportTypes) {
         if (TextUtils.isEmpty(iface)) return;
+        final int displayTransport = NetworkCapabilitiesUtils.getDisplayTransport(transportTypes);
 
         synchronized (mModemNetworkLock) {
-            if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
+            if (displayTransport == TRANSPORT_CELLULAR) {
                 mModemIfaces = includeInStringArray(mModemIfaces, iface);
                 if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mModemIfaces);
             } else {
@@ -6113,7 +6116,7 @@
         }
 
         synchronized (mWifiNetworkLock) {
-            if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
+            if (displayTransport == TRANSPORT_WIFI) {
                 mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
                 if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
             } else {
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index ae566c3..3fc3933 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -5,3 +5,16 @@
 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 *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/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
index c17a020..13c9115 100644
--- a/core/jni/android_media_AudioErrors.h
+++ b/core/jni/android_media_AudioErrors.h
@@ -35,7 +35,7 @@
     AUDIO_JAVA_WOULD_BLOCK        = -7,
 };
 
-static inline jint nativeToJavaStatus(status_t status) {
+static constexpr inline jint nativeToJavaStatus(status_t status) {
     switch (status) {
     case NO_ERROR:
         return AUDIO_JAVA_SUCCESS;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 7a5c383..065c79b 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -263,18 +263,7 @@
         return (jint) AUDIO_JAVA_ERROR;
     }
 
-    // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
-    if (tunerConfiguration != nullptr) {
-        const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
-        ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
-              tunerHelper.getContentId(), tunerHelper.getSyncId());
-        return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
-    }
-    // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
-    if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
-        ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
-        return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
-    }
+    const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
 
     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
@@ -369,6 +358,18 @@
             offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
         }
 
+        if (encapsulationMode != 0) {
+            offloadInfo = AUDIO_INFO_INITIALIZER;
+            offloadInfo.format = format;
+            offloadInfo.sample_rate = sampleRateInHertz;
+            offloadInfo.channel_mask = nativeChannelMask;
+            offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+            offloadInfo.encapsulation_mode =
+                    static_cast<audio_encapsulation_mode_t>(encapsulationMode);
+            offloadInfo.content_id = tunerHelper.getContentId();
+            offloadInfo.sync_id = tunerHelper.getSyncId();
+        }
+
         // initialize the native AudioTrack object
         status_t status = NO_ERROR;
         switch (memoryMode) {
@@ -389,7 +390,8 @@
                                   sessionId, // audio session ID
                                   offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
                                           : AudioTrack::TRANSFER_SYNC,
-                                  offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values
+                                  (offload || encapsulationMode) ? &offloadInfo : NULL, -1,
+                                  -1, // default uid, pid values
                                   paa.get());
             break;
 
@@ -1364,8 +1366,7 @@
         return (jint)AUDIO_JAVA_ERROR;
     }
 
-    // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
-    return (jint)AUDIO_JAVA_ERROR;
+    return nativeToJavaStatus(lpTrack->setAudioDescriptionMixLevel(level));
 }
 
 static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
@@ -1381,12 +1382,10 @@
         return (jint)AUDIO_JAVA_ERROR;
     }
 
-    // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
-    // By contract we can return -infinity if unsupported.
-    *nativeLevel = -std::numeric_limits<float>::infinity();
+    status_t status = lpTrack->getAudioDescriptionMixLevel(reinterpret_cast<float *>(nativeLevel));
     env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
-    nativeLevel = nullptr;
-    return (jint)AUDIO_JAVA_SUCCESS;
+
+    return nativeToJavaStatus(status);
 }
 
 static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
@@ -1396,8 +1395,8 @@
         return (jint)AUDIO_JAVA_ERROR;
     }
 
-    // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
-    return (jint)AUDIO_JAVA_ERROR;
+    return nativeToJavaStatus(
+            lpTrack->setDualMonoMode(static_cast<audio_dual_mono_mode_t>(dualMonoMode)));
 }
 
 static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
@@ -1407,18 +1406,17 @@
         ALOGE("%s: AudioTrack not initialized", __func__);
         return (jint)AUDIO_JAVA_ERROR;
     }
-    jfloat *nativeDualMonoMode = (jfloat *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
+    jint *nativeDualMonoMode = (jint *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
     if (nativeDualMonoMode == nullptr) {
         ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
         return (jint)AUDIO_JAVA_ERROR;
     }
 
-    // TODO: replace in r-dev or r-tv-dev with code if HW is able to select dual mono mode.
-    // By contract we can return DUAL_MONO_MODE_OFF if unsupported.
-    *nativeDualMonoMode = 0; // DUAL_MONO_MODE_OFF for now.
+    status_t status = lpTrack->getDualMonoMode(
+            reinterpret_cast<audio_dual_mono_mode_t *>(nativeDualMonoMode));
     env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
-    nativeDualMonoMode = nullptr;
-    return (jint)AUDIO_JAVA_SUCCESS;
+
+    return nativeToJavaStatus(status);
 }
 
 // ----------------------------------------------------------------------------
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_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 b2e562c..d7001d8 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -70,7 +70,6 @@
 #include <bionic/malloc.h>
 #include <bionic/mte.h>
 #include <cutils/fs.h>
-#include <cutils/memory.h>
 #include <cutils/multiuser.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
@@ -638,13 +637,6 @@
 
   // Set the jemalloc decay time to 1.
   mallopt(M_DECAY_TIME, 1);
-
-  // Avoid potentially expensive memory mitigations, mostly meant for system
-  // processes, in apps. These may cause app compat problems, use more memory,
-  // or reduce performance. While it would be nice to have them for apps,
-  // we will have to wait until they are proven out, have more efficient
-  // hardware, and/or apply them only to new applications.
-  process_disable_memory_mitigations();
 }
 
 static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) {
@@ -1811,6 +1803,14 @@
       break;
   }
   mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
+
+  // Avoid heap zero initialization for applications without MTE. Zero init may
+  // cause app compat problems, use more memory, or reduce performance. While it
+  // would be nice to have them for apps, we will have to wait until they are
+  // proven out, have more efficient hardware, and/or apply them only to new
+  // applications.
+  mallopt(M_BIONIC_ZERO_INIT, 0);
+
   // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
   runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 24dabfc..0e80c7b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1673,7 +1673,7 @@
      @SystemApi
      <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM"
-                android:protectionLevel="signature|setup" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows applications to toggle airplane mode.
          <p>Not for use by third-party or privileged applications.
@@ -4507,7 +4507,7 @@
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|setup" />
 
     <!-- Allows applications to set the initial lockscreen state.
          <p>Not for use by third-party applications. @hide -->
diff --git a/core/res/OWNERS b/core/res/OWNERS
index a30111b..9d739b9 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -6,9 +6,12 @@
 dupin@google.com
 hackbod@android.com
 hackbod@google.com
+ilyamaty@google.com
+jaggies@google.com
 jsharkey@android.com
 jsharkey@google.com
 juliacr@google.com
+kchyn@google.com
 michaelwr@google.com
 nandana@google.com
 narayan@google.com
diff --git a/core/res/assets/images/progress_font.png b/core/res/assets/images/progress_font.png
new file mode 100644
index 0000000..78c3ed9
--- /dev/null
+++ b/core/res/assets/images/progress_font.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4b3d82a..9cc0690 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3856,6 +3856,9 @@
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. -->
         <attr name="settingsActivity"/>
+        <!-- Whether the device must be screen on before routing data to this service.
+             The default is true.-->
+        <attr name="requireDeviceScreenOn" format="boolean"/>
     </declare-styleable>
 
     <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -3874,6 +3877,12 @@
         <attr name="settingsActivity"/>
         <!-- Secure Element which the AIDs should be routed to -->
         <attr name="secureElementName" format="string"/>
+        <!-- Whether the device must be unlocked before routing data to this service.
+             The default is false.-->
+        <attr name="requireDeviceUnlock"/>
+        <!-- Whether the device must be screen on before routing data to this service.
+             The default is false.-->
+        <attr name="requireDeviceScreenOn"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d30efa9..20cb270 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4411,4 +4411,7 @@
 
     <!-- Component names of the services which will keep critical code path warm -->
     <string-array name="config_keep_warming_services" translatable="false" />
+
+    <!-- Whether to select voice/data/sms preference without user confirmation -->
+    <bool name="config_voice_data_sms_auto_fallback">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a0be068..0874a77 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3045,6 +3045,7 @@
   <public-group type="attr" first-id="0x01010617">
     <public name="canPauseRecording" />
     <!-- attribute definitions go here -->
+    <public name="requireDeviceScreenOn" />
   </public-group>
 
   <public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 937716d..4509b4e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4057,4 +4057,6 @@
   <java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
 
   <java-symbol type="array" name="config_keep_warming_services" />
+
+  <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
 </resources>
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 912db1e..c61a4b5 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -1,3 +1,4 @@
+per-file AssetTest.java = file:/core/java/android/content/res/OWNERS
 per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
-per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
+per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
diff --git a/core/tests/coretests/src/android/content/integrity/OWNERS b/core/tests/coretests/src/android/content/integrity/OWNERS
new file mode 100644
index 0000000..4ffc704
--- /dev/null
+++ b/core/tests/coretests/src/android/content/integrity/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/integrity/OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
index 7b76706..8673365 100644
--- a/core/tests/coretests/src/android/content/pm/OWNERS
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -1,3 +1,5 @@
+include /core/java/android/content/pm/OWNERS
+
 per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-per-file SigningDetailsTest.java = mpgroover@google.com
 per-file SigningDetailsTest.java = cbrubaker@google.com
+per-file SigningDetailsTest.java = mpgroover@google.com
diff --git a/core/tests/coretests/src/android/content/res/OWNERS b/core/tests/coretests/src/android/content/res/OWNERS
new file mode 100644
index 0000000..3e79d8f
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
diff --git a/core/tests/mockingcoretests/src/android/view/OWNERS b/core/tests/mockingcoretests/src/android/view/OWNERS
new file mode 100644
index 0000000..9c9f824
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/view/OWNERS
@@ -0,0 +1,2 @@
+# Display
+per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 30501fb..a664ee3 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -345,7 +345,6 @@
         <permission name="android.permission.MOVE_PACKAGE"/>
         <!-- Needed for test only -->
         <permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
-        <permission name="android.permission.NETWORK_AIRPLANE_MODE"/>
         <permission name="android.permission.OBSERVE_APP_USAGE"/>
         <permission name="android.permission.NETWORK_SCAN"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
@@ -444,6 +443,9 @@
         <!-- Permission needed for CTS test - WifiManagerTest -->
         <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
         <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+        <!-- Permission required for GTS test - GtsAssistIntentTestCases -->
+        <permission name="android.permission.MANAGE_SOUND_TRIGGER" />
+        <permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 7abcfdc..9e1fb54 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -19,9 +19,9 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 
-import com.android.org.bouncycastle.util.io.pem.PemObject;
-import com.android.org.bouncycastle.util.io.pem.PemReader;
-import com.android.org.bouncycastle.util.io.pem.PemWriter;
+import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
+import com.android.internal.org.bouncycastle.util.io.pem.PemReader;
+import com.android.internal.org.bouncycastle.util.io.pem.PemWriter;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 4a67135..e19d88c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -45,8 +45,8 @@
 import android.security.keystore.UserNotAuthenticatedException;
 import android.util.Log;
 
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 92d87aa..f7477bf 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.security.keymaster.KeymasterDefs;
 import android.system.keystore2.IKeystoreService;
 import android.system.keystore2.KeyDescriptor;
 import android.system.keystore2.KeyEntryResponse;
@@ -107,7 +108,7 @@
                 return request.execute(service);
             } catch (ServiceSpecificException e) {
                 Log.e(TAG, "KeyStore exception", e);
-                throw new KeyStoreException(e.errorCode, "");
+                throw getKeyStoreException(e.errorCode);
             } catch (RemoteException e) {
                 if (firstTry) {
                     Log.w(TAG, "Looks like we may have lost connection to the Keystore "
@@ -274,4 +275,40 @@
         }
     }
 
+    static KeyStoreException getKeyStoreException(int errorCode) {
+        if (errorCode > 0) {
+            // KeyStore layer error
+            switch (errorCode) {
+                case ResponseCode.LOCKED:
+                    return new KeyStoreException(errorCode, "User authentication required");
+                case ResponseCode.UNINITIALIZED:
+                    return new KeyStoreException(errorCode, "Keystore not initialized");
+                case ResponseCode.SYSTEM_ERROR:
+                    return new KeyStoreException(errorCode, "System error");
+                case ResponseCode.PERMISSION_DENIED:
+                    return new KeyStoreException(errorCode, "Permission denied");
+                case ResponseCode.KEY_NOT_FOUND:
+                    return new KeyStoreException(errorCode, "Key not found");
+                case ResponseCode.VALUE_CORRUPTED:
+                    return new KeyStoreException(errorCode, "Key blob corrupted");
+                case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
+                    return new KeyStoreException(errorCode, "Key permanently invalidated");
+                default:
+                    return new KeyStoreException(errorCode, String.valueOf(errorCode));
+            }
+        } else {
+            // Keymaster layer error
+            switch (errorCode) {
+                case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
+                    // The name of this parameter significantly differs between Keymaster and
+                    // framework APIs. Use the framework wording to make life easier for developers.
+                    return new KeyStoreException(errorCode,
+                            "Invalid user authentication validity duration");
+                default:
+                    return new KeyStoreException(errorCode,
+                            KeymasterDefs.getErrorMessage(errorCode));
+            }
+        }
+    }
+
 }
diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java
index 7ea9e14..a6552dd 100644
--- a/keystore/java/android/security/KeyStoreOperation.java
+++ b/keystore/java/android/security/KeyStoreOperation.java
@@ -73,8 +73,7 @@
                     );
                 }
                 default:
-                    // TODO Human readable string. Use something like KeyStore.getKeyStoreException
-                    throw new KeyStoreException(e.errorCode, "");
+                    throw KeyStore2.getKeyStoreException(e.errorCode);
             }
         } catch (RemoteException e) {
             // Log exception and report invalid operation handle.
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 3ef4aa5..372add9 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -52,7 +52,7 @@
         try {
             return request.execute();
         } catch (ServiceSpecificException e) {
-            throw new KeyStoreException(e.errorCode, "");
+            throw KeyStore2.getKeyStoreException(e.errorCode);
         } catch (RemoteException e) {
             // Log exception and report invalid operation handle.
             // This should prompt the caller drop the reference to this operation and retry.
@@ -96,25 +96,26 @@
             } catch (ServiceSpecificException e) {
                 switch (e.errorCode) {
                     case ResponseCode.BACKEND_BUSY: {
+                        long backOffHint = (long) (Math.random() * 80 + 20);
                         if (CompatChanges.isChangeEnabled(
                                 KeyStore2.KEYSTORE_OPERATION_CREATION_MAY_FAIL)) {
                             // Starting with Android S we inform the caller about the
                             // backend being busy.
-                            throw new BackendBusyException();
+                            throw new BackendBusyException(backOffHint);
                         } else {
                             // Before Android S operation creation must always succeed. So we
                             // just have to retry. We do so with a randomized back-off between
-                            // 50 and 250ms.
+                            // 20 and 100ms.
                             // It is a little awkward that we cannot break out of this loop
                             // by interrupting this thread. But that is the expected behavior.
                             // There is some comfort in the fact that interrupting a thread
                             // also does not unblock a thread waiting for a binder transaction.
-                            interruptedPreservingSleep((long) (Math.random() * 200 + 50));
+                            interruptedPreservingSleep(backOffHint);
                         }
                         break;
                     }
                     default:
-                        throw new KeyStoreException(e.errorCode, "");
+                        throw KeyStore2.getKeyStoreException(e.errorCode);
                 }
             } catch (RemoteException e) {
                 Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 6ad8d2c..334b111 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -26,24 +26,24 @@
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keymaster.KeymasterDefs;
 
-import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.ASN1Integer;
-import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import com.android.org.bouncycastle.asn1.DERBitString;
-import com.android.org.bouncycastle.asn1.DERNull;
-import com.android.org.bouncycastle.asn1.DERSequence;
-import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import com.android.org.bouncycastle.asn1.x509.Certificate;
-import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import com.android.org.bouncycastle.asn1.x509.TBSCertificate;
-import com.android.org.bouncycastle.asn1.x509.Time;
-import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import com.android.org.bouncycastle.jce.X509Principal;
-import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
-import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
+import com.android.internal.org.bouncycastle.asn1.x509.Time;
+import com.android.internal.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.jce.provider.X509CertificateObject;
+import com.android.internal.org.bouncycastle.x509.X509V3CertificateGenerator;
 
 import libcore.util.EmptyArray;
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index b1b6306..16bf546 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) {
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/BackendBusyException.java b/keystore/java/android/security/keystore/BackendBusyException.java
index 1a88469..a813e93 100644
--- a/keystore/java/android/security/keystore/BackendBusyException.java
+++ b/keystore/java/android/security/keystore/BackendBusyException.java
@@ -16,37 +16,66 @@
 
 package android.security.keystore;
 
+import android.annotation.DurationMillisLong;
 import android.annotation.NonNull;
 
 import java.security.ProviderException;
 
 /**
  * Indicates a transient error that prevented a key operation from being created.
- * Callers should try again with a back-off period of 10-30 milliseconds.
+ * Callers should try again with a back-off period of {@link #getBackOffHintMillis()}
+ * milliseconds.
  */
 public class BackendBusyException extends ProviderException {
 
+    private final long mBackOffHintMillis;
+
     /**
      * Constructs a new {@code BackendBusyException} without detail message and cause.
+     *
      */
-    public BackendBusyException() {
+    public BackendBusyException(@DurationMillisLong long backOffHintMillis) {
         super("The keystore backend has no operation slots available. Retry later.");
+        if (backOffHintMillis < 0) {
+            throw new IllegalArgumentException("Back-off hint cannot be negative.");
+        }
+        mBackOffHintMillis = backOffHintMillis;
     }
 
     /**
      * Constructs a new {@code BackendBusyException} with the provided detail message and
      * no cause.
      */
-    public BackendBusyException(@NonNull String message) {
+    public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+            @NonNull String message) {
         super(message);
+        if (backOffHintMillis < 0) {
+            throw new IllegalArgumentException("Back-off hint cannot be negative.");
+        }
+        mBackOffHintMillis = backOffHintMillis;
     }
 
     /**
      * Constructs a new {@code BackendBusyException} with the provided detail message and
      * cause.
      */
-    public BackendBusyException(@NonNull String message, @NonNull Throwable cause) {
+    public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+            @NonNull String message, @NonNull Throwable cause) {
         super(message, cause);
+        if (backOffHintMillis < 0) {
+            throw new IllegalArgumentException("Back-off hint cannot be negative.");
+        }
+        mBackOffHintMillis = backOffHintMillis;
     }
 
+    /**
+     * When retrying to start a Keystore operation after receiving this exception, this can be
+     * used to determine how long to wait before retrying. It is not guaranteed that the operation
+     * will succeeds after this time. Multiple retries may be necessary if the system is congested.
+     *
+     * @return Number of milliseconds to back off before retrying.
+     */
+    public @DurationMillisLong long getBackOffHintMillis() {
+        return mBackOffHintMillis;
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index e9aac7d..c2a7b2e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -274,6 +274,7 @@
     private final boolean mUserConfirmationRequired;
     private final boolean mUnlockedDeviceRequired;
     private final boolean mCriticalToDeviceEncryption;
+    private final int mMaxUsageCount;
     /*
      * ***NOTE***: All new fields MUST also be added to the following:
      * ParcelableKeyGenParameterSpec class.
@@ -313,7 +314,8 @@
             boolean isStrongBoxBacked,
             boolean userConfirmationRequired,
             boolean unlockedDeviceRequired,
-            boolean criticalToDeviceEncryption) {
+            boolean criticalToDeviceEncryption,
+            int maxUsageCount) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -366,6 +368,7 @@
         mUserConfirmationRequired = userConfirmationRequired;
         mUnlockedDeviceRequired = unlockedDeviceRequired;
         mCriticalToDeviceEncryption = criticalToDeviceEncryption;
+        mMaxUsageCount = maxUsageCount;
     }
 
     /**
@@ -782,7 +785,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 +795,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 KeyGenParameterSpec} instances.
      */
     public final static class Builder {
@@ -827,6 +841,7 @@
         private boolean mUserConfirmationRequired;
         private boolean mUnlockedDeviceRequired = false;
         private boolean mCriticalToDeviceEncryption = false;
+        private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -894,6 +909,7 @@
             mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
             mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
             mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();
+            mMaxUsageCount = sourceSpec.getMaxUsageCount();
         }
 
         /**
@@ -1553,6 +1569,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 {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1587,7 +1644,8 @@
                     mIsStrongBoxBacked,
                     mUserConfirmationRequired,
                     mUnlockedDeviceRequired,
-                    mCriticalToDeviceEncryption);
+                    mCriticalToDeviceEncryption,
+                    mMaxUsageCount);
         }
     }
 }
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 5928540..fa4f8b1 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -67,6 +67,7 @@
             PURPOSE_SIGN,
             PURPOSE_VERIFY,
             PURPOSE_WRAP_KEY,
+            PURPOSE_AGREE_KEY,
     })
     public @interface PurposeEnum {}
 
@@ -96,6 +97,11 @@
     public static final int PURPOSE_WRAP_KEY = 1 << 5;
 
     /**
+     * Purpose of key: creating a shared ECDH secret through key agreement.
+     */
+    public static final int PURPOSE_AGREE_KEY = 1 << 6;
+
+    /**
      * @hide
      */
     public static abstract class Purpose {
@@ -113,6 +119,8 @@
                     return KeymasterDefs.KM_PURPOSE_VERIFY;
                 case PURPOSE_WRAP_KEY:
                     return KeymasterDefs.KM_PURPOSE_WRAP;
+                case PURPOSE_AGREE_KEY:
+                    return KeymasterDefs.KM_PURPOSE_AGREE_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
@@ -130,6 +138,8 @@
                     return PURPOSE_VERIFY;
                 case KeymasterDefs.KM_PURPOSE_WRAP:
                     return PURPOSE_WRAP_KEY;
+                case KeymasterDefs.KM_PURPOSE_AGREE_KEY:
+                    return PURPOSE_AGREE_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
@@ -897,4 +907,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..76ce23e 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,7 @@
         private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
         private boolean mCriticalToDeviceEncryption = false;
         private boolean mIsStrongBoxBacked = false;
+        private  int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -1040,6 +1055,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 +1122,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..8163472 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -108,6 +108,7 @@
         out.writeBoolean(mSpec.isUserConfirmationRequired());
         out.writeBoolean(mSpec.isUnlockedDeviceRequired());
         out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
+        out.writeInt(mSpec.getMaxUsageCount());
     }
 
     private static Date readDateOrNull(Parcel in) {
@@ -166,6 +167,7 @@
         final boolean userConfirmationRequired = in.readBoolean();
         final boolean unlockedDeviceRequired = in.readBoolean();
         final boolean criticalToDeviceEncryption = in.readBoolean();
+        final int maxUsageCount = in.readInt();
         // 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).
@@ -199,7 +201,8 @@
                 isStrongBoxBacked,
                 userConfirmationRequired,
                 unlockedDeviceRequired,
-                criticalToDeviceEncryption);
+                criticalToDeviceEncryption,
+                maxUsageCount);
     }
 
     public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
new file mode 100644
index 0000000..fc963a8
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
@@ -0,0 +1,240 @@
+/*
+ * 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.keystore2;
+
+import android.hardware.security.keymint.Algorithm;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyPurpose;
+import android.hardware.security.keymint.Tag;
+import android.security.KeyStoreException;
+import android.security.KeyStoreOperation;
+import android.security.keystore.KeyStoreCryptoOperation;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * {@link KeyAgreementSpi} which provides an ECDH implementation backed by Android KeyStore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi
+        implements KeyStoreCryptoOperation {
+
+    private static final String TAG = "AndroidKeyStoreKeyAgreementSpi";
+
+    /**
+     * ECDH implementation.
+     *
+     * @hide
+     */
+    public static class ECDH extends AndroidKeyStoreKeyAgreementSpi {
+        public ECDH() {
+            super(Algorithm.EC);
+        }
+    }
+
+    private final int mKeymintAlgorithm;
+
+    // Fields below are populated by engineInit and should be preserved after engineDoFinal.
+    private AndroidKeyStorePrivateKey mKey;
+    private PublicKey mOtherPartyKey;
+
+    // Fields below are reset when engineDoFinal succeeds.
+    private KeyStoreOperation mOperation;
+    private long mOperationHandle;
+
+    protected AndroidKeyStoreKeyAgreementSpi(int keymintAlgorithm) {
+        resetAll();
+
+        mKeymintAlgorithm = keymintAlgorithm;
+    }
+
+    @Override
+    protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+        resetAll();
+
+        if (key == null) {
+            throw new InvalidKeyException("key == null");
+        } else if (!(key instanceof AndroidKeyStorePrivateKey)) {
+            throw new InvalidKeyException(
+                    "Only Android KeyStore private keys supported. Key: " + key);
+        }
+        // Checking the correct KEY_PURPOSE and algorithm is done by the Keymint implementation in
+        // ensureKeystoreOperationInitialized() below.
+        mKey = (AndroidKeyStorePrivateKey) key;
+
+        boolean success = false;
+        try {
+            ensureKeystoreOperationInitialized();
+            success = true;
+        } finally {
+            if (!success) {
+                resetAll();
+            }
+        }
+    }
+
+    @Override
+    protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (params != null) {
+            throw new InvalidAlgorithmParameterException(
+                    "Unsupported algorithm parameters: " + params);
+        }
+        engineInit(key, random);
+    }
+
+    @Override
+    protected Key engineDoPhase(Key key, boolean lastPhase)
+            throws InvalidKeyException, IllegalStateException {
+        ensureKeystoreOperationInitialized();
+
+        if (key == null) {
+            throw new InvalidKeyException("key == null");
+        } else if (!(key instanceof PublicKey)) {
+            throw new InvalidKeyException("Only public keys supported. Key: " + key);
+        } else if (!lastPhase) {
+            throw new IllegalStateException(
+                    "Only one other party supported. lastPhase must be set to true.");
+        } else if (mOtherPartyKey != null) {
+            throw new IllegalStateException(
+                    "Only one other party supported. doPhase() must only be called exactly once.");
+        }
+        // The other party key will be passed as part of the doFinal() call, to prevent an
+        // additional IPC.
+        mOtherPartyKey = (PublicKey) key;
+
+        return null; // No intermediate key
+    }
+
+    @Override
+    protected byte[] engineGenerateSecret() throws IllegalStateException {
+        try {
+            ensureKeystoreOperationInitialized();
+        } catch (InvalidKeyException e) {
+            throw new IllegalStateException("Not initialized", e);
+        }
+
+        if (mOtherPartyKey == null) {
+            throw new IllegalStateException("Other party key not provided. Call doPhase() first.");
+        }
+        byte[] otherPartyKeyEncoded = mOtherPartyKey.getEncoded();
+
+        try {
+            return mOperation.finish(otherPartyKeyEncoded, null);
+        } catch (KeyStoreException e) {
+            throw new ProviderException("Keystore operation failed", e);
+        } finally {
+            resetWhilePreservingInitState();
+        }
+    }
+
+    @Override
+    protected SecretKey engineGenerateSecret(String algorithm)
+            throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+        byte[] generatedSecret = engineGenerateSecret();
+
+        return new SecretKeySpec(generatedSecret, algorithm);
+    }
+
+    @Override
+    protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+            throws IllegalStateException, ShortBufferException {
+        byte[] generatedSecret = engineGenerateSecret();
+
+        if (generatedSecret.length > sharedSecret.length - offset) {
+            throw new ShortBufferException("Needed: " + generatedSecret.length);
+        }
+        System.arraycopy(generatedSecret, 0, sharedSecret, offset, generatedSecret.length);
+        return generatedSecret.length;
+    }
+
+    @Override
+    public long getOperationHandle() {
+        return mOperationHandle;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            resetAll();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void resetWhilePreservingInitState() {
+        KeyStoreCryptoOperationUtils.abortOperation(mOperation);
+        mOperationHandle = 0;
+        mOperation = null;
+        mOtherPartyKey = null;
+    }
+
+    private void resetAll() {
+        resetWhilePreservingInitState();
+        mKey = null;
+    }
+
+    private void ensureKeystoreOperationInitialized()
+            throws InvalidKeyException, IllegalStateException {
+        if (mKey == null) {
+            throw new IllegalStateException("Not initialized");
+        }
+        if (mOperation != null) {
+            return;
+        }
+
+        // We don't need to explicitly pass in any other parameters here, as they're part of the
+        // private key that is available to Keymint.
+        List<KeyParameter> parameters = new ArrayList<>();
+        parameters.add(KeyStore2ParameterUtils.makeEnum(
+                Tag.PURPOSE, KeyPurpose.AGREE_KEY
+        ));
+
+        try {
+            mOperation =
+                    mKey.getSecurityLevel().createOperation(mKey.getKeyIdDescriptor(), parameters);
+        } catch (KeyStoreException keyStoreException) {
+            // If necessary, throw an exception due to KeyStore operation having failed.
+            InvalidKeyException e =
+                    KeyStoreCryptoOperationUtils.getInvalidKeyException(mKey, keyStoreException);
+            if (e != null) {
+                throw e;
+            }
+        }
+
+        // Set the operation handle. This will be a random number, or the operation challenge if
+        // user authentication is required. If we got a challenge we check if the authorization can
+        // possibly succeed.
+        mOperationHandle =
+                KeyStoreCryptoOperationUtils.getOrMakeOperationChallenge(mOperation, mKey);
+    }
+}
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..6a92980 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -586,6 +586,13 @@
             ));
         }
 
+        if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+            params.add(KeyStore2ParameterUtils.makeInt(
+                    KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+                    mSpec.getMaxUsageCount()
+            ));
+        }
+
         addAlgorithmSpecificParameters(params);
 
         if (mSpec.isUniqueIdIncluded()) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 403da18..75ac61a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -94,6 +94,9 @@
             put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
         }
 
+        // javax.crypto.KeyAgreement
+        put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
+
         // java.security.SecretKeyFactory
         putSecretKeyFactoryImpl("AES");
         if (supports3DES) {
@@ -360,6 +363,11 @@
             }
         }
 
+        if (response.iSecurityLevel == null) {
+            // This seems to be a pure certificate entry, nothing to return here.
+            return null;
+        }
+
         Integer keymasterAlgorithm = null;
         // We just need one digest for the algorithm name
         int keymasterDigest = -1;
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 5e7f648..8c8acc4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -490,7 +490,7 @@
             int[] keymasterEncryptionPaddings =
                     KeyProperties.EncryptionPadding.allToKeymaster(
                             spec.getEncryptionPaddings());
-            if (((spec.getPurposes() & KeyProperties.PURPOSE_DECRYPT) != 0)
+            if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
                     && (spec.isRandomizedEncryptionRequired())) {
                 for (int keymasterPadding : keymasterEncryptionPaddings) {
                     if (!KeymasterUtils
@@ -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);
         }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index d67cf8c..621f286 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -301,7 +301,8 @@
     }
     sk_sp<SkImage> image = bitmap.makeImage();
 
-    applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+    applyLooper(get_looper(paint), *filterBitmap(std::move(filteredPaint)),
+                [&](SkScalar x, SkScalar y, const SkPaint& p) {
         mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
     });
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7dff0c2..d22e97c 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5434,8 +5434,12 @@
     public boolean setAdditionalOutputDeviceDelay(
             @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
         Objects.requireNonNull(device);
-        // Implement the setter in r-dev or r-tv-dev as needed.
-        return false;
+        try {
+            return getService().setAdditionalOutputDeviceDelay(
+                new AudioDeviceAttributes(device), delayMillis);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -5450,8 +5454,11 @@
     @IntRange(from = 0)
     public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
         Objects.requireNonNull(device);
-        // Implement the getter in r-dev or r-tv-dev as needed.
-        return 0;
+        try {
+            return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -5468,8 +5475,12 @@
     @IntRange(from = 0)
     public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
         Objects.requireNonNull(device);
-        // Implement the getter in r-dev or r-tv-dev as needed.
-        return 0;
+        try {
+            return getService().getMaxAdditionalOutputDeviceDelay(
+                    new AudioDeviceAttributes(device));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b2c2c4b..d7ef454 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1269,10 +1269,12 @@
             // native code figure out the minimum buffer size.
             if (mMode == MODE_STREAM && mBufferSizeInBytes == 0) {
                 int bytesPerSample = 1;
-                try {
-                    bytesPerSample = mFormat.getBytesPerSample(mFormat.getEncoding());
-                } catch (IllegalArgumentException e) {
-                    // do nothing
+                if (AudioFormat.isEncodingLinearFrames(mFormat.getEncoding())) {
+                    try {
+                        bytesPerSample = mFormat.getBytesPerSample(mFormat.getEncoding());
+                    } catch (IllegalArgumentException e) {
+                        // do nothing
+                    }
                 }
                 mBufferSizeInBytes = mFormat.getChannelCount() * bytesPerSample;
             }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ebaa316..ed48b56 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -330,4 +330,10 @@
 
     oneway void unregisterCommunicationDeviceDispatcher(
             ICommunicationDeviceDispatcher dispatcher);
+
+    boolean setAdditionalOutputDeviceDelay(in AudioDeviceAttributes device, long delayMillis);
+
+    long getAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
+
+    long getMaxAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
 }
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5daf8b0..694b939 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -169,8 +169,9 @@
 static int IP_V4_LENGTH = 4;
 static int IP_V6_LENGTH = 16;
 
-void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
+void DestroyCallback(const C2Buffer * buf, void *arg) {
     android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
+    android::Mutex::Autolock autoLock(event->mLock);
     if (event->mLinearBlockObj != NULL) {
         JNIEnv *env = android::AndroidRuntime::getJNIEnv();
         env->DeleteWeakGlobalRef(event->mLinearBlockObj);
@@ -179,6 +180,7 @@
 
     event->mAvHandleRefCnt--;
     event->finalize();
+    event->decStrong(buf);
 }
 
 namespace android {
@@ -369,6 +371,7 @@
             pC2Buffer->setInfo(info);
         }
         pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
+        incStrong(pC2Buffer.get());
         jobject linearBlock =
                 env->NewObject(
                         env->FindClass("android/media/MediaCodec$LinearBlock"),
@@ -3646,6 +3649,7 @@
         ALOGD("Failed get MediaEvent");
         return NULL;
     }
+    android::Mutex::Autolock autoLock(mediaEventSp->mLock);
 
     return mediaEventSp->getLinearBlock();
 }
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index 0f930b5..742db34 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -61,8 +61,6 @@
     AMIDI_DEVICE_TYPE_BLUETOOTH = 3 /* A MIDI device connected via BlueTooth */
 };
 
-#if __ANDROID_API__ >= 29
-
 /*
  * Device API
  */
@@ -249,8 +247,6 @@
  */
 void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
-#endif /* __ANDROID_API__ >= 29 */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/core/java/android/net/CaptivePortal.java b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
similarity index 100%
rename from core/java/android/net/CaptivePortal.java
rename to packages/Connectivity/framework/src/android/net/CaptivePortal.java
diff --git a/core/java/android/net/CaptivePortalData.aidl b/packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl
similarity index 100%
rename from core/java/android/net/CaptivePortalData.aidl
rename to packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl
diff --git a/core/java/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
similarity index 100%
rename from core/java/android/net/CaptivePortalData.java
rename to packages/Connectivity/framework/src/android/net/CaptivePortalData.java
diff --git a/core/java/android/net/ConnectionInfo.aidl b/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl
similarity index 100%
rename from core/java/android/net/ConnectionInfo.aidl
rename to packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl
diff --git a/core/java/android/net/ConnectionInfo.java b/packages/Connectivity/framework/src/android/net/ConnectionInfo.java
similarity index 100%
rename from core/java/android/net/ConnectionInfo.java
rename to packages/Connectivity/framework/src/android/net/ConnectionInfo.java
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.aidl b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl
similarity index 100%
rename from core/java/android/net/ConnectivityDiagnosticsManager.aidl
rename to packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
similarity index 100%
rename from core/java/android/net/ConnectivityDiagnosticsManager.java
rename to packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
new file mode 100644
index 0000000..9afa5d1
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * Class for performing registration for all core connectivity services.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class ConnectivityFrameworkInitializer {
+    private ConnectivityFrameworkInitializer() {}
+
+    /**
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers all core
+     * connectivity services to {@link Context}, so that {@link Context#getSystemService} can
+     * return them.
+     *
+     * @throws IllegalStateException if this is called anywhere besides
+     * {@link SystemServiceRegistry}.
+     */
+    public static void registerServiceWrappers() {
+        // registerContextAwareService will throw if this is called outside of SystemServiceRegistry
+        // initialization.
+        SystemServiceRegistry.registerContextAwareService(
+                Context.CONNECTIVITY_SERVICE,
+                ConnectivityManager.class,
+                (context, serviceBinder) -> {
+                    IConnectivityManager icm = IConnectivityManager.Stub.asInterface(serviceBinder);
+                    return new ConnectivityManager(context, icm);
+                }
+        );
+
+        // 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,
+                (context) -> {
+                    final ConnectivityManager cm = context.getSystemService(
+                            ConnectivityManager.class);
+                    return cm.createDiagnosticsManager();
+                }
+        );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.TEST_NETWORK_SERVICE,
+                TestNetworkManager.class,
+                context -> {
+                    final ConnectivityManager cm = context.getSystemService(
+                            ConnectivityManager.class);
+                    return cm.startOrGetTestNetworkManager();
+                }
+        );
+    }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
similarity index 96%
rename from core/java/android/net/ConnectivityManager.java
rename to packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index d107261..987dcc4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -15,7 +15,9 @@
  */
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
@@ -28,6 +30,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.PendingIntent;
@@ -4820,6 +4823,28 @@
         }
     }
 
+    /** @hide */
+    public TestNetworkManager startOrGetTestNetworkManager() {
+        final IBinder tnBinder;
+        try {
+            tnBinder = mService.startOrGetTestNetworkService();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
+    }
+
+    /** @hide */
+    public VpnManager createVpnManager() {
+        return new VpnManager(mContext, mService);
+    }
+
+    /** @hide */
+    public ConnectivityDiagnosticsManager createDiagnosticsManager() {
+        return new ConnectivityDiagnosticsManager(mContext, mService);
+    }
+
     /**
      * Simulates a Data Stall for the specified Network.
      *
@@ -4964,4 +4989,92 @@
         }
         return null;
     }
+
+    /**
+     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+     * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
+     * be used to request that the system provide a network without causing the network to be
+     * in the foreground.
+     *
+     * <p>This method will attempt to find the best network that matches the passed
+     * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
+     * criteria. The platform will evaluate which network is the best at its own discretion.
+     * Throughput, latency, cost per byte, policy, user preference and other considerations
+     * may be factored in the decision of what is considered the best network.
+     *
+     * <p>As long as this request is outstanding, the platform will try to maintain the best network
+     * matching this request, while always attempting to match the request to a better network if
+     * possible. If a better match is found, the platform will switch this request to the now-best
+     * network and inform the app of the newly best network by invoking
+     * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
+     * will not try to maintain any other network than the best one currently matching the request:
+     * a network not matching any network request may be disconnected at any time.
+     *
+     * <p>For example, an application could use this method to obtain a connected cellular network
+     * even if the device currently has a data connection over Ethernet. This may cause the cellular
+     * radio to consume additional power. Or, an application could inform the system that it wants
+     * a network supporting sending MMSes and have the system let it know about the currently best
+     * MMS-supporting network through the provided {@link NetworkCallback}.
+     *
+     * <p>The status of the request can be followed by listening to the various callbacks described
+     * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
+     * used to direct traffic to the network (although accessing some networks may be subject to
+     * holding specific permissions). Callers will learn about the specific characteristics of the
+     * network through
+     * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
+     * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
+     * provided {@link NetworkCallback} will only be invoked due to changes in the best network
+     * matching the request at any given time; therefore when a better network matching the request
+     * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
+     * with the new network after which no further updates are given about the previously-best
+     * network, unless it becomes the best again at some later time. All callbacks are invoked
+     * in order on the same thread, which by default is a thread created by the framework running
+     * in the app.
+     *
+     * <p>This{@link NetworkRequest} will live until released via
+     * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
+     * which point the system may let go of the network at any time.
+     *
+     * <p>It is presently unsupported to request a network with mutable
+     * {@link NetworkCapabilities} such as
+     * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+     * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+     * as these {@code NetworkCapabilities} represent states that a particular
+     * network may never attain, and whether a network will attain these states
+     * is unknown prior to bringing up the network so the framework does not
+     * know how to go about satisfying a request with these capabilities.
+     *
+     * <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 #registerNetworkCallback} 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 request {@link NetworkRequest} describing this request.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     *                If null, the callback is invoked on the default internal Handler.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if the app already has too many callbacks registered.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @SuppressLint("ExecutorRegistration")
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
+    public void requestBackgroundNetwork(@NonNull NetworkRequest request,
+            @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+        final NetworkCapabilities nc = request.networkCapabilities;
+        sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
+                TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
+    }
 }
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl
similarity index 100%
rename from core/java/android/net/ConnectivityMetricsEvent.aidl
rename to packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl
diff --git a/core/java/android/net/ConnectivityThread.java b/packages/Connectivity/framework/src/android/net/ConnectivityThread.java
similarity index 100%
rename from core/java/android/net/ConnectivityThread.java
rename to packages/Connectivity/framework/src/android/net/ConnectivityThread.java
diff --git a/core/java/android/net/DhcpInfo.aidl b/packages/Connectivity/framework/src/android/net/DhcpInfo.aidl
similarity index 100%
rename from core/java/android/net/DhcpInfo.aidl
rename to packages/Connectivity/framework/src/android/net/DhcpInfo.aidl
diff --git a/core/java/android/net/DhcpInfo.java b/packages/Connectivity/framework/src/android/net/DhcpInfo.java
similarity index 100%
rename from core/java/android/net/DhcpInfo.java
rename to packages/Connectivity/framework/src/android/net/DhcpInfo.java
diff --git a/core/java/android/net/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java
similarity index 100%
rename from core/java/android/net/DnsResolver.java
rename to packages/Connectivity/framework/src/android/net/DnsResolver.java
diff --git a/core/java/android/net/ICaptivePortal.aidl b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
similarity index 100%
rename from core/java/android/net/ICaptivePortal.aidl
rename to packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
diff --git a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
similarity index 100%
rename from core/java/android/net/IConnectivityDiagnosticsCallback.aidl
rename to packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
diff --git a/core/java/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
similarity index 99%
rename from core/java/android/net/IConnectivityManager.aidl
rename to packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 7197831..1b4d2e4 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -31,7 +31,6 @@
 import android.net.NetworkState;
 import android.net.ProxyInfo;
 import android.net.UidRange;
-import android.net.VpnInfo;
 import android.net.QosSocketInfo;
 import android.os.Bundle;
 import android.os.IBinder;
diff --git a/core/java/android/net/ISocketKeepaliveCallback.aidl b/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl
similarity index 100%
rename from core/java/android/net/ISocketKeepaliveCallback.aidl
rename to packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl
diff --git a/core/java/android/net/ITestNetworkManager.aidl b/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl
similarity index 100%
rename from core/java/android/net/ITestNetworkManager.aidl
rename to packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl
diff --git a/core/java/android/net/InetAddresses.java b/packages/Connectivity/framework/src/android/net/InetAddresses.java
similarity index 100%
rename from core/java/android/net/InetAddresses.java
rename to packages/Connectivity/framework/src/android/net/InetAddresses.java
diff --git a/core/java/android/net/InterfaceConfiguration.aidl b/packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl
similarity index 100%
rename from core/java/android/net/InterfaceConfiguration.aidl
rename to packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl
diff --git a/core/java/android/net/InvalidPacketException.java b/packages/Connectivity/framework/src/android/net/InvalidPacketException.java
similarity index 100%
rename from core/java/android/net/InvalidPacketException.java
rename to packages/Connectivity/framework/src/android/net/InvalidPacketException.java
diff --git a/core/java/android/net/IpConfiguration.aidl b/packages/Connectivity/framework/src/android/net/IpConfiguration.aidl
similarity index 100%
rename from core/java/android/net/IpConfiguration.aidl
rename to packages/Connectivity/framework/src/android/net/IpConfiguration.aidl
diff --git a/core/java/android/net/IpConfiguration.java b/packages/Connectivity/framework/src/android/net/IpConfiguration.java
similarity index 100%
rename from core/java/android/net/IpConfiguration.java
rename to packages/Connectivity/framework/src/android/net/IpConfiguration.java
diff --git a/core/java/android/net/IpPrefix.aidl b/packages/Connectivity/framework/src/android/net/IpPrefix.aidl
similarity index 100%
rename from core/java/android/net/IpPrefix.aidl
rename to packages/Connectivity/framework/src/android/net/IpPrefix.aidl
diff --git a/core/java/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java
similarity index 100%
rename from core/java/android/net/IpPrefix.java
rename to packages/Connectivity/framework/src/android/net/IpPrefix.java
diff --git a/core/java/android/net/KeepalivePacketData.aidl b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl
similarity index 100%
rename from core/java/android/net/KeepalivePacketData.aidl
rename to packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl
diff --git a/core/java/android/net/KeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/KeepalivePacketData.java
rename to packages/Connectivity/framework/src/android/net/KeepalivePacketData.java
diff --git a/core/java/android/net/LinkAddress.aidl b/packages/Connectivity/framework/src/android/net/LinkAddress.aidl
similarity index 100%
rename from core/java/android/net/LinkAddress.aidl
rename to packages/Connectivity/framework/src/android/net/LinkAddress.aidl
diff --git a/core/java/android/net/LinkAddress.java b/packages/Connectivity/framework/src/android/net/LinkAddress.java
similarity index 100%
rename from core/java/android/net/LinkAddress.java
rename to packages/Connectivity/framework/src/android/net/LinkAddress.java
diff --git a/core/java/android/net/LinkProperties.aidl b/packages/Connectivity/framework/src/android/net/LinkProperties.aidl
similarity index 100%
rename from core/java/android/net/LinkProperties.aidl
rename to packages/Connectivity/framework/src/android/net/LinkProperties.aidl
diff --git a/core/java/android/net/LinkProperties.java b/packages/Connectivity/framework/src/android/net/LinkProperties.java
similarity index 100%
rename from core/java/android/net/LinkProperties.java
rename to packages/Connectivity/framework/src/android/net/LinkProperties.java
diff --git a/core/java/android/net/MacAddress.aidl b/packages/Connectivity/framework/src/android/net/MacAddress.aidl
similarity index 100%
rename from core/java/android/net/MacAddress.aidl
rename to packages/Connectivity/framework/src/android/net/MacAddress.aidl
diff --git a/core/java/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java
similarity index 100%
rename from core/java/android/net/MacAddress.java
rename to packages/Connectivity/framework/src/android/net/MacAddress.java
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/NattKeepalivePacketData.java
rename to packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java
diff --git a/core/java/android/net/NattSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java
similarity index 100%
rename from core/java/android/net/NattSocketKeepalive.java
rename to packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java
diff --git a/core/java/android/net/Network.aidl b/packages/Connectivity/framework/src/android/net/Network.aidl
similarity index 100%
rename from core/java/android/net/Network.aidl
rename to packages/Connectivity/framework/src/android/net/Network.aidl
diff --git a/core/java/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
similarity index 94%
rename from core/java/android/net/Network.java
rename to packages/Connectivity/framework/src/android/net/Network.java
index fbca7f1..b07bd68 100644
--- a/core/java/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -21,6 +21,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -380,7 +381,13 @@
         // Query a property of the underlying socket to ensure that the socket's file descriptor
         // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        bindSocket(socket.getFileDescriptor$());
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
+        bindSocket(pfd.getFileDescriptor());
+        // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+        // dup share the underlying socket in the kernel. The socket is never truly closed until the
+        // last fd pointing to the socket being closed. So close the dup one after binding the
+        // socket to control the lifetime of the dup fd.
+        pfd.close();
     }
 
     /**
@@ -392,7 +399,13 @@
         // Query a property of the underlying socket to ensure that the socket's file descriptor
         // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        bindSocket(socket.getFileDescriptor$());
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
+        bindSocket(pfd.getFileDescriptor());
+        // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+        // dup share the underlying socket in the kernel. The socket is never truly closed until the
+        // last fd pointing to the socket being closed. So close the dup one after binding the
+        // socket to control the lifetime of the dup fd.
+        pfd.close();
     }
 
     /**
diff --git a/core/java/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
similarity index 100%
rename from core/java/android/net/NetworkAgent.java
rename to packages/Connectivity/framework/src/android/net/NetworkAgent.java
diff --git a/core/java/android/net/NetworkAgentConfig.aidl b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl
similarity index 100%
rename from core/java/android/net/NetworkAgentConfig.aidl
rename to packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl
diff --git a/core/java/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
similarity index 98%
rename from core/java/android/net/NetworkAgentConfig.java
rename to packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index fe1268d..664c265 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -125,6 +127,7 @@
      * @return the subscriber ID, or null if none.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     @Nullable
     public String getSubscriberId() {
         return subscriberId;
@@ -275,6 +278,7 @@
          * @hide
          */
         @NonNull
+        @SystemApi(client = MODULE_LIBRARIES)
         public Builder setSubscriberId(@Nullable String subscriberId) {
             mConfig.subscriberId = subscriberId;
             return this;
diff --git a/core/java/android/net/NetworkCapabilities.aidl b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl
similarity index 100%
rename from core/java/android/net/NetworkCapabilities.aidl
rename to packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl
diff --git a/core/java/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
similarity index 97%
rename from core/java/android/net/NetworkCapabilities.java
rename to packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 0a895b9..8bfa77a 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -34,9 +34,9 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.CollectionUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -204,6 +204,7 @@
             NET_CAPABILITY_TEMPORARILY_NOT_METERED,
             NET_CAPABILITY_OEM_PRIVATE,
             NET_CAPABILITY_VEHICLE_INTERNAL,
+            NET_CAPABILITY_NOT_VCN_MANAGED,
     })
     public @interface NetCapability { }
 
@@ -399,8 +400,23 @@
     @SystemApi
     public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27;
 
+    /**
+     * Indicates that this network is not subsumed by a Virtual Carrier Network (VCN).
+     * <p>
+     * To provide an experience on a VCN similar to a single traditional carrier network, in
+     * some cases the system sets this bit is set by default in application's network requests,
+     * and may choose to remove it at its own discretion when matching the request to a network.
+     * <p>
+     * Applications that want to know about a Virtual Carrier Network's underlying networks,
+     * for example to use them for multipath purposes, should remove this bit from their network
+     * requests ; the system will not add it back once removed.
+     * @hide
+     */
+    @SystemApi
+    public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
+
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VEHICLE_INTERNAL;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED;
 
     /**
      * Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -417,7 +433,8 @@
             | (1 << NET_CAPABILITY_NOT_CONGESTED)
             | (1 << NET_CAPABILITY_NOT_SUSPENDED)
             | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
-            | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+            | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -426,16 +443,21 @@
      * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
      * get immediately torn down because they do not have the requested capability.
      */
+    // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities
+    // are mutable but requestable. Factories are responsible for not getting
+    // in an infinite loop about these.
     private static final long NON_REQUESTABLE_CAPABILITIES =
-            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
+            MUTABLE_CAPABILITIES
+            & ~(1 << NET_CAPABILITY_TRUSTED)
+            & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Capabilities that are set by default when the object is constructed.
      */
     private static final long DEFAULT_CAPABILITIES =
-            (1 << NET_CAPABILITY_NOT_RESTRICTED) |
-            (1 << NET_CAPABILITY_TRUSTED) |
-            (1 << NET_CAPABILITY_NOT_VPN);
+            (1 << NET_CAPABILITY_NOT_RESTRICTED)
+            | (1 << NET_CAPABILITY_TRUSTED)
+            | (1 << NET_CAPABILITY_NOT_VPN);
 
     /**
      * Capabilities that suggest that a network is restricted.
@@ -495,7 +517,8 @@
             | (1 << NET_CAPABILITY_NOT_VPN)
             | (1 << NET_CAPABILITY_NOT_ROAMING)
             | (1 << NET_CAPABILITY_NOT_CONGESTED)
-            | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+            | (1 << NET_CAPABILITY_NOT_SUSPENDED)
+            | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
 
     /**
      * Adds the given capability to this {@code NetworkCapability} instance.
@@ -751,7 +774,7 @@
         if (originalOwnerUid == creatorUid) {
             setOwnerUid(creatorUid);
         }
-        if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
+        if (CollectionUtils.contains(originalAdministratorUids, creatorUid)) {
             setAdministratorUids(new int[] {creatorUid});
         }
         // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
@@ -1857,7 +1880,7 @@
             sb.append(" OwnerUid: ").append(mOwnerUid);
         }
 
-        if (!ArrayUtils.isEmpty(mAdministratorUids)) {
+        if (mAdministratorUids != null && mAdministratorUids.length != 0) {
             sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids));
         }
 
@@ -1982,6 +2005,7 @@
             case NET_CAPABILITY_TEMPORARILY_NOT_METERED:    return "TEMPORARILY_NOT_METERED";
             case NET_CAPABILITY_OEM_PRIVATE:          return "OEM_PRIVATE";
             case NET_CAPABILITY_VEHICLE_INTERNAL:     return "NET_CAPABILITY_VEHICLE_INTERNAL";
+            case NET_CAPABILITY_NOT_VCN_MANAGED:      return "NOT_VCN_MANAGED";
             default:                                  return Integer.toString(capability);
         }
     }
@@ -2489,7 +2513,7 @@
         @NonNull
         public NetworkCapabilities build() {
             if (mCaps.getOwnerUid() != Process.INVALID_UID) {
-                if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
+                if (!CollectionUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
                     throw new IllegalStateException("The owner UID must be included in "
                             + " administrator UIDs.");
                 }
diff --git a/core/java/android/net/NetworkConfig.java b/packages/Connectivity/framework/src/android/net/NetworkConfig.java
similarity index 100%
rename from core/java/android/net/NetworkConfig.java
rename to packages/Connectivity/framework/src/android/net/NetworkConfig.java
diff --git a/core/java/android/net/NetworkInfo.aidl b/packages/Connectivity/framework/src/android/net/NetworkInfo.aidl
similarity index 100%
rename from core/java/android/net/NetworkInfo.aidl
rename to packages/Connectivity/framework/src/android/net/NetworkInfo.aidl
diff --git a/core/java/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
similarity index 100%
rename from core/java/android/net/NetworkInfo.java
rename to packages/Connectivity/framework/src/android/net/NetworkInfo.java
diff --git a/core/java/android/net/NetworkProvider.java b/packages/Connectivity/framework/src/android/net/NetworkProvider.java
similarity index 100%
rename from core/java/android/net/NetworkProvider.java
rename to packages/Connectivity/framework/src/android/net/NetworkProvider.java
diff --git a/core/java/android/net/NetworkRequest.aidl b/packages/Connectivity/framework/src/android/net/NetworkRequest.aidl
similarity index 100%
rename from core/java/android/net/NetworkRequest.aidl
rename to packages/Connectivity/framework/src/android/net/NetworkRequest.aidl
diff --git a/core/java/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
similarity index 100%
rename from core/java/android/net/NetworkRequest.java
rename to packages/Connectivity/framework/src/android/net/NetworkRequest.java
diff --git a/core/java/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
similarity index 100%
rename from core/java/android/net/NetworkUtils.java
rename to packages/Connectivity/framework/src/android/net/NetworkUtils.java
diff --git a/core/java/android/net/PacProxySelector.java b/packages/Connectivity/framework/src/android/net/PacProxySelector.java
similarity index 100%
rename from core/java/android/net/PacProxySelector.java
rename to packages/Connectivity/framework/src/android/net/PacProxySelector.java
diff --git a/core/java/android/net/Proxy.java b/packages/Connectivity/framework/src/android/net/Proxy.java
similarity index 100%
rename from core/java/android/net/Proxy.java
rename to packages/Connectivity/framework/src/android/net/Proxy.java
diff --git a/core/java/android/net/ProxyInfo.aidl b/packages/Connectivity/framework/src/android/net/ProxyInfo.aidl
similarity index 100%
rename from core/java/android/net/ProxyInfo.aidl
rename to packages/Connectivity/framework/src/android/net/ProxyInfo.aidl
diff --git a/core/java/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
similarity index 100%
rename from core/java/android/net/ProxyInfo.java
rename to packages/Connectivity/framework/src/android/net/ProxyInfo.java
diff --git a/core/java/android/net/RouteInfo.aidl b/packages/Connectivity/framework/src/android/net/RouteInfo.aidl
similarity index 100%
rename from core/java/android/net/RouteInfo.aidl
rename to packages/Connectivity/framework/src/android/net/RouteInfo.aidl
diff --git a/core/java/android/net/RouteInfo.java b/packages/Connectivity/framework/src/android/net/RouteInfo.java
similarity index 100%
rename from core/java/android/net/RouteInfo.java
rename to packages/Connectivity/framework/src/android/net/RouteInfo.java
diff --git a/core/java/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
similarity index 100%
rename from core/java/android/net/SocketKeepalive.java
rename to packages/Connectivity/framework/src/android/net/SocketKeepalive.java
diff --git a/core/java/android/net/StaticIpConfiguration.aidl b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl
similarity index 100%
rename from core/java/android/net/StaticIpConfiguration.aidl
rename to packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl
diff --git a/core/java/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
similarity index 100%
rename from core/java/android/net/StaticIpConfiguration.java
rename to packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java
similarity index 100%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java
diff --git a/core/java/android/net/TcpRepairWindow.java b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
similarity index 100%
rename from core/java/android/net/TcpRepairWindow.java
rename to packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java
similarity index 100%
rename from core/java/android/net/TcpSocketKeepalive.java
rename to packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java
diff --git a/core/java/android/net/TestNetworkInterface.aidl b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl
similarity index 100%
rename from core/java/android/net/TestNetworkInterface.aidl
rename to packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl
diff --git a/core/java/android/net/TestNetworkInterface.java b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java
similarity index 100%
rename from core/java/android/net/TestNetworkInterface.java
rename to packages/Connectivity/framework/src/android/net/TestNetworkInterface.java
diff --git a/core/java/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
similarity index 100%
rename from core/java/android/net/TestNetworkManager.java
rename to packages/Connectivity/framework/src/android/net/TestNetworkManager.java
diff --git a/core/java/android/net/TransportInfo.java b/packages/Connectivity/framework/src/android/net/TransportInfo.java
similarity index 100%
rename from core/java/android/net/TransportInfo.java
rename to packages/Connectivity/framework/src/android/net/TransportInfo.java
diff --git a/core/java/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl
similarity index 100%
rename from core/java/android/net/UidRange.aidl
rename to packages/Connectivity/framework/src/android/net/UidRange.aidl
diff --git a/core/java/android/net/VpnManager.java b/packages/Connectivity/framework/src/android/net/VpnManager.java
similarity index 100%
rename from core/java/android/net/VpnManager.java
rename to packages/Connectivity/framework/src/android/net/VpnManager.java
diff --git a/core/java/android/net/VpnService.java b/packages/Connectivity/framework/src/android/net/VpnService.java
similarity index 100%
rename from core/java/android/net/VpnService.java
rename to packages/Connectivity/framework/src/android/net/VpnService.java
diff --git a/core/java/android/net/apf/ApfCapabilities.aidl b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl
similarity index 100%
rename from core/java/android/net/apf/ApfCapabilities.aidl
rename to packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
similarity index 100%
rename from core/java/android/net/apf/ApfCapabilities.java
rename to packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
diff --git a/core/java/android/net/util/DnsUtils.java b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
similarity index 100%
rename from core/java/android/net/util/DnsUtils.java
rename to packages/Connectivity/framework/src/android/net/util/DnsUtils.java
diff --git a/core/java/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
similarity index 100%
rename from core/java/android/net/util/KeepaliveUtils.java
rename to packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
similarity index 100%
rename from core/java/android/net/util/MultinetworkPolicyTracker.java
rename to packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
diff --git a/core/java/android/net/util/SocketUtils.java b/packages/Connectivity/framework/src/android/net/util/SocketUtils.java
similarity index 100%
rename from core/java/android/net/util/SocketUtils.java
rename to packages/Connectivity/framework/src/android/net/util/SocketUtils.java
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index c8f3bd3..8fc3181 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -57,6 +57,7 @@
     static_libs: [
         "net-utils-device-common",
         "net-utils-framework-common",
+        "netd-client",
     ],
     apex_available: [
         "//apex_available:platform",
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 266bfe0..6568bff 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -846,8 +846,8 @@
             try {
                 stmt = db.compileStatement("INSERT INTO system(name,value)"
                         + " VALUES(?,?);");
-                loadBooleanSetting(stmt, Settings.System.USER_ROTATION,
-                        R.integer.def_user_rotation); // should be zero degrees
+                loadIntegerSetting(stmt, Settings.System.USER_ROTATION,
+                        R.integer.def_user_rotation);
                 db.setTransactionSuccessful();
             } finally {
                 db.endTransaction();
@@ -2265,6 +2265,8 @@
             loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
                     R.bool.def_accelerometer_rotation);
 
+            loadIntegerSetting(stmt, Settings.System.USER_ROTATION, R.integer.def_user_rotation);
+
             loadDefaultHapticSettings(stmt);
 
             loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index dcbad30..135356c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -296,9 +296,6 @@
     <uses-permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM" />
 
     <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
-    <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" />
-
-    <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
     <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
 
     <!-- Permission needed to use wifi usability API's for CtsNetTestCases -->
@@ -352,6 +349,13 @@
     <!-- Permission required for CTS test - CtsSensorPrivacyTestCases -->
     <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
 
+    <!-- Permission required for GTS test - GtsAssistIntentTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+    <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
+    <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" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/services/Android.bp b/services/Android.bp
index 785ca35..a13dbe6 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -139,7 +139,7 @@
         last_released: {
             api_file: ":android.api.system-server.latest",
             removed_api_file: ":removed.api.system-server.latest",
-            baseline_file: ":system-server-api-incompatibilities-with-last-released"
+            baseline_file: ":android-incompatibilities.api.system-server.latest"
         },
         api_lint: {
             enabled: true,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 410ec1d..f2e1920 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -132,8 +132,8 @@
 import android.net.TetheringManager;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
-import android.net.VpnInfo;
 import android.net.VpnManager;
 import android.net.VpnService;
 import android.net.metrics.INetdEventListener;
@@ -216,8 +216,6 @@
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.utils.PriorityDump;
 
-import com.google.android.collect.Lists;
-
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
@@ -741,11 +739,11 @@
         }
 
         private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
-                boolean isDefaultNetwork) {
+                boolean isFallbackNetwork) {
             if (DBG) {
                 log("Sending " + state
                         + " broadcast for type " + type + " " + nai.toShortString()
-                        + " isDefaultNetwork=" + isDefaultNetwork);
+                        + " isFallbackNetwork=" + isFallbackNetwork);
             }
         }
 
@@ -764,10 +762,10 @@
                 list.add(nai);
             }
 
-            // 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 ((list.size() == 1) || isDefaultNetwork) {
-                maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
+            // 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);
             }
         }
@@ -796,7 +794,7 @@
                               ", sending connected broadcast");
                 final NetworkAgentInfo replacement = list.get(0);
                 maybeLogBroadcast(replacement, DetailedState.CONNECTED, type,
-                        mService.isDefaultNetwork(replacement));
+                        mService.isFallbackNetwork(replacement));
                 mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type);
             }
         }
@@ -812,14 +810,14 @@
         // send out another legacy broadcast - currently only used for suspend/unsuspend
         // toggle
         public void update(NetworkAgentInfo nai) {
-            final boolean isDefault = mService.isDefaultNetwork(nai);
+            final boolean isFallback = mService.isFallbackNetwork(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 && isDefault) {
-                    maybeLogBroadcast(nai, state, type, isDefault);
+                if (isFirst || contains && isFallback) {
+                    maybeLogBroadcast(nai, state, type, isFallback);
                     mService.sendLegacyNetworkBroadcast(nai, state, type);
                 }
             }
@@ -1023,11 +1021,13 @@
         mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
 
         mMetricsLog = logger;
-        mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
         mNetworkRanker = new NetworkRanker();
-        NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
-        mNetworkRequests.put(mDefaultRequest, defaultNRI);
-        mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
+        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);
 
         mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
@@ -1329,31 +1329,6 @@
         return mNextNetworkRequestId++;
     }
 
-    private NetworkState getFilteredNetworkState(int networkType, int uid) {
-        if (mLegacyTypeTracker.isTypeSupported(networkType)) {
-            final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
-            final NetworkState state;
-            if (nai != null) {
-                state = nai.getNetworkState();
-                state.networkInfo.setType(networkType);
-            } else {
-                final NetworkInfo info = new NetworkInfo(networkType, 0,
-                        getNetworkTypeName(networkType), "");
-                info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
-                info.setIsAvailable(true);
-                final NetworkCapabilities capabilities = new NetworkCapabilities();
-                capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
-                        !info.isRoaming());
-                state = new NetworkState(info, new LinkProperties(), capabilities,
-                        null, null, null);
-            }
-            filterNetworkStateForUid(state, uid, false);
-            return state;
-        } else {
-            return NetworkState.EMPTY;
-        }
-    }
-
     @VisibleForTesting
     protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
         if (network == null) {
@@ -1391,7 +1366,7 @@
     }
 
     private NetworkState getUnfilteredActiveNetworkState(int uid) {
-        NetworkAgentInfo nai = getDefaultNetwork();
+        NetworkAgentInfo nai = getFallbackNetwork();
 
         final Network[] networks = getVpnUnderlyingNetworks(uid);
         if (networks != null) {
@@ -1464,6 +1439,18 @@
                 "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
     }
 
+    private void filterNetworkInfo(@NonNull NetworkInfo networkInfo,
+            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
+        if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
+            networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
+        }
+        synchronized (mVpns) {
+            if (mLockdownTracker != null) {
+                mLockdownTracker.augmentNetworkInfo(networkInfo);
+            }
+        }
+    }
+
     /**
      * Apply any relevant filters to {@link NetworkState} for the given UID. For
      * example, this may mark the network as {@link DetailedState#BLOCKED} based
@@ -1471,16 +1458,7 @@
      */
     private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
         if (state == null || state.networkInfo == null || state.linkProperties == null) return;
-
-        if (isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid,
-                ignoreBlocked)) {
-            state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
-        }
-        synchronized (mVpns) {
-            if (mLockdownTracker != null) {
-                mLockdownTracker.augmentNetworkInfo(state.networkInfo);
-            }
-        }
+        filterNetworkInfo(state.networkInfo, state.networkCapabilities, uid, ignoreBlocked);
     }
 
     /**
@@ -1521,7 +1499,7 @@
             }
         }
 
-        NetworkAgentInfo nai = getDefaultNetwork();
+        NetworkAgentInfo nai = getFallbackNetwork();
         if (nai == null || isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid,
                 ignoreBlocked)) {
             return null;
@@ -1545,6 +1523,27 @@
         return state.networkInfo;
     }
 
+    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+        if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
+            return null;
+        }
+        final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        final NetworkInfo info;
+        final NetworkCapabilities nc;
+        if (nai != null) {
+            info = new NetworkInfo(nai.networkInfo);
+            info.setType(networkType);
+            nc = nai.networkCapabilities;
+        } else {
+            info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), "");
+            info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+            info.setIsAvailable(true);
+            nc = new NetworkCapabilities();
+        }
+        filterNetworkInfo(info, nc, uid, false);
+        return info;
+    }
+
     @Override
     public NetworkInfo getNetworkInfo(int networkType) {
         enforceAccessPermission();
@@ -1559,8 +1558,7 @@
                 return state.networkInfo;
             }
         }
-        final NetworkState state = getFilteredNetworkState(networkType, uid);
-        return state.networkInfo;
+        return getFilteredNetworkInfo(networkType, uid);
     }
 
     @Override
@@ -1579,7 +1577,7 @@
     @Override
     public NetworkInfo[] getAllNetworkInfo() {
         enforceAccessPermission();
-        final ArrayList<NetworkInfo> result = Lists.newArrayList();
+        final ArrayList<NetworkInfo> result = new ArrayList<>();
         for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
                 networkType++) {
             NetworkInfo info = getNetworkInfo(networkType);
@@ -1593,10 +1591,16 @@
     @Override
     public Network getNetworkForType(int networkType) {
         enforceAccessPermission();
+        if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
+            return null;
+        }
+        final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        if (nai == null) {
+            return null;
+        }
         final int uid = mDeps.getCallingUid();
-        NetworkState state = getFilteredNetworkState(networkType, uid);
-        if (!isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, false)) {
-            return state.network;
+        if (!isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
+            return nai.network;
         }
         return null;
     }
@@ -1634,7 +1638,7 @@
 
         HashMap<Network, NetworkCapabilities> result = new HashMap<>();
 
-        NetworkAgentInfo nai = getDefaultNetwork();
+        final NetworkAgentInfo nai = getFallbackNetwork();
         NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
         if (nc != null) {
             result.put(
@@ -1847,7 +1851,7 @@
         // This contains IMSI details, so make sure the caller is privileged.
         NetworkStack.checkNetworkStackPermission(mContext);
 
-        final ArrayList<NetworkState> result = Lists.newArrayList();
+        final ArrayList<NetworkState> result = new ArrayList<>();
         for (Network network : getAllNetworks()) {
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
             if (nai != null) {
@@ -2021,7 +2025,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(mDefaultRequest)) {
+            if (nai != null && nai.satisfies(mFallbackRequest.mRequests.get(0))) {
                 nai.networkMonitor().notifyDnsResponse(returnCode);
             }
         }
@@ -2578,12 +2582,12 @@
         pw.println();
         pw.println();
 
-        final NetworkAgentInfo defaultNai = getDefaultNetwork();
+        final NetworkAgentInfo fallbackNai = getFallbackNetwork();
         pw.print("Active default network: ");
-        if (defaultNai == null) {
+        if (fallbackNai == null) {
             pw.println("none");
         } else {
-            pw.println(defaultNai.network.getNetId());
+            pw.println(fallbackNai.network.getNetId());
         }
         pw.println();
 
@@ -2966,7 +2970,7 @@
 
             final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
             final boolean wasValidated = nai.lastValidated;
-            final boolean wasDefault = isDefaultNetwork(nai);
+            final boolean wasFallback = isFallbackNetwork(nai);
 
             if (DBG) {
                 final String logMsg = !TextUtils.isEmpty(redirectUrl)
@@ -2975,7 +2979,7 @@
                 log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
             }
             if (valid != nai.lastValidated) {
-                if (wasDefault) {
+                if (wasFallback) {
                     mMetricsLog.logDefaultNetworkValidity(valid);
                 }
                 final int oldScore = nai.getCurrentScore();
@@ -3351,13 +3355,13 @@
             loge("Error connecting NetworkAgent");
             mNetworkAgentInfos.remove(nai);
             if (nai != null) {
-                final boolean wasDefault = isDefaultNetwork(nai);
+                final boolean wasFallback = isFallbackNetwork(nai);
                 synchronized (mNetworkForNetId) {
                     mNetworkForNetId.remove(nai.network.getNetId());
                 }
                 mNetIdManager.releaseNetId(nai.network.getNetId());
                 // Just in case.
-                mLegacyTypeTracker.remove(nai, wasDefault);
+                mLegacyTypeTracker.remove(nai, wasFallback);
             }
         }
     }
@@ -3396,8 +3400,8 @@
             nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
                     null, null);
         }
-        final boolean wasDefault = isDefaultNetwork(nai);
-        if (wasDefault) {
+        final boolean wasFallback = isFallbackNetwork(nai);
+        if (wasFallback) {
             mDefaultInetConditionPublished = 0;
             // Log default network disconnection before required book-keeping.
             // Let rematchAllNetworksAndRequests() below record a new default network event
@@ -3439,19 +3443,24 @@
                     && currentNetwork.network.getNetId() == nai.network.getNetId()) {
                 nri.setSatisfier(null, null);
                 sendUpdatedScoreToFactories(request, null);
+
+                if (mFallbackRequest == 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
+                    //  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();
-        // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given
-        // there's a full rematch right after. Currently, deleting it breaks tests that check for
-        // the default network disconnecting. Find out why, fix the rematch code, and delete this.
-        if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
-            mDefaultNetworkNai = null;
-            mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai);
-            notifyLockdownVpn(nai);
-            ensureNetworkTransitionWakelock(nai.toShortString());
-        }
-        mLegacyTypeTracker.remove(nai, wasDefault);
+        // 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.
+        //  Find out why, fix the rematch code, and delete this.
+        mLegacyTypeTracker.remove(nai, wasFallback);
         rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
         if (nai.created) {
@@ -4251,7 +4260,7 @@
 
     @Override
     public NetworkRequest getDefaultRequest() {
-        return mDefaultRequest;
+        return mFallbackRequest.mRequests.get(0);
     }
 
     private class InternalHandler extends Handler {
@@ -4497,7 +4506,7 @@
         // revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
         final NetworkAgentInfo nai;
         if (network == null) {
-            nai = getDefaultNetwork();
+            nai = getFallbackNetwork();
         } else {
             nai = getNetworkAgentInfoForNetwork(network);
         }
@@ -4516,7 +4525,7 @@
             Network network, int uid, boolean hasConnectivity) {
         final NetworkAgentInfo nai;
         if (network == null) {
-            nai = getDefaultNetwork();
+            nai = getFallbackNetwork();
         } else {
             nai = getNetworkAgentInfoForNetwork(network);
         }
@@ -4829,7 +4838,7 @@
         }
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
+            mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
         }
     }
 
@@ -4854,35 +4863,35 @@
      *
      * <p>Must be called on the handler thread.
      */
-    private VpnInfo[] getAllVpnInfo() {
+    private UnderlyingNetworkInfo[] getAllVpnInfo() {
         ensureRunningOnConnectivityServiceThread();
         synchronized (mVpns) {
             if (mLockdownEnabled) {
-                return new VpnInfo[0];
+                return new UnderlyingNetworkInfo[0];
             }
         }
-        List<VpnInfo> infoList = new ArrayList<>();
+        List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
-            VpnInfo info = createVpnInfo(nai);
+            UnderlyingNetworkInfo info = createVpnInfo(nai);
             if (info != null) {
                 infoList.add(info);
             }
         }
-        return infoList.toArray(new VpnInfo[infoList.size()]);
+        return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
     }
 
     /**
      * @return VPN information for accounting, or null if we can't retrieve all required
      *         information, e.g underlying ifaces.
      */
-    private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+    private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
         if (!nai.isVPN()) return null;
 
         Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
         // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
         // the underlyingNetworks list.
         if (underlyingNetworks == null) {
-            NetworkAgentInfo defaultNai = getDefaultNetwork();
+            final NetworkAgentInfo defaultNai = getFallbackNetwork();
             if (defaultNai != null) {
                 underlyingNetworks = new Network[] { defaultNai.network };
             }
@@ -4907,11 +4916,11 @@
         // Must be non-null or NetworkStatsService will crash.
         // Cannot happen in production code because Vpn only registers the NetworkAgent after the
         // tun or ipsec interface is created.
+        // TODO: Remove this check.
         if (nai.linkProperties.getInterfaceName() == null) return null;
 
-        return new VpnInfo(nai.networkCapabilities.getOwnerUid(),
-                nai.linkProperties.getInterfaceName(),
-                interfaces.toArray(new String[0]));
+        return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
+                nai.linkProperties.getInterfaceName(), interfaces);
     }
 
     /**
@@ -4934,7 +4943,7 @@
     }
 
     private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
-        final Network defaultNetwork = getNetwork(getDefaultNetwork());
+        final Network defaultNetwork = getNetwork(getFallbackNetwork());
         if (underlyingNetworks == null && defaultNetwork != null) {
             // null underlying networks means to track the default.
             underlyingNetworks = new Network[] { defaultNetwork };
@@ -5491,6 +5500,8 @@
      */
     @VisibleForTesting
     protected class NetworkRequestInfo implements IBinder.DeathRecipient {
+        // The requests to be satisfied in priority order. Non-multilayer requests will only have a
+        // single NetworkRequest in mRequests.
         final List<NetworkRequest> mRequests;
 
         // mSatisfier and mActiveRequest rely on one another therefore set them together.
@@ -5707,6 +5718,9 @@
                 networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
                 enforceAccessPermission();
                 break;
+            case BACKGROUND_REQUEST:
+                enforceNetworkStackOrSettingsPermission();
+                // Fall-through since other checks are the same with normal requests.
             case REQUEST:
                 networkCapabilities = new NetworkCapabilities(networkCapabilities);
                 enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
@@ -6033,11 +6047,13 @@
     @GuardedBy("mBlockedAppUids")
     private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
 
+    // The always-on request for an Internet-capable network that apps without a specific default
+    // fall back to.
     @NonNull
-    private final NetworkRequest mDefaultRequest;
-    // The NetworkAgentInfo currently satisfying the default request, if any.
-    @Nullable
-    private volatile NetworkAgentInfo mDefaultNetworkNai = null;
+    private final NetworkRequestInfo mFallbackRequest;
+    // Collection of NetworkRequestInfo's used for default networks.
+    @NonNull
+    private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
 
     // Request used to optionally keep mobile data active even when higher
     // priority networks like Wi-Fi are active.
@@ -6050,8 +6066,10 @@
     // Request used to optionally keep vehicle internal network always active
     private final NetworkRequest mDefaultVehicleRequest;
 
-    private NetworkAgentInfo getDefaultNetwork() {
-        return mDefaultNetworkNai;
+    // 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;
     }
 
     @Nullable
@@ -6068,8 +6086,8 @@
     }
 
     @VisibleForTesting
-    protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
-        return nai == getDefaultNetwork();
+    protected boolean isFallbackNetwork(NetworkAgentInfo nai) {
+        return nai == getFallbackNetwork();
     }
 
     // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
@@ -6138,8 +6156,8 @@
 
         LinkProperties lp = new LinkProperties(linkProperties);
 
-        // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
-        // satisfies mDefaultRequest.
+        // 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,
@@ -6196,7 +6214,7 @@
         nai.networkAgentPortalData = lp.getCaptivePortalData();
     }
 
-    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
+    private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkProperties newLp,
             @NonNull LinkProperties oldLp) {
         int netId = networkAgent.network.getNetId();
 
@@ -6205,8 +6223,7 @@
         // the LinkProperties for the network are accurate.
         networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
 
-        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
-                networkAgent.networkInfo.getType());
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
 
         // update filtering rules, need to happen after the interface update so netd knows about the
         // new interface (the interface name -> index map becomes initialized)
@@ -6217,7 +6234,7 @@
 //        for (LinkProperties lp : newLp.getStackedLinks()) {
 //            updateMtu(lp, null);
 //        }
-        if (isDefaultNetwork(networkAgent)) {
+        if (isFallbackNetwork(networkAgent)) {
             updateTcpBufferSizes(newLp.getTcpBufferSizes());
         }
 
@@ -6229,7 +6246,7 @@
         // updateDnses will fetch the private DNS configuration from DnsManager.
         mDnsManager.updatePrivateDnsStatus(netId, newLp);
 
-        if (isDefaultNetwork(networkAgent)) {
+        if (isFallbackNetwork(networkAgent)) {
             handleApplyDefaultProxy(newLp.getHttpProxy());
         } else {
             updateProxy(newLp, oldLp);
@@ -6345,7 +6362,7 @@
 
     private void updateInterfaces(final @Nullable LinkProperties newLp,
             final @Nullable LinkProperties oldLp, final int netId,
-            final @Nullable NetworkCapabilities caps, final int legacyType) {
+            final @NonNull NetworkCapabilities caps) {
         final CompareResult<String> interfaceDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
@@ -6356,7 +6373,7 @@
                     if (DBG) log("Adding iface " + iface + " to network " + netId);
                     mNetd.networkAddInterface(netId, iface);
                     wakeupModifyInterface(iface, caps, true);
-                    bs.noteNetworkInterfaceType(iface, legacyType);
+                    bs.noteNetworkInterfaceForTransports(iface, caps.getTransportTypes());
                 } catch (Exception e) {
                     loge("Exception adding interface: " + e);
                 }
@@ -6628,6 +6645,7 @@
      * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
      * and foreground status).
      */
+    @NonNull
     private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
         // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
          // Don't complain for VPNs since they're not driven by requests and there is no risk of
@@ -6684,6 +6702,25 @@
         return newNc;
     }
 
+    private void updateNetworkInfoForRoamingAndSuspended(NetworkAgentInfo nai,
+            NetworkCapabilities prevNc, NetworkCapabilities newNc) {
+        final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        if (prevSuspended != suspended) {
+            // TODO (b/73132094) : remove this call once the few users of onSuspended and
+            // onResumed have been removed.
+            notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
+                    : ConnectivityManager.CALLBACK_RESUMED);
+        }
+        if (prevSuspended != suspended || prevRoaming != roaming) {
+            // updateNetworkInfo will mix in the suspended info from the capabilities and
+            // take appropriate action for the network having possibly changed state.
+            updateNetworkInfo(nai, nai.networkInfo);
+        }
+    }
+
     /**
      * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically:
      *
@@ -6715,25 +6752,13 @@
             // on this network. We might have been called by rematchNetworkAndRequests when a
             // network changed foreground state.
             processListenRequests(nai);
-            final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
-            final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
-            final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-            final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-            if (prevSuspended != suspended || prevRoaming != roaming) {
-                // TODO (b/73132094) : remove this call once the few users of onSuspended and
-                // onResumed have been removed.
-                notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
-                        : ConnectivityManager.CALLBACK_RESUMED);
-                // updateNetworkInfo will mix in the suspended info from the capabilities and
-                // take appropriate action for the network having possibly changed state.
-                updateNetworkInfo(nai, nai.networkInfo);
-            }
         } else {
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests();
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
+        updateNetworkInfoForRoamingAndSuspended(nai, prevNc, newNc);
 
         final boolean oldMetered = prevNc.isMetered();
         final boolean newMetered = newNc.isMetered();
@@ -7172,14 +7197,41 @@
         }
     }
 
-    private void makeDefault(@Nullable final NetworkAgentInfo newNetwork) {
-        if (DBG) log("Switching to new default network: " + newNetwork);
+    private void processDefaultNetworkChanges(@NonNull final NetworkReassignment changes) {
+        boolean isDefaultChanged = false;
+        for (final NetworkRequestInfo defaultRequestInfo : mDefaultNetworkRequests) {
+            final NetworkReassignment.RequestReassignment reassignment =
+                    changes.getReassignment(defaultRequestInfo);
+            if (null == reassignment) {
+                continue;
+            }
+            // reassignment only contains those instances where the satisfying network changed.
+            isDefaultChanged = true;
+            // Notify system services of the new default.
+            makeDefault(defaultRequestInfo, reassignment.mOldNetwork, reassignment.mNewNetwork);
+        }
 
-        mDefaultNetworkNai = newNetwork;
+        if (isDefaultChanged) {
+            // Hold a wakelock for a short time to help apps in migrating to a new default.
+            scheduleReleaseNetworkTransitionWakelock();
+        }
+    }
+
+    private void makeDefault(@NonNull final NetworkRequestInfo nri,
+            @Nullable final NetworkAgentInfo oldDefaultNetwork,
+            @Nullable final NetworkAgentInfo newDefaultNetwork) {
+        if (DBG) {
+            log("Switching to new default network for: " + nri + " using " + newDefaultNetwork);
+        }
 
         try {
-            if (null != newNetwork) {
-                mNetd.networkSetDefault(newNetwork.network.getNetId());
+            // 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();
             }
@@ -7187,16 +7239,41 @@
             loge("Exception setting default network :" + e);
         }
 
-        notifyLockdownVpn(newNetwork);
-        handleApplyDefaultProxy(null != newNetwork
-                ? newNetwork.linkProperties.getHttpProxy() : null);
-        updateTcpBufferSizes(null != newNetwork
-                ? newNetwork.linkProperties.getTcpBufferSizes() : null);
+        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 (newNetwork != null) {
-            propagateUnderlyingNetworkCapabilities(newNetwork.network);
+        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;
+        final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
+        final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
+        final LinkProperties lp = (newDefaultNetwork != null)
+                ? newDefaultNetwork.linkProperties : null;
+        final NetworkCapabilities nc = (newDefaultNetwork != null)
+                ? newDefaultNetwork.networkCapabilities : null;
+
+        final Network prevNetwork = (oldDefaultNetwork != null)
+                ? oldDefaultNetwork.network : null;
+        final int prevScore = (oldDefaultNetwork != null)
+                ? oldDefaultNetwork.getCurrentScore() : 0;
+        final LinkProperties prevLp = (oldDefaultNetwork != null)
+                ? oldDefaultNetwork.linkProperties : null;
+        final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
+                ? oldDefaultNetwork.networkCapabilities : null;
+
+        mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
+                prevNetwork, prevScore, prevLp, prevNc);
     }
 
     private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -7448,46 +7525,8 @@
                     now);
         }
 
-        final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
-        final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
-        final NetworkReassignment.RequestReassignment reassignment =
-                changes.getReassignment(defaultRequestInfo);
-        final NetworkAgentInfo newDefaultNetwork =
-                null != reassignment ? reassignment.mNewNetwork : oldDefaultNetwork;
-
-        if (oldDefaultNetwork != newDefaultNetwork) {
-            if (oldDefaultNetwork != null) {
-                mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
-            }
-            mNetworkActivityTracker.updateDataActivityTracking(
-                    newDefaultNetwork, oldDefaultNetwork);
-            // Notify system services of the new default.
-            makeDefault(newDefaultNetwork);
-
-            // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-            final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
-            final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
-            final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
-            final LinkProperties lp = (newDefaultNetwork != null)
-                    ? newDefaultNetwork.linkProperties : null;
-            final NetworkCapabilities nc = (newDefaultNetwork != null)
-                    ? newDefaultNetwork.networkCapabilities : null;
-
-            final Network prevNetwork = (oldDefaultNetwork != null)
-                    ? oldDefaultNetwork.network : null;
-            final int prevScore = (oldDefaultNetwork != null)
-                    ? oldDefaultNetwork.getCurrentScore() : 0;
-            final LinkProperties prevLp = (oldDefaultNetwork != null)
-                    ? oldDefaultNetwork.linkProperties : null;
-            final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
-                    ? oldDefaultNetwork.networkCapabilities : null;
-
-            mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
-                    prevNetwork, prevScore, prevLp, prevNc);
-
-            // Have a new default network, release the transition wakelock in
-            scheduleReleaseNetworkTransitionWakelock();
-        }
+        // Process default network changes if applicable.
+        processDefaultNetworkChanges(changes);
 
         // Notify requested networks are available after the default net is switched, but
         // before LegacyTypeTracker sends legacy broadcasts
@@ -7540,7 +7579,7 @@
             notifyNetworkLosing(nai, now);
         }
 
-        updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+        updateLegacyTypeTrackerAndVpnLockdownForRematch(changes, nais);
 
         // Tear down all unneeded networks.
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
@@ -7583,29 +7622,36 @@
     }
 
     private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
-            @Nullable final NetworkAgentInfo oldDefaultNetwork,
-            @Nullable final NetworkAgentInfo newDefaultNetwork,
+            @NonNull final NetworkReassignment changes,
             @NonNull final Collection<NetworkAgentInfo> nais) {
-        if (oldDefaultNetwork != newDefaultNetwork) {
+        final NetworkReassignment.RequestReassignment fallbackReassignment =
+                changes.getReassignment(mFallbackRequest);
+        final NetworkAgentInfo oldFallbackNetwork =
+                null != fallbackReassignment ? fallbackReassignment.mOldNetwork : null;
+        final NetworkAgentInfo newFallbackNetwork =
+                null != fallbackReassignment ? fallbackReassignment.mNewNetwork : null;
+
+        if (oldFallbackNetwork != newFallbackNetwork) {
             // 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 (oldDefaultNetwork != null) {
-                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
-                        oldDefaultNetwork, true);
+            if (oldFallbackNetwork != null) {
+                mLegacyTypeTracker.remove(oldFallbackNetwork.networkInfo.getType(),
+                        oldFallbackNetwork, true);
             }
-            if (newDefaultNetwork != null) {
+            if (newFallbackNetwork != 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 = newDefaultNetwork.lastValidated ? 100 : 0;
-                mLegacyTypeTracker.add(newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
+                mDefaultInetConditionPublished = newFallbackNetwork.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(newDefaultNetwork);
+                notifyLockdownVpn(newFallbackNetwork);
             }
         }
 
@@ -7640,7 +7686,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., mDefaultRequest
+        // because usually there are no NetworkRequests it satisfies (e.g., mFallbackRequest
         // 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()) {
@@ -7651,9 +7697,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 default connection.
+        // For now only update icons for the fallback connection.
         // TODO: Update WiFi and cellular icons separately. b/17237507
-        if (!isDefaultNetwork(nai)) return;
+        if (!isFallbackNetwork(nai)) return;
 
         int newInetCondition = nai.lastValidated ? 100 : 0;
         // Don't repeat publish.
@@ -7921,8 +7967,8 @@
                 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
             }
             NetworkAgentInfo newDefaultAgent = null;
-            if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
-                newDefaultAgent = getDefaultNetwork();
+            if (nai.isSatisfyingRequest(mFallbackRequest.mRequests.get(0).requestId)) {
+                newDefaultAgent = getFallbackNetwork();
                 if (newDefaultAgent != null) {
                     intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
                             newDefaultAgent.networkInfo);
@@ -7969,10 +8015,10 @@
      */
     private Network[] getDefaultNetworks() {
         ensureRunningOnConnectivityServiceThread();
-        ArrayList<Network> defaultNetworks = new ArrayList<>();
-        NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+        final ArrayList<Network> defaultNetworks = new ArrayList<>();
+        final NetworkAgentInfo fallbackNetwork = getFallbackNetwork();
         for (NetworkAgentInfo nai : mNetworkAgentInfos) {
-            if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) {
+            if (nai.everConnected && (nai == fallbackNetwork || nai.isVPN())) {
                 defaultNetworks.add(nai.network);
             }
         }
@@ -7991,10 +8037,10 @@
             activeIface = activeLinkProperties.getInterfaceName();
         }
 
-        final VpnInfo[] vpnInfos = getAllVpnInfo();
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
-            mStatsService.forceUpdateIfaces(
-                    getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
+            mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
+                    underlyingNetworkInfos);
         } catch (Exception ignored) {
         }
     }
@@ -8022,7 +8068,6 @@
         int user = UserHandle.getUserId(mDeps.getCallingUid());
         final boolean success;
         synchronized (mVpns) {
-            throwIfLockdownEnabled();
             success = mVpns.get(user).setUnderlyingNetworks(networks);
         }
         return success;
@@ -8254,6 +8299,7 @@
         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);
@@ -8262,7 +8308,7 @@
         if (vpn == null) {
             return null;
         } else {
-            final VpnInfo info = vpn.getVpnInfo();
+            final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
             return (info == null || info.ownerUid != uid) ? null : vpn;
         }
     }
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e8687e5..e96fd39 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -32,6 +32,7 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
+import android.net.NetworkStack;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.TestNetworkInterface;
@@ -48,6 +49,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.NetdUtils;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -242,6 +244,7 @@
         nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
         nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
         nc.setAdministratorUids(administratorUids);
         if (!isMetered) {
@@ -316,10 +319,10 @@
         }
 
         try {
-            // This requires NETWORK_STACK privileges.
             final long token = Binder.clearCallingIdentity();
             try {
-                mNMS.setInterfaceUp(iface);
+                NetworkStack.checkNetworkStackPermission(mContext);
+                NetdUtils.setInterfaceUp(mNetd, iface);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76db019..6a72010 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -25,9 +25,14 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.IVcnManagementService;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.net.wifi.WifiInfo;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -288,6 +293,12 @@
                 @NonNull VcnConfig config) {
             return new Vcn(vcnContext, subscriptionGroup, config);
         }
+
+        /** Gets the subId indicated by the given {@link WifiInfo}. */
+        public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) {
+            // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
     }
 
     /** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -527,7 +538,7 @@
             @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
         requireNonNull(listener, "listener was null");
 
-        mContext.enforceCallingPermission(
+        mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.NETWORK_FACTORY,
                 "Must have permission NETWORK_FACTORY to register a policy listener");
 
@@ -561,4 +572,55 @@
             }
         }
     }
+
+    /**
+     * Gets the UnderlyingNetworkPolicy as determined by the provided NetworkCapabilities and
+     * LinkProperties.
+     */
+    @NonNull
+    @Override
+    public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties) {
+        requireNonNull(networkCapabilities, "networkCapabilities was null");
+        requireNonNull(linkProperties, "linkProperties was null");
+
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_FACTORY,
+                "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying"
+                        + " Network policies");
+
+        // Defensive copy in case this call is in-process and the given NetworkCapabilities mutates
+        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+
+        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
+            TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+                    (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier();
+            subId = telephonyNetworkSpecifier.getSubscriptionId();
+        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+                && networkCapabilities.getTransportInfo() instanceof WifiInfo) {
+            WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
+            subId = mDeps.getSubIdForWifiInfo(wifiInfo);
+        }
+
+        boolean isVcnManagedNetwork = 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;
+                }
+            }
+        }
+        if (isVcnManagedNetwork) {
+            networkCapabilities.removeCapability(
+                    NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+        }
+
+        return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
+    }
 }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index ab24015..a847847 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceDebugInfo;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -109,7 +110,6 @@
     };
 
     public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
-            "android.hardware.audio@2.0::IDevicesFactory",
             "android.hardware.audio@4.0::IDevicesFactory",
             "android.hardware.audio@5.0::IDevicesFactory",
             "android.hardware.audio@6.0::IDevicesFactory",
@@ -135,6 +135,11 @@
             "android.system.suspend@1.0::ISystemSuspend"
     );
 
+    public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
+            "android.hardware.light.ILights/",
+            "android.hardware.power.stats.IPowerStats/",
+    };
+
     private static Watchdog sWatchdog;
 
     /* This handler will be used to post message back onto the main thread */
@@ -515,12 +520,11 @@
         return builder.toString();
     }
 
-    private static ArrayList<Integer> getInterestingHalPids() {
+    private static void addInterestingHidlPids(HashSet<Integer> pids) {
         try {
             IServiceManager serviceManager = IServiceManager.getService();
             ArrayList<IServiceManager.InstanceDebugInfo> dump =
                     serviceManager.debugDump();
-            HashSet<Integer> pids = new HashSet<>();
             for (IServiceManager.InstanceDebugInfo info : dump) {
                 if (info.pid == IServiceManager.PidConstant.NO_PID) {
                     continue;
@@ -532,24 +536,37 @@
 
                 pids.add(info.pid);
             }
-            return new ArrayList<Integer>(pids);
         } catch (RemoteException e) {
-            return new ArrayList<Integer>();
+            Log.w(TAG, e);
+        }
+    }
+
+    private static void addInterestingAidlPids(HashSet<Integer> pids) {
+        ServiceDebugInfo[] infos = ServiceManager.getServiceDebugInfo();
+        if (infos == null) return;
+
+        for (ServiceDebugInfo info : infos) {
+            for (String prefix : AIDL_INTERFACE_PREFIXES_OF_INTEREST) {
+                if (info.name.startsWith(prefix)) {
+                    pids.add(info.debugPid);
+                }
+            }
         }
     }
 
     static ArrayList<Integer> getInterestingNativePids() {
-        ArrayList<Integer> pids = getInterestingHalPids();
+        HashSet<Integer> pids = new HashSet<>();
+        addInterestingAidlPids(pids);
+        addInterestingHidlPids(pids);
 
         int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST);
         if (nativePids != null) {
-            pids.ensureCapacity(pids.size() + nativePids.length);
             for (int i : nativePids) {
                 pids.add(i);
             }
         }
 
-        return pids;
+        return new ArrayList<Integer>(pids);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3c53880..9986085 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1066,9 +1066,9 @@
     }
 
     @Override
-    public void noteNetworkInterfaceType(String iface, int networkType) {
+    public void noteNetworkInterfaceForTransports(final String iface, int[] transportTypes) {
         enforceCallingPermission();
-        mStats.noteNetworkInterfaceType(iface, networkType);
+        mStats.noteNetworkInterfaceForTransports(iface, transportTypes);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 508bb01..fded85c 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -20,6 +20,7 @@
 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.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
@@ -46,6 +47,7 @@
 import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -55,6 +57,7 @@
 import java.io.FileDescriptor;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * System service that manages app hibernation state, a state apps can enter that means they are
@@ -74,6 +77,8 @@
     private final UserManager mUserManager;
     @GuardedBy("mLock")
     private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final Set<String> mGloballyHibernatedPackages = new ArraySet<>();
 
     /**
      * Initializes the system service.
@@ -138,7 +143,7 @@
      * @param userId the user to check
      * @return true if package is hibernating for the user
      */
-    public boolean isHibernating(String packageName, int userId) {
+    boolean isHibernatingForUser(String packageName, int userId) {
         userId = handleIncomingUser(userId, "isHibernating");
         synchronized (mLock) {
             final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
@@ -151,7 +156,19 @@
                         String.format("Package %s is not installed for user %s",
                                 packageName, userId));
             }
-            return pkgState != null ? pkgState.hibernated : null;
+            return pkgState.hibernated;
+        }
+    }
+
+    /**
+     * Whether a package is hibernated globally. This only occurs when a package is hibernating for
+     * all users and allows us to make optimizations at the package or APK level.
+     *
+     * @param packageName package to check
+     */
+    boolean isHibernatingGlobally(String packageName) {
+        synchronized (mLock) {
+            return mGloballyHibernatedPackages.contains(packageName);
         }
     }
 
@@ -162,7 +179,7 @@
      * @param userId user
      * @param isHibernating new hibernation state
      */
-    public void setHibernating(String packageName, int userId, boolean isHibernating) {
+    void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
         userId = handleIncomingUser(userId, "setHibernating");
         synchronized (mLock) {
             if (!mUserStates.contains(userId)) {
@@ -180,32 +197,99 @@
                 return;
             }
 
-
-            final long caller = Binder.clearCallingIdentity();
-            try {
-                if (isHibernating) {
-                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
-                    mIActivityManager.forceStopPackage(packageName, userId);
-                    mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
-                            null /* observer */);
-                } else {
-                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
-                    mIPackageManager.setPackageStoppedState(packageName, false, userId);
-                }
-                pkgState.hibernated = isHibernating;
-            } catch (RemoteException e) {
-                throw new IllegalStateException(
-                        "Failed to hibernate due to manager not being available", e);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Binder.restoreCallingIdentity(caller);
+            if (isHibernating) {
+                hibernatePackageForUserL(packageName, userId, pkgState);
+            } else {
+                unhibernatePackageForUserL(packageName, userId, pkgState);
             }
-
-            // TODO: Support package level hibernation when package is hibernating for all users
         }
     }
 
     /**
+     * Set whether the package should be hibernated globally at a package level, allowing the
+     * the system to make optimizations at the package or APK level.
+     *
+     * @param packageName package to hibernate globally
+     * @param isHibernating new hibernation state
+     */
+    void setHibernatingGlobally(String packageName, boolean isHibernating) {
+        if (isHibernating != mGloballyHibernatedPackages.contains(packageName)) {
+            synchronized (mLock) {
+                if (isHibernating) {
+                    hibernatePackageGloballyL(packageName);
+                } else {
+                    unhibernatePackageGloballyL(packageName);
+                }
+            }
+        }
+    }
+
+    /**
+     * 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) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
+        final long caller = Binder.clearCallingIdentity();
+        try {
+            mIActivityManager.forceStopPackage(packageName, userId);
+            mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
+                    null /* observer */);
+            pkgState.hibernated = true;
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to hibernate due to manager not being available", e);
+        } finally {
+            Binder.restoreCallingIdentity(caller);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
+    }
+
+    /**
+     * Remove a package from hibernation for a given user. The caller should hold {@link #mLock}.
+     *
+     * @param pkgState package hibernation state
+     */
+    private void unhibernatePackageForUserL(@NonNull String packageName, int userId,
+            UserPackageState pkgState) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
+        final long caller = Binder.clearCallingIdentity();
+        try {
+            mIPackageManager.setPackageStoppedState(packageName, false, userId);
+            pkgState.hibernated = false;
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to unhibernate due to manager not being available", e);
+        } finally {
+            Binder.restoreCallingIdentity(caller);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
+    }
+
+    /**
+     * 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) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
+        // TODO(175830194): Delete vdex/odex when DexManager API is built out
+        mGloballyHibernatedPackages.add(packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+    }
+
+    /**
+     * Unhibernate a package from global hibernation. The caller should hold {@link #mLock}.
+     */
+    private void unhibernatePackageGloballyL(@NonNull String packageName) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
+        mGloballyHibernatedPackages.remove(packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+    }
+
+    /**
      * Populates {@link #mUserStates} with the users installed packages. The caller should hold
      * {@link #mLock}.
      *
@@ -220,8 +304,8 @@
             throw new IllegalStateException("Package manager not available.", e);
         }
 
-        for (PackageInfo pkg : packageList) {
-            packages.put(pkg.packageName, new UserPackageState());
+        for (int i = 0, size = packageList.size(); i < size; i++) {
+            packages.put(packageList.get(i).packageName, new UserPackageState());
         }
         mUserStates.put(userId, packages);
     }
@@ -250,6 +334,12 @@
         }
     }
 
+    private void onPackageRemovedForAllUsers(@NonNull String packageName) {
+        synchronized (mLock) {
+            mGloballyHibernatedPackages.remove(packageName);
+        }
+    }
+
     /**
      * Private helper method to get the real user id and enforce permission checks.
      *
@@ -277,13 +367,23 @@
         }
 
         @Override
-        public boolean isHibernating(String packageName, int userId) {
-            return mService.isHibernating(packageName, userId);
+        public boolean isHibernatingForUser(String packageName, int userId) {
+            return mService.isHibernatingForUser(packageName, userId);
         }
 
         @Override
-        public void setHibernating(String packageName, int userId, boolean isHibernating) {
-            mService.setHibernating(packageName, userId, isHibernating);
+        public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+            mService.setHibernatingForUser(packageName, userId, isHibernating);
+        }
+
+        @Override
+        public void setHibernatingGlobally(String packageName, boolean isHibernating) {
+            mService.setHibernatingGlobally(packageName, isHibernating);
+        }
+
+        @Override
+        public boolean isHibernatingGlobally(String packageName) {
+            return mService.isHibernatingGlobally(packageName);
         }
 
         @Override
@@ -322,6 +422,9 @@
                     onPackageAdded(packageName, userId);
                 } else if (ACTION_PACKAGE_REMOVED.equals(action)) {
                     onPackageRemoved(packageName, userId);
+                    if (intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false)) {
+                        onPackageRemovedForAllUsers(packageName);
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
index 869885e..7d6eea2 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
@@ -18,7 +18,6 @@
 
 import android.os.ShellCommand;
 import android.os.UserHandle;
-import android.text.TextUtils;
 
 import java.io.PrintWriter;
 
@@ -27,6 +26,7 @@
  */
 final class AppHibernationShellCommand extends ShellCommand {
     private static final String USER_OPT = "--user";
+    private static final String GLOBAL_OPT = "--global";
     private static final int SUCCESS = 0;
     private static final int ERROR = -1;
     private final AppHibernationService mService;
@@ -51,7 +51,21 @@
     }
 
     private int runSetState() {
-        int userId = parseUserOption();
+        String opt;
+        boolean setsGlobal = false;
+        int userId = UserHandle.USER_CURRENT;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case USER_OPT:
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                case GLOBAL_OPT:
+                    setsGlobal = true;
+                    break;
+                default:
+                    getErrPrintWriter().println("Error: Unknown option: " + opt);
+            }
+        }
 
         String pkg = getNextArgRequired();
         if (pkg == null) {
@@ -66,32 +80,43 @@
         }
         boolean newState = Boolean.parseBoolean(newStateRaw);
 
-        mService.setHibernating(pkg, userId, newState);
+        if (setsGlobal) {
+            mService.setHibernatingGlobally(pkg, newState);
+        } else {
+            mService.setHibernatingForUser(pkg, userId, newState);
+        }
         return SUCCESS;
     }
 
     private int runGetState() {
-        int userId = parseUserOption();
+        String opt;
+        boolean requestsGlobal = false;
+        int userId = UserHandle.USER_CURRENT;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case USER_OPT:
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                case GLOBAL_OPT:
+                    requestsGlobal = true;
+                    break;
+                default:
+                    getErrPrintWriter().println("Error: Unknown option: " + opt);
+            }
+        }
 
         String pkg = getNextArgRequired();
         if (pkg == null) {
             getErrPrintWriter().println("Error: No package specified");
             return ERROR;
         }
-        boolean isHibernating = mService.isHibernating(pkg, userId);
+        boolean isHibernating = requestsGlobal
+                ? mService.isHibernatingGlobally(pkg) : mService.isHibernatingForUser(pkg, userId);
         final PrintWriter pw = getOutPrintWriter();
         pw.println(isHibernating);
         return SUCCESS;
     }
 
-    private int parseUserOption() {
-        String option = getNextOption();
-        if (TextUtils.equals(option, USER_OPT)) {
-            return UserHandle.parseUserArg(getNextArgRequired());
-        }
-        return UserHandle.USER_CURRENT;
-    }
-
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
@@ -99,11 +124,13 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println("");
-        pw.println("  set-state [--user USER_ID] PACKAGE true|false");
-        pw.println("    Sets the hibernation state of the package to value specified");
+        pw.println("  set-state [--user USER_ID] [--global] PACKAGE true|false");
+        pw.println("    Sets the hibernation state of the package to value specified. Optionally");
+        pw.println("    may specify a user id or set global hibernation state.");
         pw.println("");
-        pw.println("  get-state [--user USER_ID] PACKAGE");
-        pw.println("    Gets the hibernation state of the package");
+        pw.println("  get-state [--user USER_ID] [--global] PACKAGE");
+        pw.println("    Gets the hibernation state of the package. Optionally may specify a user");
+        pw.println("    id or request global hibernation state.");
         pw.println("");
     }
 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 024dca7..4c69704 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -32,6 +32,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -166,6 +167,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -173,6 +175,7 @@
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
 import java.util.stream.Collectors;
 
 /**
@@ -563,6 +566,117 @@
 
     private boolean mDockAudioMediaEnabled = true;
 
+    /**
+     * RestorableParameters is a thread-safe class used to store a
+     * first-in first-out history of parameters for replay / restoration.
+     *
+     * The idealized implementation of restoration would have a list of setting methods and
+     * values to be called for restoration.  Explicitly managing such setters and
+     * values would be tedious - a simpler method is to store the values and the
+     * method implicitly by lambda capture (the values must be immutable or synchronization
+     * needs to be taken).
+     *
+     * We provide queueRestoreWithRemovalIfTrue() to allow
+     * the caller to provide a BooleanSupplier lambda, which conveniently packages
+     * the setter and its parameters needed for restoration.  If during restoration,
+     * the BooleanSupplier returns true, it is removed from the mMap.
+     *
+     * We provide a setParameters() method as an example helper method.
+     */
+    private static class RestorableParameters {
+        /**
+         * Sets a parameter and queues for restoration if successful.
+         *
+         * @param id a string handle associated with this parameter.
+         * @param parameter the actual parameter string.
+         * @return the result of AudioSystem.setParameters
+         */
+        public int setParameters(@NonNull String id, @NonNull String parameter) {
+            Objects.requireNonNull(id, "id must not be null");
+            Objects.requireNonNull(parameter, "parameter must not be null");
+            synchronized (mMap) {
+                final int status = AudioSystem.setParameters(parameter);
+                if (status == AudioSystem.AUDIO_STATUS_OK) { // Java uses recursive mutexes.
+                    queueRestoreWithRemovalIfTrue(id, () -> { // remove me if set fails.
+                        return AudioSystem.setParameters(parameter) != AudioSystem.AUDIO_STATUS_OK;
+                    });
+                }
+                // Implementation detail: We do not mMap.remove(id); on failure.
+                return status;
+            }
+        }
+
+        /**
+         * Queues a restore method which is executed on restoreAll().
+         *
+         * If the supplier null, the id is removed from the restore map.
+         *
+         * Note: When the BooleanSupplier restore method is executed
+         * during restoreAll, if it returns true, it is removed from the
+         * restore map.
+         *
+         * @param id a unique tag associated with the restore method.
+         * @param supplier is a BooleanSupplier lambda.
+         */
+        public void queueRestoreWithRemovalIfTrue(
+                @NonNull String id, @Nullable BooleanSupplier supplier) {
+            Objects.requireNonNull(id, "id must not be null");
+            synchronized (mMap) {
+                if (supplier != null) {
+                    mMap.put(id, supplier);
+                } else {
+                    mMap.remove(id);
+                }
+            }
+        }
+
+        /**
+         * Restore all parameters
+         *
+         * During restoration after audioserver death, any BooleanSupplier that returns
+         * true will be removed from mMap.
+         */
+        public void restoreAll() {
+            synchronized (mMap) {
+                // Note: removing from values() also removes from the backing map.
+                // TODO: Consider catching exceptions?
+                mMap.values().removeIf(v -> {
+                    return v.getAsBoolean();
+                });
+            }
+        }
+
+        /**
+         * mMap is a LinkedHashMap<Key, Value> of parameters restored by restore().
+         * The Key is a unique id tag for identification.
+         * The Value is a lambda expression which returns true if the entry is to
+         *     be removed.
+         *
+         * 1) For memory limitation purposes, mMap keeps the latest MAX_ENTRIES
+         *    accessed in the map.
+         * 2) Parameters are restored in order of queuing, first in first out,
+         *    from earliest to latest.
+         */
+        @GuardedBy("mMap")
+        private Map</* @NonNull */ String, /* @NonNull */ BooleanSupplier> mMap =
+                new LinkedHashMap<>() {
+            // TODO: do we need this memory limitation?
+            private static final int MAX_ENTRIES = 1000;  // limit our memory for now.
+            @Override
+            protected boolean removeEldestEntry(Map.Entry eldest) {
+                if (size() <= MAX_ENTRIES) return false;
+                Log.w(TAG, "Parameter map exceeds "
+                        + MAX_ENTRIES + " removing " + eldest.getKey()); // don't silently remove.
+                return true;
+            }
+        };
+    }
+
+    // We currently have one instance for mRestorableParameters used for
+    // setAdditionalOutputDeviceDelay().  Other methods requiring restoration could share this
+    // or use their own instance.
+    private RestorableParameters mRestorableParameters = new RestorableParameters();
+
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
     // Used when safe volume warning message display is requested by setStreamVolume(). In this
@@ -1095,6 +1209,9 @@
             RotationHelper.updateOrientation();
         }
 
+        // Restore setParameters and other queued setters.
+        mRestorableParameters.restoreAll();
+
         synchronized (mSettingsLock) {
             final int forDock = mDockAudioMediaEnabled ?
                     AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
@@ -9303,6 +9420,95 @@
         }
     }
 
+    /**
+     * @hide
+     * Sets an additional audio output device delay in milliseconds.
+     *
+     * The additional output delay is a request to the output device to
+     * delay audio presentation (generally with respect to video presentation for better
+     * synchronization).
+     * It may not be supported by all output devices,
+     * and typically increases the audio latency by the amount of additional
+     * audio delay requested.
+     *
+     * If additional audio delay is supported by an audio output device,
+     * it is expected to be supported for all output streams (and configurations)
+     * opened on that device.
+     *
+     * @param deviceType
+     * @param address
+     * @param delayMillis delay in milliseconds desired.  This should be in range of {@code 0}
+     *     to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
+     * @return true if successful, false if the device does not support output device delay
+     *     or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
+     */
+    @Override
+    //@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public boolean setAdditionalOutputDeviceDelay(
+            @NonNull AudioDeviceAttributes device, @IntRange(from = 0) long delayMillis) {
+        Objects.requireNonNull(device, "device must not be null");
+        enforceModifyAudioRoutingPermission();
+        final String getterKey = "additional_output_device_delay="
+                 + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+                 + "," + device.getAddress(); // "getter" key as an id.
+        final String setterKey = getterKey + "," + delayMillis;     // append the delay for setter
+        return mRestorableParameters.setParameters(getterKey, setterKey)
+                == AudioSystem.AUDIO_STATUS_OK;
+    }
+
+    /**
+     * @hide
+     * Returns the current additional audio output device delay in milliseconds.
+     *
+     * @param deviceType
+     * @param address
+     * @return the additional output device delay. This is a non-negative number.
+     *     {@code 0} is returned if unsupported.
+     */
+    @Override
+    @IntRange(from = 0)
+    public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceAttributes device) {
+        Objects.requireNonNull(device, "device must not be null");
+        final String key = "additional_output_device_delay";
+        final String reply = AudioSystem.getParameters(
+                key + "=" + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+                    + "," + device.getAddress());
+        long delayMillis;
+        try {
+            delayMillis = Long.parseLong(reply.substring(key.length() + 1));
+        } catch (NullPointerException e) {
+            delayMillis = 0;
+        }
+        return delayMillis;
+    }
+
+    /**
+     * @hide
+     * Returns the maximum additional audio output device delay in milliseconds.
+     *
+     * @param deviceType
+     * @param address
+     * @return the maximum output device delay in milliseconds that can be set.
+     *     This is a non-negative number
+     *     representing the additional audio delay supported for the device.
+     *     {@code 0} is returned if unsupported.
+     */
+    @Override
+    @IntRange(from = 0)
+    public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceAttributes device) {
+        Objects.requireNonNull(device, "device must not be null");
+        final String key = "max_additional_output_device_delay";
+        final String reply = AudioSystem.getParameters(
+                key + "=" + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+                    + "," + device.getAddress());
+        long delayMillis;
+        try {
+            delayMillis = Long.parseLong(reply.substring(key.length() + 1));
+        } catch (NullPointerException e) {
+            delayMillis = 0;
+        }
+        return delayMillis;
+    }
 
     //======================
     // misc
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ab0360b..1a4f20c7 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -57,6 +57,7 @@
 import com.android.server.ConnectivityService;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -329,7 +330,7 @@
     private final QosCallbackTracker mQosCallbackTracker;
 
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
-            LinkProperties lp, NetworkCapabilities nc, int score, Context context,
+            @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
             int creatorUid, QosCallbackTracker qosCallbackTracker) {
@@ -1025,6 +1026,8 @@
                 + (networkAgentConfig.acceptUnvalidated ? " acceptUnvalidated" : "")
                 + (networkAgentConfig.acceptPartialConnectivity ? " acceptPartialConnectivity" : "")
                 + (clatd.isStarted() ? " clat{" + clatd + "} " : "")
+                + (declaredUnderlyingNetworks != null
+                        ? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
                 + "  lp{" + linkProperties + "}"
                 + "  nc{" + networkCapabilities + "}"
                 + "}";
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index a7be657..5e6b9f3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -686,7 +686,7 @@
 
             mHostname = hostname;
             mMeasurement.description = "DNS TLS dst{" + mTarget.getHostAddress() + "} hostname{"
-                    + TextUtils.emptyIfNull(mHostname) + "}";
+                    + (mHostname == null ? "" : mHostname) + "}";
         }
 
         private SSLSocket setupSSLSocket() throws IOException {
diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
index 5dc8c1a..aadaf4d 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
@@ -16,7 +16,6 @@
 
 package com.android.server.connectivity;
 
-import android.annotation.NonNull;
 import android.annotation.WorkerThread;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -72,6 +71,10 @@
     private static final int DELAY_LONG = 4;
     private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
+    // Return values for #setCurrentProxyScriptUrl
+    public static final boolean DONT_SEND_BROADCAST = false;
+    public static final boolean DO_SEND_BROADCAST = true;
+
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
     private volatile Uri mPacUrl = Uri.EMPTY;
@@ -90,7 +93,7 @@
     private volatile boolean mHasSentBroadcast;
     private volatile boolean mHasDownloaded;
 
-    private final Handler mConnectivityHandler;
+    private Handler mConnectivityHandler;
     private final int mProxyMessage;
 
     /**
@@ -99,13 +102,6 @@
     private final Object mProxyLock = new Object();
 
     /**
-     * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the
-     * last URL and port, and the broadcast message being sent with the correct arguments.
-     * TODO : this should probably protect all instances of these variables
-     */
-    private final Object mBroadcastStateLock = new Object();
-
-    /**
      * Runnable to download PAC script.
      * The behavior relies on the assumption it always runs on mNetThread to guarantee that the
      * latest data fetched from mPacUrl is stored in mProxyService.
@@ -150,7 +146,7 @@
         }
     }
 
-    public PacProxyInstaller(@NonNull Context context, @NonNull Handler handler, int proxyMessage) {
+    public PacProxyInstaller(Context context, Handler handler, int proxyMessage) {
         mContext = context;
         mLastPort = -1;
         final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller",
@@ -180,27 +176,31 @@
      * PacProxyInstaller will trigger a new broadcast when it is ready.
      *
      * @param proxy Proxy information that is about to be broadcast.
+     * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
      */
-    public void setCurrentProxyScriptUrl(@NonNull ProxyInfo proxy) {
-        synchronized (mBroadcastStateLock) {
-            if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
-                if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return;
-                mPacUrl = proxy.getPacFileUrl();
-                mCurrentDelay = DELAY_1;
-                mHasSentBroadcast = false;
-                mHasDownloaded = false;
-                getAlarmManager().cancel(mPacRefreshIntent);
-                bind();
-            } else {
-                getAlarmManager().cancel(mPacRefreshIntent);
-                synchronized (mProxyLock) {
-                    mPacUrl = Uri.EMPTY;
-                    mCurrentPac = null;
-                    if (mProxyService != null) {
-                        unbind();
-                    }
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+        if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
+            if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
+                // Allow to send broadcast, nothing to do.
+                return DO_SEND_BROADCAST;
+            }
+            mPacUrl = proxy.getPacFileUrl();
+            mCurrentDelay = DELAY_1;
+            mHasSentBroadcast = false;
+            mHasDownloaded = false;
+            getAlarmManager().cancel(mPacRefreshIntent);
+            bind();
+            return DONT_SEND_BROADCAST;
+        } else {
+            getAlarmManager().cancel(mPacRefreshIntent);
+            synchronized (mProxyLock) {
+                mPacUrl = Uri.EMPTY;
+                mCurrentPac = null;
+                if (mProxyService != null) {
+                    unbind();
                 }
             }
+            return DO_SEND_BROADCAST;
         }
     }
 
@@ -275,7 +275,6 @@
         getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
     }
 
-    @GuardedBy("mProxyLock")
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
@@ -348,9 +347,6 @@
                             public void setProxyPort(int port) {
                                 if (mLastPort != -1) {
                                     // Always need to send if port changed
-                                    // TODO: Here lacks synchronization because this write cannot
-                                    // guarantee that it's visible from sendProxyIfNeeded() when
-                                    // it's called by a Runnable which is post by mNetThread.
                                     mHasSentBroadcast = false;
                                 }
                                 mLastPort = port;
@@ -390,15 +386,13 @@
         mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
     }
 
-    private void sendProxyIfNeeded() {
-        synchronized (mBroadcastStateLock) {
-            if (!mHasDownloaded || (mLastPort == -1)) {
-                return;
-            }
-            if (!mHasSentBroadcast) {
-                sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
-                mHasSentBroadcast = true;
-            }
+    private synchronized void sendProxyIfNeeded() {
+        if (!mHasDownloaded || (mLastPort == -1)) {
+            return;
+        }
+        if (!mHasSentBroadcast) {
+            sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
+            mHasSentBroadcast = true;
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index b618d2b..d83ff83 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -226,9 +226,9 @@
         final ProxyInfo defaultProxy = getDefaultProxy();
         final ProxyInfo proxyInfo = null != defaultProxy ?
                 defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
-        mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo);
 
-        if (!shouldSendBroadcast(proxyInfo)) {
+        if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
+                == PacProxyInstaller.DONT_SEND_BROADCAST) {
             return;
         }
         if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,13 +244,6 @@
         }
     }
 
-    private boolean shouldSendBroadcast(ProxyInfo proxy) {
-        if (Uri.EMPTY.equals(proxy.getPacFileUrl())) return false;
-        if (proxy.getPacFileUrl().equals(proxy.getPacFileUrl())
-                && (proxy.getPort() > 0)) return true;
-        return true;
-    }
-
     /**
      * Sets the global proxy in memory. Also writes the values to the global settings of the device.
      *
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8ce6746..d956ba3 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -70,7 +70,7 @@
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 import android.net.VpnManager;
 import android.net.VpnService;
 import android.net.ipsec.ike.ChildSessionCallback;
@@ -426,6 +426,7 @@
         mNetworkCapabilities = new NetworkCapabilities();
         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
         mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
 
         loadAlwaysOnPackage(keyStore);
     }
@@ -1819,12 +1820,12 @@
      * This method should not be called if underlying interfaces field is needed, because it doesn't
      * have enough data to fill VpnInfo.underlyingIfaces field.
      */
-    public synchronized VpnInfo getVpnInfo() {
+    public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
         if (!isRunningLocked()) {
             return null;
         }
 
-        return new VpnInfo(mOwnerUID, mInterface, null);
+        return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>());
     }
 
     public synchronized boolean appliesToUid(int uid) {
@@ -1981,27 +1982,28 @@
      * secondary thread to perform connection work, returning quickly.
      *
      * Should only be called to respond to Binder requests as this enforces caller permission. Use
-     * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
+     * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, Network, LinkProperties)} to skip the
      * permission check only when the caller is trusted (or the call is initiated by the system).
      */
-    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, @Nullable Network underlying,
+            LinkProperties egress) {
         enforceControlPermission();
         final long token = Binder.clearCallingIdentity();
         try {
-            startLegacyVpnPrivileged(profile, keyStore, egress);
+            startLegacyVpnPrivileged(profile, keyStore, underlying, egress);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
     /**
-     * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
-     * permissions under the assumption that the caller is the system.
+     * Like {@link #startLegacyVpn(VpnProfile, KeyStore, Network, LinkProperties)}, but does not
+     * check permissions under the assumption that the caller is the system.
      *
      * Callers are responsible for checking permissions if needed.
      */
     public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
-            LinkProperties egress) {
+            @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,
@@ -2127,6 +2129,9 @@
         config.session = profile.name;
         config.isMetered = false;
         config.proxyInfo = profile.proxy;
+        if (underlying != null) {
+            config.underlyingNetworks = new Network[] { underlying };
+        }
 
         config.addLegacyRoutes(profile.routes);
         if (!profile.dnsServers.isEmpty()) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8e50bb4..5d1c4e6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -621,7 +621,14 @@
         mWakeUpMessageReceived = false;
 
         if (isTvDeviceEnabled()) {
-            mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
+            boolean autoWakeupEnabled =
+                readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
+            boolean autoDeviceOffEnabled =
+                readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
+
+            mCecController.setOption(OptionKey.WAKEUP, autoWakeupEnabled);
+            tv().setAutoWakeup(autoWakeupEnabled);
+            tv().setAutoDeviceOff(autoDeviceOffEnabled);
         }
         int reason = -1;
         switch (initiatedBy) {
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 6c8694e..9a52c19 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -17,8 +17,8 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
 import android.util.Slog;
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index d4393d6..90c2330 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,2 +1,3 @@
 arthuri@google.com
 bduddie@google.com
+stange@google.com
diff --git a/services/core/java/com/android/server/location/timezone/OWNERS b/services/core/java/com/android/server/location/timezone/OWNERS
deleted file mode 100644
index 28aff18..0000000
--- a/services/core/java/com/android/server/location/timezone/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index 8399f54..a1e18bd 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -106,6 +106,8 @@
         private final Context mContext;
         private final ComponentName mComponentName;
         private IResumeOnRebootService mBinder;
+        @Nullable
+        ServiceConnection mServiceConnection;
 
         private ResumeOnRebootServiceConnection(Context context,
                 @NonNull ComponentName componentName) {
@@ -115,17 +117,9 @@
 
         /** Unbind from the service */
         public void unbindService() {
-            mContext.unbindService(new ServiceConnection() {
-                @Override
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                }
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    mBinder = null;
-
-                }
-            });
+            if (mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+            }
         }
 
         /** Bind to the service */
@@ -134,17 +128,19 @@
                 CountDownLatch connectionLatch = new CountDownLatch(1);
                 Intent intent = new Intent();
                 intent.setComponent(mComponentName);
-                final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
-                            @Override
-                            public void onServiceConnected(ComponentName name, IBinder service) {
-                                mBinder = IResumeOnRebootService.Stub.asInterface(service);
-                                connectionLatch.countDown();
-                            }
+                mServiceConnection = new ServiceConnection() {
+                    @Override
+                    public void onServiceConnected(ComponentName name, IBinder service) {
+                        mBinder = IResumeOnRebootService.Stub.asInterface(service);
+                        connectionLatch.countDown();
+                    }
 
-                            @Override
-                            public void onServiceDisconnected(ComponentName name) {
-                            }
-                        },
+                    @Override
+                    public void onServiceDisconnected(ComponentName name) {
+                        mBinder = null;
+                    }
+                };
+                final boolean success = mContext.bindServiceAsUser(intent, mServiceConnection,
                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                         BackgroundThread.getHandler(), UserHandle.SYSTEM);
 
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea2788c..6d1c680 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -155,7 +155,7 @@
                 try {
                     // Use the privileged method because Lockdown VPN is initiated by the system, so
                     // no additional permission checks are necessary.
-                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
+                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, null, egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
                     Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 01d4faf..0fd39a4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -239,6 +239,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.StatLogger;
 import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.NetworkIdentityUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
@@ -2162,13 +2163,14 @@
             if (template.matches(probeIdent)) {
                 if (LOGD) {
                     Slog.d(TAG, "Found template " + template + " which matches subscriber "
-                            + NetworkIdentity.scrubSubscriberId(subscriberId));
+                            + NetworkIdentityUtils.scrubSubscriberId(subscriberId));
                 }
                 return false;
             }
         }
 
-        Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
+        Slog.i(TAG, "No policy for subscriber "
+                + NetworkIdentityUtils.scrubSubscriberId(subscriberId)
                 + "; generating default policy");
         final NetworkPolicy policy = buildDefaultMobilePolicy(subId, subscriberId);
         addNetworkPolicyAL(policy);
@@ -3596,14 +3598,15 @@
                     final int subId = mSubIdToSubscriberId.keyAt(i);
                     final String subscriberId = mSubIdToSubscriberId.valueAt(i);
 
-                    fout.println(subId + "=" + NetworkIdentity.scrubSubscriberId(subscriberId));
+                    fout.println(subId + "="
+                            + NetworkIdentityUtils.scrubSubscriberId(subscriberId));
                 }
                 fout.decreaseIndent();
 
                 fout.println();
                 for (String[] mergedSubscribers : mMergedSubscriberIds) {
                     fout.println("Merged subscriptions: " + Arrays.toString(
-                            NetworkIdentity.scrubSubscriberId(mergedSubscribers)));
+                            NetworkIdentityUtils.scrubSubscriberIds(mergedSubscribers)));
                 }
 
                 fout.println();
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 4faa790..d042b88 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -27,7 +27,7 @@
 import android.annotation.Nullable;
 import android.net.INetd;
 import android.net.NetworkStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 import android.net.util.NetdService;
 import android.os.RemoteException;
 import android.os.StrictMode;
@@ -81,7 +81,7 @@
     private final Object mPersistentDataLock = new Object();
 
     /** Set containing info about active VPNs and their underlying networks. */
-    private volatile VpnInfo[] mVpnInfos = new VpnInfo[0];
+    private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0];
 
     // A persistent snapshot of cumulative stats since device start
     @GuardedBy("mPersistentDataLock")
@@ -116,8 +116,8 @@
      *
      * @param vpnArray The snapshot of the currently-running VPNs.
      */
-    public void updateVpnInfos(VpnInfo[] vpnArray) {
-        mVpnInfos = vpnArray.clone();
+    public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) {
+        mUnderlyingNetworkInfos = vpnArray.clone();
     }
 
     /**
@@ -319,7 +319,7 @@
         // code that will acquire other locks within the system server. See b/134244752.
         synchronized (mPersistentDataLock) {
             // Take a reference. If this gets swapped out, we still have the old reference.
-            final VpnInfo[] vpnArray = mVpnInfos;
+            final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos;
             // Take a defensive copy. mPersistSnapshot is mutated in some cases below
             final NetworkStats prev = mPersistSnapshot.clone();
 
@@ -369,8 +369,8 @@
     }
 
     @GuardedBy("mPersistentDataLock")
-    private NetworkStats adjustForTunAnd464Xlat(
-            NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) {
+    private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats,
+            NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) {
         // Calculate delta from last snapshot
         final NetworkStats delta = uidDetailStats.subtract(previousStats);
 
@@ -381,8 +381,9 @@
         delta.apply464xlatAdjustments(mStackedIfaces);
 
         // Migrate data usage over a VPN to the TUN network.
-        for (VpnInfo info : vpnArray) {
-            delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces);
+        for (UnderlyingNetworkInfo info : vpnArray) {
+            delta.migrateTun(info.ownerUid, info.iface,
+                    info.underlyingIfaces.toArray(new String[0]));
             // Filter out debug entries as that may lead to over counting.
             delta.filterDebugEntries();
         }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4be7b48..0ab35a9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,8 +104,8 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
+import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
-import android.net.VpnInfo;
 import android.net.netstats.provider.INetworkStatsProvider;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
@@ -973,7 +973,7 @@
             Network[] defaultNetworks,
             NetworkState[] networkStates,
             String activeIface,
-            VpnInfo[] vpnInfos) {
+            UnderlyingNetworkInfo[] underlyingNetworkInfos) {
         checkNetworkStackPermission(mContext);
 
         final long token = Binder.clearCallingIdentity();
@@ -986,7 +986,7 @@
         // Update the VPN underlying interfaces only after the poll is made and tun data has been
         // migrated. Otherwise the migration would use the new interfaces instead of the ones that
         // were current when the polled data was transferred.
-        mStatsFactory.updateVpnInfos(vpnInfos);
+        mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
     }
 
     @Override
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/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 6427ae2..fd12c2d2 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -18,16 +18,28 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkCapabilities.NetCapability;
+import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.Handler;
 import android.os.ParcelUuid;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+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 java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Tracks a set of Networks underpinning a VcnGatewayConnection.
@@ -38,53 +50,385 @@
  *
  * @hide
  */
-public class UnderlyingNetworkTracker extends Handler {
+public class UnderlyingNetworkTracker {
     @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName();
 
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @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 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;
+
+    @Nullable private UnderlyingNetworkRecord mCurrentRecord;
+    @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
 
     public UnderlyingNetworkTracker(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
+            @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
             @NonNull UnderlyingNetworkTrackerCallback cb) {
-        this(vcnContext, subscriptionGroup, cb, new Dependencies());
+        this(
+                vcnContext,
+                subscriptionGroup,
+                requiredUnderlyingNetworkCapabilities,
+                cb,
+                new Dependencies());
     }
 
     private UnderlyingNetworkTracker(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
+            @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
             @NonNull UnderlyingNetworkTrackerCallback cb,
             @NonNull Dependencies deps) {
-        super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
-        mVcnContext = vcnContext;
+        mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
         mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
+        mRequiredUnderlyingNetworkCapabilities =
+                Objects.requireNonNull(
+                        requiredUnderlyingNetworkCapabilities,
+                        "Missing requiredUnderlyingNetworkCapabilities");
         mCb = Objects.requireNonNull(cb, "Missing cb");
         mDeps = Objects.requireNonNull(deps, "Missing deps");
+
+        mHandler = new Handler(mVcnContext.getLooper());
+
+        mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
+        mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class);
+
+        registerNetworkRequests();
+    }
+
+    private void registerNetworkRequests() {
+        // register bringup requests for underlying Networks
+        mConnectivityManager.requestBackgroundNetwork(
+                getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
+        updateSubIdsAndCellularRequests();
+
+        // register Network-selection request used to decide selected underlying Network
+        mConnectivityManager.requestBackgroundNetwork(
+                getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback);
+    }
+
+    private NetworkRequest getWifiNetworkRequest() {
+        return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+    }
+
+    private NetworkRequest getCellNetworkRequestForSubId(int subId) {
+        return getNetworkRequestBase()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
+                .build();
+    }
+
+    private NetworkRequest.Builder getNetworkRequestBase() {
+        NetworkRequest.Builder requestBase = new NetworkRequest.Builder();
+        for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) {
+            requestBase.addCapability(capability);
+        }
+
+        return requestBase
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+    }
+
+    /**
+     * Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker.
+     */
+    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);
+            }
+        }
+
+        // unregister all NetworkCallbacks for outdated subIds
+        for (final int subId : prevSubIds) {
+            if (!mSubIds.contains(subId)) {
+                final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
+                mConnectivityManager.unregisterNetworkCallback(cb);
+            }
+        }
     }
 
     /** Tears down this Tracker, and releases all underlying network requests. */
-    public void teardown() {}
+    public void teardown() {
+        mVcnContext.ensureRunningOnLooperThread();
 
-    /** An record of a single underlying network, caching relevant fields. */
+        mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback);
+        mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback);
+
+        for (final int subId : mSubIds) {
+            final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
+            mConnectivityManager.unregisterNetworkCallback(cb);
+        }
+        mSubIds.clear();
+    }
+
+    /** Returns whether the currently selected Network matches the given network. */
+    private static boolean isSameNetwork(
+            @Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) {
+        return recordInProgress != null && recordInProgress.getNetwork().equals(network);
+    }
+
+    /** Notify the Callback if a full UnderlyingNetworkRecord exists. */
+    private void maybeNotifyCallback() {
+        // Only forward this update if a complete record has been received
+        if (!mRecordInProgress.isValid()) {
+            return;
+        }
+
+        // Only forward this update if the updated record differs form the current record
+        UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build();
+        if (!updatedRecord.equals(mCurrentRecord)) {
+            mCurrentRecord = updatedRecord;
+
+            mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);
+        }
+    }
+
+    private void handleNetworkAvailable(@NonNull Network network) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        mRecordInProgress = new UnderlyingNetworkRecord.Builder(network);
+    }
+
+    private void handleNetworkLost(@NonNull Network network) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (!isSameNetwork(mRecordInProgress, network)) {
+            Slog.wtf(TAG, "Non-underlying Network lost");
+            return;
+        }
+
+        mRecordInProgress = null;
+        mCurrentRecord = null;
+        mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */);
+    }
+
+    private void handleCapabilitiesChanged(
+            @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (!isSameNetwork(mRecordInProgress, network)) {
+            Slog.wtf(TAG, "Invalid update to NetworkCapabilities");
+            return;
+        }
+
+        mRecordInProgress.setNetworkCapabilities(networkCapabilities);
+
+        maybeNotifyCallback();
+    }
+
+    private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (!isSameNetwork(mRecordInProgress, network)) {
+            Slog.wtf(TAG, "Invalid update to isSuspended");
+            return;
+        }
+
+        final NetworkCapabilities newCaps =
+                new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities());
+        if (isSuspended) {
+            newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
+        } else {
+            newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
+        }
+
+        handleCapabilitiesChanged(network, newCaps);
+    }
+
+    private void handlePropertiesChanged(
+            @NonNull Network network, @NonNull LinkProperties linkProperties) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (!isSameNetwork(mRecordInProgress, network)) {
+            Slog.wtf(TAG, "Invalid update to LinkProperties");
+            return;
+        }
+
+        mRecordInProgress.setLinkProperties(linkProperties);
+
+        maybeNotifyCallback();
+    }
+
+    private void handleNetworkBlocked(@NonNull Network network, boolean isBlocked) {
+        mVcnContext.ensureRunningOnLooperThread();
+
+        if (!isSameNetwork(mRecordInProgress, network)) {
+            Slog.wtf(TAG, "Invalid update to isBlocked");
+            return;
+        }
+
+        mRecordInProgress.setIsBlocked(isBlocked);
+
+        maybeNotifyCallback();
+    }
+
+    /**
+     * NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped.
+     *
+     * <p>NetworkBringupCallback only exists to prevent matching (VCN-managed) Networks from being
+     * reaped, and no action is taken on any events firing.
+     */
+    @VisibleForTesting
+    class NetworkBringupCallback extends NetworkCallback {}
+
+    /**
+     * RouteSelectionCallback is used to select the "best" underlying Network.
+     *
+     * <p>The "best" network is determined by ConnectivityService, which is treated as a source of
+     * truth.
+     */
+    @VisibleForTesting
+    class RouteSelectionCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(@NonNull Network network) {
+            handleNetworkAvailable(network);
+        }
+
+        @Override
+        public void onLost(@NonNull Network network) {
+            handleNetworkLost(network);
+        }
+
+        @Override
+        public void onCapabilitiesChanged(
+                @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+            handleCapabilitiesChanged(network, networkCapabilities);
+        }
+
+        @Override
+        public void onNetworkSuspended(@NonNull Network network) {
+            handleNetworkSuspended(network, true /* isSuspended */);
+        }
+
+        @Override
+        public void onNetworkResumed(@NonNull Network network) {
+            handleNetworkSuspended(network, false /* isSuspended */);
+        }
+
+        @Override
+        public void onLinkPropertiesChanged(
+                @NonNull Network network, @NonNull LinkProperties linkProperties) {
+            handlePropertiesChanged(network, linkProperties);
+        }
+
+        @Override
+        public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) {
+            handleNetworkBlocked(network, isBlocked);
+        }
+    }
+
+    /** A record of a single underlying network, caching relevant fields. */
     public static class UnderlyingNetworkRecord {
         @NonNull public final Network network;
         @NonNull public final NetworkCapabilities networkCapabilities;
         @NonNull public final LinkProperties linkProperties;
-        public final boolean blocked;
+        public final boolean isBlocked;
 
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         UnderlyingNetworkRecord(
                 @NonNull Network network,
                 @NonNull NetworkCapabilities networkCapabilities,
                 @NonNull LinkProperties linkProperties,
-                boolean blocked) {
+                boolean isBlocked) {
             this.network = network;
             this.networkCapabilities = networkCapabilities;
             this.linkProperties = linkProperties;
-            this.blocked = blocked;
+            this.isBlocked = isBlocked;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof UnderlyingNetworkRecord)) return false;
+            final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
+
+            return network.equals(that.network)
+                    && networkCapabilities.equals(that.networkCapabilities)
+                    && linkProperties.equals(that.linkProperties)
+                    && isBlocked == that.isBlocked;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
+        }
+
+        /** Builder to incrementally construct an UnderlyingNetworkRecord. */
+        private static class Builder {
+            @NonNull private final Network mNetwork;
+
+            @Nullable private NetworkCapabilities mNetworkCapabilities;
+            @Nullable private LinkProperties mLinkProperties;
+            boolean mIsBlocked;
+            boolean mWasIsBlockedSet;
+
+            private Builder(@NonNull Network network) {
+                mNetwork = network;
+            }
+
+            @NonNull
+            private Network getNetwork() {
+                return mNetwork;
+            }
+
+            private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+                mNetworkCapabilities = networkCapabilities;
+            }
+
+            @Nullable
+            private NetworkCapabilities getNetworkCapabilities() {
+                return mNetworkCapabilities;
+            }
+
+            private void setLinkProperties(@NonNull LinkProperties linkProperties) {
+                mLinkProperties = linkProperties;
+            }
+
+            private void setIsBlocked(boolean isBlocked) {
+                mIsBlocked = isBlocked;
+                mWasIsBlockedSet = true;
+            }
+
+            private boolean isValid() {
+                return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
+            }
+
+            private UnderlyingNetworkRecord build() {
+                return new UnderlyingNetworkRecord(
+                        mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
+            }
         }
     }
 
@@ -95,9 +439,10 @@
          *
          * <p>This callback does NOT signal a mobility event.
          *
-         * @param underlying The details of the new underlying network
+         * @param underlyingNetworkRecord The details of the new underlying network
          */
-        void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying);
+        void onSelectedUnderlyingNetworkChanged(
+                @Nullable UnderlyingNetworkRecord underlyingNetworkRecord);
     }
 
     private static class Dependencies {}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 9d21b92..132883e 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -168,8 +168,8 @@
             @NonNull NetworkRequest request, int score, int providerId) {
         if (score > getNetworkScore()) {
             Slog.v(getLogTag(),
-                    "Request " + request.requestId + " already satisfied by higher-scoring ("
-                            + score + ") network from provider " + providerId);
+                    "Request already satisfied by higher-scoring (" + score + ") network from "
+                            + "provider " + providerId + ": " + request);
             return;
         }
 
@@ -177,8 +177,7 @@
         for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
             if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                 Slog.v(getLogTag(),
-                        "Request " + request.requestId
-                                + " satisfied by existing VcnGatewayConnection");
+                        "Request already satisfied by existing VcnGatewayConnection: " + request);
                 return;
             }
         }
@@ -202,12 +201,12 @@
 
     private boolean requestSatisfiedByGatewayConnectionConfig(
             @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
-        final NetworkCapabilities configCaps = new NetworkCapabilities();
+        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
         for (int cap : config.getAllExposedCapabilities()) {
-            configCaps.addCapability(cap);
+            builder.addCapability(cap);
         }
 
-        return request.networkCapabilities.satisfiedByNetworkCapabilities(configCaps);
+        return request.canBeSatisfiedBy(builder.build());
     }
 
     private String getLogTag() {
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index dba59bd..7399e56 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -55,4 +55,15 @@
     public VcnNetworkProvider getVcnNetworkProvider() {
         return mVcnNetworkProvider;
     }
+
+    /**
+     * Verifies that the caller is running on the VcnContext Thread.
+     *
+     * @throwsIllegalStateException if the caller is not running on the VcnContext Thread.
+     */
+    public void ensureRunningOnLooperThread() {
+        if (getLooper().getThread() != Thread.currentThread()) {
+            throw new IllegalStateException("Not running on VcnMgmtSvc thread");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 8805fa2..39c9606 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -65,6 +65,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -476,7 +477,10 @@
 
         mUnderlyingNetworkTracker =
                 mDeps.newUnderlyingNetworkTracker(
-                        mVcnContext, subscriptionGroup, mUnderlyingNetworkTrackerCallback);
+                        mVcnContext,
+                        subscriptionGroup,
+                        mConnectionConfig.getAllUnderlyingCapabilities(),
+                        mUnderlyingNetworkTrackerCallback);
         mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
 
         IpSecTunnelInterface iface;
@@ -638,6 +642,22 @@
 
         protected abstract void processStateMsg(Message msg) throws Exception;
 
+        @Override
+        public void exit() {
+            try {
+                exitState();
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Uncaught exception", e);
+                sendMessage(
+                        EVENT_DISCONNECT_REQUESTED,
+                        TOKEN_ALL,
+                        new EventDisconnectRequestedInfo(
+                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+            }
+        }
+
+        protected void exitState() throws Exception {}
+
         protected void logUnhandledMessage(Message msg) {
             // Log as unexpected all known messages, and log all else as unknown.
             switch (msg.what) {
@@ -664,18 +684,11 @@
             }
         }
 
-        protected void teardownIke() {
-            if (mIkeSession != null) {
-                mIkeSession.close();
-            }
-        }
-
         protected void handleDisconnectRequested(String msg) {
             Slog.v(TAG, "Tearing down. Cause: " + msg);
             mIsRunning = false;
 
             teardownNetwork();
-            teardownIke();
 
             if (mIkeSession == null) {
                 // Already disconnected, go straight to DisconnectedState
@@ -768,6 +781,20 @@
      * does not complete teardown in a timely fashion, it will be killed (forcibly closed).
      */
     private class DisconnectingState extends ActiveBaseState {
+        /**
+         * Whether to skip the RetryTimeoutState and go straight to the ConnectingState.
+         *
+         * <p>This is used when an underlying network change triggered a restart on a new network.
+         *
+         * <p>Reset (to false) upon exit of the DisconnectingState.
+         */
+        private boolean mSkipRetryTimeout = false;
+
+        // TODO(b/178441390): Remove this in favor of resetting retry timers on UND_NET change.
+        public void setSkipRetryTimeout(boolean shouldSkip) {
+            mSkipRetryTimeout = shouldSkip;
+        }
+
         @Override
         protected void enterState() throws Exception {
             if (mIkeSession == null) {
@@ -783,6 +810,7 @@
                 return;
             }
 
+            mIkeSession.close();
             sendMessageDelayed(
                     EVENT_TEARDOWN_TIMEOUT_EXPIRED,
                     mCurrentToken,
@@ -822,7 +850,7 @@
                     mIkeSession = null;
 
                     if (mIsRunning && mUnderlying != null) {
-                        transitionTo(mRetryTimeoutState);
+                        transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
                     } else {
                         teardownNetwork();
                         transitionTo(mDisconnectedState);
@@ -833,6 +861,11 @@
                     break;
             }
         }
+
+        @Override
+        protected void exitState() throws Exception {
+            mSkipRetryTimeout = false;
+        }
     }
 
     /**
@@ -843,7 +876,69 @@
      */
     private class ConnectingState extends ActiveBaseState {
         @Override
-        protected void processStateMsg(Message msg) {}
+        protected void enterState() {
+            if (mIkeSession != null) {
+                Slog.wtf(TAG, "ConnectingState entered with active session");
+
+                // Attempt to recover.
+                mIkeSession.kill();
+                mIkeSession = null;
+            }
+
+            mIkeSession = buildIkeSession();
+        }
+
+        @Override
+        protected void processStateMsg(Message msg) {
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED:
+                    final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+                    mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+                    if (oldUnderlying == null) {
+                        // This should never happen, but if it does, there's likely a nasty bug.
+                        Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?");
+                    }
+
+                    // If new underlying is null, all underlying networks have been lost; disconnect
+                    if (mUnderlying == null) {
+                        transitionTo(mDisconnectingState);
+                        break;
+                    }
+
+                    if (oldUnderlying != null
+                            && mUnderlying.network.equals(oldUnderlying.network)) {
+                        break; // Only network properties have changed; continue connecting.
+                    }
+                    // Else, retry on the new network.
+
+                    // Immediately come back to the ConnectingState (skip RetryTimeout, since this
+                    // isn't a failure)
+                    mDisconnectingState.setSkipRetryTimeout(true);
+
+                    // fallthrough - disconnect, and retry on new network.
+                case EVENT_SESSION_LOST:
+                    transitionTo(mDisconnectingState);
+                    break;
+                case EVENT_SESSION_CLOSED:
+                    deferMessage(msg);
+
+                    transitionTo(mDisconnectingState);
+                    break;
+                case EVENT_SETUP_COMPLETED: // fallthrough
+                case EVENT_TRANSFORM_CREATED:
+                    // Child setup complete; move to ConnectedState for NetworkAgent registration
+                    deferMessage(msg);
+                    transitionTo(mConnectedState);
+                    break;
+                case EVENT_DISCONNECT_REQUESTED:
+                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    break;
+                default:
+                    logUnhandledMessage(msg);
+                    break;
+            }
+        }
     }
 
     private abstract class ConnectedStateBase extends ActiveBaseState {}
@@ -872,18 +967,18 @@
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static NetworkCapabilities buildNetworkCapabilities(
             @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
-        final NetworkCapabilities caps = new NetworkCapabilities();
+        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
 
-        caps.addTransportType(TRANSPORT_CELLULAR);
-        caps.addCapability(NET_CAPABILITY_NOT_CONGESTED);
-        caps.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        builder.addTransportType(TRANSPORT_CELLULAR);
+        builder.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+        builder.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
 
         // Add exposed capabilities
         for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
-            caps.addCapability(cap);
+            builder.addCapability(cap);
         }
 
-        return caps;
+        return builder.build();
     }
 
     private static LinkProperties buildConnectedLinkProperties(
@@ -1015,12 +1110,12 @@
     }
 
     private IkeSessionParams buildIkeParams() {
-        // TODO: Implement this with ConnectingState
+        // TODO: Implement this once IkeSessionParams is persisted
         return null;
     }
 
     private ChildSessionParams buildChildParams() {
-        // TODO: Implement this with ConnectingState
+        // TODO: Implement this once IkeSessionParams is persisted
         return null;
     }
 
@@ -1043,8 +1138,10 @@
         public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
                 VcnContext vcnContext,
                 ParcelUuid subscriptionGroup,
+                Set<Integer> requiredUnderlyingNetworkCapabilities,
                 UnderlyingNetworkTrackerCallback callback) {
-            return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback);
+            return new UnderlyingNetworkTracker(
+                    vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback);
         }
 
         /** Builds a new IkeSession. */
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index 7f5b23c..b9babae 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -21,9 +21,9 @@
 import android.net.NetworkProvider;
 import android.net.NetworkRequest;
 import android.os.Looper;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import java.util.Objects;
 import java.util.Set;
@@ -40,7 +40,13 @@
     private static final String TAG = VcnNetworkProvider.class.getSimpleName();
 
     private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
-    private final SparseArray<NetworkRequestEntry> mRequests = new SparseArray<>();
+
+    /**
+     * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest
+     *
+     * <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
+     */
+    private final ArrayMap<NetworkRequest, NetworkRequestEntry> mRequests = new ArrayMap<>();
 
     public VcnNetworkProvider(Context context, Looper looper) {
         super(context, looper, VcnNetworkProvider.class.getSimpleName());
@@ -51,8 +57,8 @@
         mListeners.add(listener);
 
         // Send listener all cached requests
-        for (int i = 0; i < mRequests.size(); i++) {
-            notifyListenerForEvent(listener, mRequests.valueAt(i));
+        for (NetworkRequestEntry entry : mRequests.values()) {
+            notifyListenerForEvent(listener, entry);
         }
     }
 
@@ -75,7 +81,9 @@
                         request, score, providerId));
 
         final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
-        mRequests.put(request.requestId, entry);
+
+        // NetworkRequests are immutable once created, and therefore can be used as stable keys.
+        mRequests.put(request, entry);
 
         // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on
         // Default Data Sub, or similar)
@@ -86,7 +94,7 @@
 
     @Override
     public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
-        mRequests.remove(request.requestId);
+        mRequests.remove(request);
     }
 
     private static class NetworkRequestEntry {
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/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6089a52..203de9d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1533,15 +1533,6 @@
             }
             t.traceEnd();
 
-            t.traceBegin("StartVcnManagementService");
-            try {
-                vcnManagement = VcnManagementService.create(context);
-                ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
-            } catch (Throwable e) {
-                reportWtf("starting VCN Management Service", e);
-            }
-            t.traceEnd();
-
             t.traceBegin("StartTextServicesManager");
             mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
             t.traceEnd();
@@ -1639,6 +1630,15 @@
             networkPolicy.bindConnectivityManager(connectivity);
             t.traceEnd();
 
+            t.traceBegin("StartVcnManagementService");
+            try {
+                vcnManagement = VcnManagementService.create(context);
+                ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
+            } catch (Throwable e) {
+                reportWtf("starting VCN Management Service", e);
+            }
+            t.traceEnd();
+
             t.traceBegin("StartNsdService");
             try {
                 serviceDiscovery = NsdService.create(context);
@@ -2415,15 +2415,6 @@
                 reportWtf("making IpSec Service ready", e);
             }
             t.traceEnd();
-            t.traceBegin("MakeVcnManagementServiceReady");
-            try {
-                if (vcnManagementF != null) {
-                    vcnManagementF.systemReady();
-                }
-            } catch (Throwable e) {
-                reportWtf("making VcnManagementService ready", e);
-            }
-            t.traceEnd();
             t.traceBegin("MakeNetworkStatsServiceReady");
             try {
                 if (networkStatsF != null) {
@@ -2442,6 +2433,15 @@
                 reportWtf("making Connectivity Service ready", e);
             }
             t.traceEnd();
+            t.traceBegin("MakeVcnManagementServiceReady");
+            try {
+                if (vcnManagementF != null) {
+                    vcnManagementF.systemReady();
+                }
+            } catch (Throwable e) {
+                reportWtf("making VcnManagementService ready", e);
+            }
+            t.traceEnd();
             t.traceBegin("MakeNetworkPolicyServiceReady");
             try {
                 if (networkPolicyF != null) {
diff --git a/services/smartspace/OWNERS b/services/smartspace/OWNERS
new file mode 100644
index 0000000..19ef9d7
--- /dev/null
+++ b/services/smartspace/OWNERS
@@ -0,0 +1,2 @@
+srazdan@google.com
+alexmang@google.com
\ No newline at end of file
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 d0370b6..45bca68 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -64,6 +64,8 @@
     private static final int USER_ID_1 = 1;
     private static final int USER_ID_2 = 2;
 
+    private final List<UserInfo> mUserInfos = new ArrayList<>();
+
     private AppHibernationService mAppHibernationService;
     private BroadcastReceiver mBroadcastReceiver;
     @Mock
@@ -88,47 +90,42 @@
         verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
         mBroadcastReceiver = mReceiverCaptor.getValue();
 
-        List<UserInfo> userList = new ArrayList<>();
-        userList.add(new UserInfo(USER_ID_1, "user 1", 0 /* flags */));
-        doReturn(userList).when(mUserManager).getUsers();
-
-        List<PackageInfo> userPackages = new ArrayList<>();
-        userPackages.add(makePackageInfo(PACKAGE_NAME_1));
-
-        doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
-                .getInstalledPackages(anyInt(), eq(USER_ID_1));
+        doReturn(mUserInfos).when(mUserManager).getUsers();
 
         doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
                 anyInt(), anyBoolean(), anyBoolean(), any(), any());
 
+        addUser(USER_ID_1);
         mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
     }
 
     @Test
-    public void testSetHibernating_packageIsHibernating() {
+    public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException {
         // WHEN we hibernate a package for a user
-        mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
         // THEN the package is marked hibernating for the user
-        assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+        assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
     }
 
     @Test
-    public void testSetHibernating_newPackageAdded_packageIsHibernating() {
+    public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating()
+            throws RemoteException {
         // 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 */));
         intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
         mBroadcastReceiver.onReceive(mContext, intent);
 
-        mAppHibernationService.setHibernating(PACKAGE_NAME_2, USER_ID_1, true);
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_1, true);
 
         // THEN the new package is hibernated
-        assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_2, USER_ID_1));
+        assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_2, USER_ID_1));
     }
 
     @Test
-    public void testSetHibernating_newUserAdded_packageIsHibernating() throws RemoteException {
+    public void testSetHibernatingForUser_newUserAdded_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));
@@ -138,16 +135,17 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
         mBroadcastReceiver.onReceive(mContext, intent);
 
-        mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_2, true);
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
 
         // THEN the new user's package is hibernated
-        assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_2));
+        assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
     }
 
     @Test
-    public void testIsHibernating_packageReplaced_stillReturnsHibernating() {
+    public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()
+            throws RemoteException {
         // GIVEN a package is currently hibernated
-        mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
         // WHEN the package is removed but marked as replacing
         Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
@@ -157,7 +155,38 @@
         mBroadcastReceiver.onReceive(mContext, intent);
 
         // THEN the package is still hibernating
-        assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+        assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
+    }
+
+    @Test
+    public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException {
+        // WHEN we hibernate a package
+        mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
+
+        // THEN the package is marked hibernating for the user
+        assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
+    }
+
+    /**
+     * Add a mock user with one package. Must be called before
+     * {@link AppHibernationService#onBootPhase(int)} to work properly.
+     */
+    private void addUser(int userId) throws RemoteException {
+        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
+     */
+    private void addUser(int userId, String[] packageNames) throws RemoteException {
+        mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */));
+        List<PackageInfo> userPackages = new ArrayList<>();
+        for (String pkgName : packageNames) {
+            userPackages.add(makePackageInfo(pkgName));
+        }
+        doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
+                .getInstalledPackages(anyInt(), eq(userId));
     }
 
     private static PackageInfo makePackageInfo(String packageName) {
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
deleted file mode 100644
index 28aff18..0000000
--- a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 9d48955..e567208 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -1025,6 +1025,8 @@
             writeLocked(fos, stats, version, packagesTokenData);
             file.finishWrite(fos);
             fos = null;
+        } catch (Exception e) {
+            // Do nothing. Exception has already been handled.
         } finally {
             // When fos is null (successful write), this will no-op
             file.failWrite(fos);
@@ -1032,7 +1034,7 @@
     }
 
     private static void writeLocked(OutputStream out, IntervalStats stats, int version,
-            PackagesTokenData packagesTokenData) throws RuntimeException {
+            PackagesTokenData packagesTokenData) throws Exception {
         switch (version) {
             case 1:
             case 2:
@@ -1044,6 +1046,7 @@
                     UsageStatsProto.write(out, stats);
                 } catch (Exception e) {
                     Slog.e(TAG, "Unable to write interval stats to proto.", e);
+                    throw e;
                 }
                 break;
             case 5:
@@ -1052,6 +1055,7 @@
                     UsageStatsProtoV2.write(out, stats);
                 } catch (Exception e) {
                     Slog.e(TAG, "Unable to write interval stats to proto.", e);
+                    throw e;
                 }
                 break;
             default:
diff --git a/telecomm/java/android/telecom/BluetoothCallQualityReport.java b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
new file mode 100644
index 0000000..10339a8
--- /dev/null
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
@@ -0,0 +1,256 @@
+/*
+ * 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.telecom;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents the quality report that bluetooth framework sends
+ * whenever there's a bad voice quality is detected from their side.
+ * It is sent as part of a call event via {@link Call#sendCallEvent(String, Bundle)}
+ * associated with extra EXTRA_BLUETOOTH_CALL_QUALITY_REPORT.
+ * Note that this report will be sent only during an active voice/voip call.
+ * @hide
+ */
+@SystemApi
+public final class BluetoothCallQualityReport implements Parcelable {
+
+    /**
+     * Event that is sent via {@link Call#sendCallEvent(String, Bundle)} for a call quality report
+     */
+    public static final String EVENT_BLUETOOTH_CALL_QUALITY_REPORT =
+            "android.telecom.event.BLUETOOTH_CALL_QUALITY_REPORT";
+
+    /**
+     * Extra key sent with {@link Call#sendCallEvent(String, Bundle)}
+     */
+    public static final String EXTRA_BLUETOOTH_CALL_QUALITY_REPORT =
+            "android.telecom.extra.BLUETOOTH_CALL_QUALITY_REPORT";
+
+    private final long mSentTimestampMillis;
+    private final boolean mChoppyVoice;
+    private final int mRssiDbm;
+    private final int mSnrDb;
+    private final int mRetransmittedPacketsCount;
+    private final int mPacketsNotReceivedCount;
+    private final int mNegativeAcknowledgementCount;
+
+    /**
+     * @return Time in milliseconds since the epoch. Designates when report was sent.
+     * Used to determine whether this report arrived too late to be useful.
+     */
+    public @ElapsedRealtimeLong long getSentTimestampMillis() {
+        return mSentTimestampMillis;
+    }
+
+    /**
+     * @return {@code true} if bluetooth hardware detects voice is choppy
+     */
+    public boolean isChoppyVoice() {
+        return mChoppyVoice;
+    }
+
+    /**
+     * @return Received Signal Strength Indication (RSSI) value in dBm.
+     * This value shall be an absolute received signal strength value.
+     */
+    public @IntRange(from = -127, to = 20) int getRssiDbm() {
+        return mRssiDbm;
+    }
+
+    /**
+     * @return Signal-to-Noise Ratio (SNR) value in dB.
+     * The controller shall provide the average SNR of all the channels currently used by the link.
+     */
+    public int getSnrDb() {
+        return mSnrDb;
+    }
+
+    /**
+     * @return The number of retransmissions since the last event.
+     * This count shall be reset after it is reported.
+     */
+    public @IntRange(from = 0) int getRetransmittedPacketsCount() {
+        return mRetransmittedPacketsCount;
+    }
+
+    /**
+     * @return No RX count since the last event.
+     * The count increases when no packet is received at the scheduled time slot or the received
+     * packet is corrupted.
+     * This count shall be reset after it is reported.
+     */
+    public @IntRange(from = 0) int getPacketsNotReceivedCount() {
+        return mPacketsNotReceivedCount;
+    }
+
+    /**
+     * @return NAK (Negative Acknowledge) count since the last event.
+     * This count shall be reset after it is reported.
+     */
+    public @IntRange(from = 0) int getNegativeAcknowledgementCount() {
+        return mNegativeAcknowledgementCount;
+    }
+
+    //
+    // Parcelable implementation
+    //
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeLong(mSentTimestampMillis);
+        out.writeBoolean(mChoppyVoice);
+        out.writeInt(mRssiDbm);
+        out.writeInt(mSnrDb);
+        out.writeInt(mRetransmittedPacketsCount);
+        out.writeInt(mPacketsNotReceivedCount);
+        out.writeInt(mNegativeAcknowledgementCount);
+    }
+
+    public static final @android.annotation.NonNull Creator<BluetoothCallQualityReport> CREATOR =
+            new Creator<BluetoothCallQualityReport>() {
+                @Override
+                public BluetoothCallQualityReport createFromParcel(Parcel in) {
+                    return new BluetoothCallQualityReport(in);
+                }
+
+                @Override
+                public BluetoothCallQualityReport[] newArray(int size) {
+                    return new BluetoothCallQualityReport[size];
+                }
+            };
+
+    /**
+     * Builder class for {@link ConnectionRequest}
+     */
+    public static final class Builder {
+        private long mSentTimestampMillis;
+        private boolean mChoppyVoice;
+        private int mRssiDbm;
+        private int mSnrDb;
+        private int mRetransmittedPacketsCount;
+        private int mPacketsNotReceivedCount;
+        private int mNegativeAcknowledgementCount;
+
+        public Builder() { }
+
+        /**
+         * Set the time when report was sent in milliseconds since the epoch.
+         * @param sentTimestampMillis
+         */
+        public @NonNull Builder setSentTimestampMillis(long sentTimestampMillis) {
+            mSentTimestampMillis = sentTimestampMillis;
+            return this;
+        }
+
+        /**
+         * Set if bluetooth hardware detects voice is choppy
+         * @param choppyVoice
+         */
+        public @NonNull Builder setChoppyVoice(boolean choppyVoice) {
+            mChoppyVoice = choppyVoice;
+            return this;
+        }
+
+        /**
+         * Set Received Signal Strength Indication (RSSI) value in dBm.
+         * @param rssiDbm
+         */
+        public @NonNull Builder setRssiDbm(int rssiDbm) {
+            mRssiDbm = rssiDbm;
+            return this;
+        }
+
+        /**
+         * Set Signal-to-Noise Ratio (SNR) value in dB.
+         * @param snrDb
+         */
+        public @NonNull Builder setSnrDb(int snrDb) {
+            mSnrDb = snrDb;
+            return this;
+        }
+
+        /**
+         * Set The number of retransmissions since the last event.
+         * @param retransmittedPacketsCount
+         */
+        public @NonNull Builder setRetransmittedPacketsCount(
+                int retransmittedPacketsCount) {
+            mRetransmittedPacketsCount = retransmittedPacketsCount;
+            return this;
+        }
+
+        /**
+         * Set No RX count since the last event.
+         * @param packetsNotReceivedCount
+         */
+        public @NonNull Builder setPacketsNotReceivedCount(
+                int packetsNotReceivedCount) {
+            mPacketsNotReceivedCount = packetsNotReceivedCount;
+            return this;
+        }
+
+        /**
+         * Set NAK (Negative Acknowledge) count since the last event.
+         * @param negativeAcknowledgementCount
+         */
+        public @NonNull Builder setNegativeAcknowledgementCount(
+                int negativeAcknowledgementCount) {
+            mNegativeAcknowledgementCount = negativeAcknowledgementCount;
+            return this;
+        }
+
+        /**
+         * Build the {@link BluetoothCallQualityReport}
+         * @return Result of the builder
+         */
+        public @NonNull BluetoothCallQualityReport build() {
+            return new BluetoothCallQualityReport(this);
+        }
+    }
+
+    private BluetoothCallQualityReport(Parcel in) {
+        mSentTimestampMillis = in.readLong();
+        mChoppyVoice = in.readBoolean();
+        mRssiDbm = in.readInt();
+        mSnrDb = in.readInt();
+        mRetransmittedPacketsCount = in.readInt();
+        mPacketsNotReceivedCount = in.readInt();
+        mNegativeAcknowledgementCount = in.readInt();
+    }
+
+    private BluetoothCallQualityReport(Builder builder) {
+        mSentTimestampMillis = builder.mSentTimestampMillis;
+        mChoppyVoice = builder.mChoppyVoice;
+        mRssiDbm = builder.mRssiDbm;
+        mSnrDb = builder.mSnrDb;
+        mRetransmittedPacketsCount = builder.mRetransmittedPacketsCount;
+        mPacketsNotReceivedCount = builder.mPacketsNotReceivedCount;
+        mNegativeAcknowledgementCount = builder.mNegativeAcknowledgementCount;
+    }
+}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index e55720c..335a102 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3005,6 +3005,26 @@
     public void onCallAudioStateChanged(CallAudioState state) {}
 
     /**
+     * Inform this Connection when it will or will not be tracked by an {@link InCallService} which
+     * can provide an InCall UI.
+     * This is primarily intended for use by Connections reported by self-managed
+     * {@link ConnectionService} which typically maintain their own UI.
+     *
+     * @param isUsingAlternativeUi Indicates whether an InCallService that can provide InCall UI is
+     *                             currently tracking the self-managed call.
+     */
+    public void onUsingAlternativeUi(boolean isUsingAlternativeUi) {}
+
+    /**
+     * Inform this Conenection when it will or will not be tracked by an non-UI
+     * {@link InCallService}.
+     *
+     * @param isTracked Indicates whether an non-UI InCallService is currently tracking the
+     *                 self-managed call.
+     */
+    public void onTrackedByNonUiService(boolean isTracked) {}
+
+    /**
      * Notifies this Connection of an internal state change. This method is called after the
      * state is changed.
      *
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b1ccb53..a4ecb72 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -137,6 +137,8 @@
     private static final String SESSION_HOLD = "CS.h";
     private static final String SESSION_UNHOLD = "CS.u";
     private static final String SESSION_CALL_AUDIO_SC = "CS.cASC";
+    private static final String SESSION_USING_ALTERNATIVE_UI = "CS.uAU";
+    private static final String SESSION_TRACKED_BY_NON_UI_SERVICE = "CS.tBNUS";
     private static final String SESSION_PLAY_DTMF = "CS.pDT";
     private static final String SESSION_STOP_DTMF = "CS.sDT";
     private static final String SESSION_CONFERENCE = "CS.c";
@@ -200,6 +202,9 @@
     private static final int MSG_ADD_PARTICIPANT = 39;
     private static final int MSG_EXPLICIT_CALL_TRANSFER = 40;
     private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41;
+    private static final int MSG_ON_CALL_FILTERING_COMPLETED = 42;
+    private static final int MSG_ON_USING_ALTERNATIVE_UI = 43;
+    private static final int MSG_ON_TRACKED_BY_NON_UI_SERVICE = 44;
 
     private static Connection sNullConnection;
 
@@ -584,6 +589,36 @@
         }
 
         @Override
+        public void onUsingAlternativeUi(String callId, boolean usingAlternativeUiShowing,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_USING_ALTERNATIVE_UI);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = usingAlternativeUiShowing;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_ON_USING_ALTERNATIVE_UI, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
+        public void onTrackedByNonUiService(String callId, boolean isTracked,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_TRACKED_BY_NON_UI_SERVICE);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = isTracked;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_ON_TRACKED_BY_NON_UI_SERVICE, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void playDtmfTone(String callId, char digit, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_PLAY_DTMF);
             try {
@@ -1226,6 +1261,34 @@
                     }
                     break;
                 }
+                case MSG_ON_USING_ALTERNATIVE_UI: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3,
+                            SESSION_HANDLER + SESSION_USING_ALTERNATIVE_UI);
+                    try {
+                        String callId = (String) args.arg1;
+                        boolean isUsingAlternativeUi = (boolean) args.arg2;
+                        onUsingAlternativeUi(callId, isUsingAlternativeUi);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
+                case MSG_ON_TRACKED_BY_NON_UI_SERVICE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3,
+                            SESSION_HANDLER + SESSION_TRACKED_BY_NON_UI_SERVICE);
+                    try {
+                        String callId = (String) args.arg1;
+                        boolean isTracked = (boolean) args.arg2;
+                        onTrackedByNonUiService(callId, isTracked);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_PLAY_DTMF_TONE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -1928,10 +1991,12 @@
                 request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
         boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
                 TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
-        Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
-                        "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b",
-                callManagerAccount, callId, request, isIncoming, isUnknown, isLegacyHandover,
-                isHandover);
+        boolean addSelfManaged = request.getExtras() != null && request.getExtras().getBoolean(
+                PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false);
+        Log.i(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, "
+                        + "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b, "
+                        + " addSelfManaged: %b", callManagerAccount, callId, request, isIncoming,
+                isUnknown, isLegacyHandover, isHandover, addSelfManaged);
 
         Connection connection = null;
         if (isHandover) {
@@ -2206,6 +2271,22 @@
         }
     }
 
+    private void onUsingAlternativeUi(String callId, boolean isUsingAlternativeUi) {
+        Log.i(this, "onUsingAlternativeUi %s %s", callId, isUsingAlternativeUi);
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "onUsingAlternativeUi")
+                    .onUsingAlternativeUi(isUsingAlternativeUi);
+        }
+    }
+
+    private void onTrackedByNonUiService(String callId, boolean isTracked) {
+        Log.i(this, "onTrackedByNonUiService %s %s", callId, isTracked);
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "onTrackedByNonUiService")
+                    .onTrackedByNonUiService(isTracked);
+        }
+    }
+
     private void playDtmfTone(String callId, char digit) {
         Log.i(this, "playDtmfTone %s %c", callId, digit);
         if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 835ecaa..579b33e 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -188,6 +188,15 @@
         "android.telecom.extra.SKIP_CALL_FILTERING";
 
     /**
+     * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
+     * indicates whether a Self-managed {@link PhoneAccount} want to expose its calls to all
+     * {@link InCallService} which declares the metadata
+     * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS}.
+     */
+    public static final String EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE =
+            "android.telecom.extra.ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE";
+
+    /**
      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
      * will be allowed to manage phone calls including using its own proprietary phone-call
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index fb54179..d555547 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -136,4 +136,9 @@
             int error, in Session.Info sessionInfo);
 
     void handoverComplete(String callId, in Session.Info sessionInfo);
+
+    void onUsingAlternativeUi(String callId, boolean isUsingAlternativeUi,
+            in Session.Info sessionInfo);
+
+    void onTrackedByNonUiService(String callId, boolean isTracked, in Session.Info sessionInfo);
 }
diff --git a/telephony/java/android/telephony/CarrierBandwidth.java b/telephony/java/android/telephony/CarrierBandwidth.java
index 17747a3..b153fef 100644
--- a/telephony/java/android/telephony/CarrierBandwidth.java
+++ b/telephony/java/android/telephony/CarrierBandwidth.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -102,7 +103,7 @@
     /**
      * Retrieves the upstream bandwidth for the primary network in Kbps.  This always only refers to
      * the estimated first hop transport bandwidth.
-     * This will be INVALID if the network is not connected
+     * This will be {@link #INVALID} if the network is not connected
      *
      * @return The estimated first hop upstream (device to network) bandwidth.
      */
@@ -113,7 +114,7 @@
     /**
      * Retrieves the downstream bandwidth for the primary network in Kbps.  This always only refers
      * to the estimated first hop transport bandwidth.
-     * This will be INVALID if the network is not connected
+     * This will be {@link #INVALID} if the network is not connected
      *
      * @return The estimated first hop downstream (network to device) bandwidth.
      */
@@ -124,10 +125,19 @@
     /**
      * Retrieves the upstream bandwidth for the secondary network in Kbps.  This always only refers
      * to the estimated first hop transport bandwidth.
-     * This will be INVALID if the network is not connected
+     * <p/>
+     * This will be {@link #INVALID} if either are the case:
+     * <ol>
+     *  <li>The network is not connected</li>
+     *  <li>The device does not support
+     * {@link android.telephony.TelephonyManager#CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE}.</li>
+     * </ol>
      *
      * @return The estimated first hop upstream (device to network) bandwidth.
      */
+    @RequiresFeature(
+            enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+            value = TelephonyManager.CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE)
     public int getSecondaryDownlinkCapacityKbps() {
         return mSecondaryDownlinkCapacityKbps;
     }
@@ -135,10 +145,18 @@
     /**
      * Retrieves the downstream bandwidth for the secondary network in Kbps.  This always only
      * refers to the estimated first hop transport bandwidth.
-     * This will be INVALID if the network is not connected
-     *
+     * <p/>
+     * This will be {@link #INVALID} if either are the case:
+     * <ol>
+     *  <li>The network is not connected</li>
+     *  <li>The device does not support
+     * {@link android.telephony.TelephonyManager#CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE}.</li>
+     * </ol>
      * @return The estimated first hop downstream (network to device) bandwidth.
      */
+    @RequiresFeature(
+            enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+            value = TelephonyManager.CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE)
     public int getSecondaryUplinkCapacityKbps() {
         return mSecondaryUplinkCapacityKbps;
     }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3a9896a..a42e364 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4124,6 +4124,13 @@
      */
     public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool";
 
+    /**
+     * Indicates temporarily unmetered mobile data is supported by the carrier.
+     * @hide
+     */
+    public static final String KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL =
+            "network_temp_not_metered_supported_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -4673,6 +4680,7 @@
         sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
         sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
         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);
     }
 
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/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 646744d..e8ace34 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -31,6 +31,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringDef;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
@@ -14344,9 +14345,22 @@
         return Collections.emptyList();
     }
 
+    /**
+     * Indicates whether {@link CarrierBandwidth#getSecondaryDownlinkCapacityKbps()} and
+     * {@link CarrierBandwidth#getSecondaryUplinkCapacityKbps()} are visible.  See comments
+     * on respective methods for more information.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE =
+            "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE";
+
     /** @hide */
-    @IntDef(prefix = {"RADIO_INTERFACE_CAPABILITY_"},
-            value = {})
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = "CAPABILITY_", value = {
+            CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE,
+    })
     public @interface RadioInterfaceCapability {}
 
     /**
@@ -14359,6 +14373,7 @@
      *
      * @hide
      */
+    @SystemApi
     public boolean isRadioInterfaceCapabilitySupported(
             @NonNull @RadioInterfaceCapability String capability) {
         try {
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 52b31d7..a5150b0 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -15,6 +15,7 @@
  */
 package android.telephony.euicc;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.PendingIntent;
@@ -102,44 +103,81 @@
         this.accessRules = accessRules;
     }
 
-    /** @hide */
-    @SystemApi
     public static final class Builder {
         @Nullable private String encodedActivationCode;
         @Nullable private String confirmationCode;
         @Nullable private String carrierName;
         List<UiccAccessRule> accessRules;
 
+        /** @hide */
+        @SystemApi
         public Builder() {}
 
-        public Builder(DownloadableSubscription baseSubscription) {
+        public Builder(@NonNull DownloadableSubscription baseSubscription) {
             encodedActivationCode = baseSubscription.getEncodedActivationCode();
             confirmationCode = baseSubscription.getConfirmationCode();
             carrierName = baseSubscription.getCarrierName();
             accessRules = baseSubscription.getAccessRules();
         }
 
+        public Builder(@NonNull String encodedActivationCode) {
+            this.encodedActivationCode = encodedActivationCode;
+        }
+
+        /**
+         * Builds a {@link DownloadableSubscription} object.
+         * @return a non-null {@link DownloadableSubscription} object.
+         */
+        @NonNull
         public DownloadableSubscription build() {
             return new DownloadableSubscription(encodedActivationCode, confirmationCode,
                     carrierName, accessRules);
         }
 
-        public Builder setEncodedActivationCode(String value) {
+        /**
+         * Sets the encoded activation code.
+         * @param value the activation code to use. An activation code can be parsed from a user
+         *              scanned QR code. The format of activation code is defined in SGP.22. For
+         *              example, "1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746". For
+         *              detail, see {@code com.android.euicc.data.ActivationCode}. Must not be null.
+         */
+        @NonNull
+        public Builder setEncodedActivationCode(@NonNull String value) {
             encodedActivationCode = value;
             return this;
         }
 
-        public Builder setConfirmationCode(String value) {
+        /**
+         * Sets the confirmation code.
+         * @param value the confirmation code to use to authenticate the carrier server got
+         *              subscription download.
+         */
+        @NonNull
+        public Builder setConfirmationCode(@NonNull String value) {
             confirmationCode = value;
             return this;
         }
 
-        public Builder setCarrierName(String value) {
+        /**
+         * Sets the user-visible carrier name.
+         * @param value carrier name.
+         * @hide
+         */
+        @NonNull
+        @SystemApi
+        public Builder setCarrierName(@NonNull String value) {
             carrierName = value;
             return this;
         }
 
-        public Builder setAccessRules(List<UiccAccessRule> value) {
+        /**
+         * Sets the {@link UiccAccessRule}s dictating access to this subscription.
+         * @param value A list of {@link UiccAccessRule}s.
+         * @hide
+         */
+        @NonNull
+        @SystemApi
+        public Builder setAccessRules(@NonNull List<UiccAccessRule> value) {
             accessRules = value;
             return this;
         }
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index baa0576..754814f 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -178,4 +178,11 @@
     public ImsUtListener(IImsUtListener serviceInterface) {
         mServiceInterface = serviceInterface;
     }
+
+    /**
+     * @hide
+     */
+    public IImsUtListener getListenerInterface() {
+        return mServiceInterface;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 519d016..5eb75e7 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -34,14 +35,135 @@
  * network during a SUBSCRIBE request. See RFC3863 for more information.
  * @hide
  */
+@SystemApi
 public final class RcsContactPresenceTuple implements Parcelable {
 
-    /** The service id of the MMTEL */
+    /**
+     * The service ID used to indicate that MMTEL service is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
     public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
 
-    /** The service id of the Call Composer */
+    /**
+     * The service ID used to indicate that the chat(v1.0) is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+
+    /**
+     * The service ID used to indicate that the chat(v2.0) is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+
+    /**
+     * The service ID used to indicate that the File Transfer is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+
+    /**
+     * The service ID used to indicate that the File Transfer over SMS is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_FT_OVER_SMS =
+            "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+
+    /**
+     * The service ID used to indicate that the Geolocation Push is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_GEO_PUSH =
+            "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+
+    /**
+     * The service ID used to indicate that the Geolocation Push via SMS is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_GEO_PUSH_VIA_SMS =
+            "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+
+    /**
+     * The service ID used to indicate that the Call Composer is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
     public static final String SERVICE_ID_CALL_COMPOSER =
-            "org.3gpp.urn:urn-7:3gppservice.ims.icsi.gsma.callcomposer";
+            "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+
+    /**
+     * The service ID used to indicate that the Post Call is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_POST_CALL =
+            "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+
+    /**
+     * The service ID used to indicate that the Shared Map is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_SHARED_MAP =
+            "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+
+    /**
+     * The service ID used to indicate that the Shared Sketch is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_SHARED_SKETCH =
+            "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+
+    /**
+     * The service ID used to indicate that the Chatbot using Session is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_CHATBOT =
+            "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+
+    /**
+     * The service ID used to indicate that the Standalone Messaging is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_CHATBOT_STANDALONE =
+            " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+
+    /**
+     * The service ID used to indicate that the Chatbot Role is available.
+     * <p>
+     * See the GSMA RCC.07 specification for more information.
+     */
+    public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = "SERVICE_ID_", value = {
+            SERVICE_ID_MMTEL,
+            SERVICE_ID_CHAT_V1,
+            SERVICE_ID_CHAT_V2,
+            SERVICE_ID_FT,
+            SERVICE_ID_FT_OVER_SMS,
+            SERVICE_ID_GEO_PUSH,
+            SERVICE_ID_GEO_PUSH_VIA_SMS,
+            SERVICE_ID_CALL_COMPOSER,
+            SERVICE_ID_POST_CALL,
+            SERVICE_ID_SHARED_MAP,
+            SERVICE_ID_SHARED_SKETCH,
+            SERVICE_ID_CHATBOT,
+            SERVICE_ID_CHATBOT_STANDALONE,
+            SERVICE_ID_CHATBOT_ROLE
+    })
+    public @interface ServiceId {}
 
     /** The service capabilities is available. */
     public static final String TUPLE_BASIC_STATUS_OPEN = "open";
@@ -149,6 +271,7 @@
             in.readStringList(mSupportedDuplexModeList);
             in.readStringList(mUnsupportedDuplexModeList);
         }
+
         @Override
         public void writeToParcel(@NonNull Parcel out, int flags) {
             out.writeBoolean(mIsAudioCapable);
@@ -217,12 +340,14 @@
 
         /**
          * Builds a RcsContactPresenceTuple instance.
+         * @param status The status associated with the service capability. See RFC3865 for more
+         * information.
          * @param serviceId The OMA Presence service-id associated with this capability. See the
          * OMA Presence SIMPLE specification v1.1, section 10.5.1.
          * @param serviceVersion The OMA Presence version associated with the service capability.
          * See the OMA Presence SIMPLE specification v1.1, section 10.5.1.
          */
-        public Builder(@NonNull @BasicStatus String status, @NonNull String serviceId,
+        public Builder(@NonNull @BasicStatus String status, @NonNull @ServiceId String serviceId,
                 @NonNull String serviceVersion) {
             mPresenceTuple = new RcsContactPresenceTuple(status, serviceId, serviceVersion);
         }
@@ -230,16 +355,17 @@
         /**
          * The optional SIP Contact URI associated with the PIDF tuple element.
          */
-        public @NonNull Builder addContactUri(@NonNull Uri contactUri) {
+        public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
             mPresenceTuple.mContactUri = contactUri;
             return this;
         }
 
         /**
          * The optional timestamp indicating the data and time of the status change of this tuple.
-         * See RFC3863, section 4.1.7 for more information on the expected format.
+         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
+         * string per RFC3339.
          */
-        public @NonNull Builder addTimeStamp(@NonNull String timestamp) {
+        public @NonNull Builder setTimestamp(@NonNull String timestamp) {
             mPresenceTuple.mTimestamp = timestamp;
             return this;
         }
@@ -248,7 +374,7 @@
          * An optional parameter containing the description element of the service-description. See
          * OMA Presence SIMPLE specification v1.1
          */
-        public @NonNull Builder addDescription(@NonNull String description) {
+        public @NonNull Builder setServiceDescription(@NonNull String description) {
             mPresenceTuple.mServiceDescription = description;
             return this;
         }
@@ -257,7 +383,7 @@
          * An optional parameter containing the service capabilities of the presence tuple if they
          * are present in the servcaps element.
          */
-        public @NonNull Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) {
+        public @NonNull Builder setServiceCapabilities(@NonNull ServiceCapabilities caps) {
             mPresenceTuple.mServiceCapabilities = caps;
             return this;
         }
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index d4715bf..fe85502 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +34,7 @@
  * Contains the User Capability Exchange capabilities corresponding to a contact's URI.
  * @hide
  */
+@SystemApi
 public final class RcsContactUceCapability implements Parcelable {
 
     /** Contains presence information associated with the contact */
@@ -70,52 +72,46 @@
     public @interface SourceType {}
 
     /**
+     * Capability information for the requested contact has expired and can not be refreshed due to
+     * a temporary network error. This is a temporary error and the capabilities of the contact
+     * should be queried again at a later time.
+     */
+    public static final int REQUEST_RESULT_UNKNOWN = 0;
+
+    /**
      * The requested contact was found to be offline when queried. This is only applicable to
      * contact capabilities that were queried via OPTIONS requests and the network returned a
      * 408/480 response.
      */
-    public static final int REQUEST_RESULT_NOT_ONLINE = 0;
+    public static final int REQUEST_RESULT_NOT_ONLINE = 1;
 
     /**
      * Capability information for the requested contact was not found. The contact should not be
      * considered an RCS user.
      */
-    public static final int REQUEST_RESULT_NOT_FOUND = 1;
+    public static final int REQUEST_RESULT_NOT_FOUND = 2;
 
     /**
      * Capability information for the requested contact was found successfully.
      */
-    public static final int REQUEST_RESULT_FOUND = 2;
-
-    /**
-     * Capability information for the requested contact has expired and can not be refreshed due to
-     * a temporary network error. This is a temporary error and the capabilities of the contact
-     * should be queried again at a later time.
-     */
-    public static final int REQUEST_RESULT_UNKNOWN = 3;
+    public static final int REQUEST_RESULT_FOUND = 3;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "REQUEST_RESULT_", value = {
+        REQUEST_RESULT_UNKNOWN,
         REQUEST_RESULT_NOT_ONLINE,
         REQUEST_RESULT_NOT_FOUND,
-        REQUEST_RESULT_FOUND,
-        REQUEST_RESULT_UNKNOWN
+        REQUEST_RESULT_FOUND
     })
     public @interface RequestResult {}
 
     /**
-     * The base class of {@link OptionsBuilder} and {@link PresenceBuilder}
-     */
-    public static abstract class RcsUcsCapabilityBuilder {
-        public abstract @NonNull RcsContactUceCapability build();
-    }
-
-    /**
      * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
      * queried through SIP OPTIONS.
+     * @hide
      */
-    public static class OptionsBuilder extends RcsUcsCapabilityBuilder {
+    public static final class OptionsBuilder {
 
         private final RcsContactUceCapability mCapabilities;
 
@@ -162,7 +158,6 @@
         /**
          * @return the constructed instance.
          */
-        @Override
         public @NonNull RcsContactUceCapability build() {
             return mCapabilities;
         }
@@ -172,7 +167,7 @@
      * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
      * queried through a presence server.
      */
-    public static class PresenceBuilder extends RcsUcsCapabilityBuilder {
+    public static final class PresenceBuilder {
 
         private final RcsContactUceCapability mCapabilities;
 
@@ -214,7 +209,6 @@
         /**
          * @return the RcsContactUceCapability instance.
          */
-        @Override
         public @NonNull RcsContactUceCapability build() {
             return mCapabilities;
         }
@@ -284,6 +278,7 @@
      * <p>
      * Note: this is only populated if {@link #getCapabilityMechanism} is
      * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
+     * @hide
      */
     public @NonNull List<String> getOptionsFeatureTags() {
         if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
@@ -299,7 +294,7 @@
      * Note: this is only populated if {@link #getCapabilityMechanism} is
      * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
      */
-    public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() {
+    public @NonNull List<RcsContactPresenceTuple> getCapabilityTuples() {
         if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
             return Collections.emptyList();
         }
@@ -309,13 +304,14 @@
     /**
      * Get the RcsContactPresenceTuple associated with the given service id.
      * @param serviceId The service id to get the presence tuple.
-     * @return The RcsContactPresenceTuple which has the given service id.
+     * @return The RcsContactPresenceTuple which has the given service id or {@code null} if the
+     * service id does not exist in the list of presence tuples returned from the network.
      *
      * <p>
      * Note: this is only populated if {@link #getCapabilityMechanism} is
      * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
      */
-    public @Nullable RcsContactPresenceTuple getPresenceTuple(@NonNull String serviceId) {
+    public @Nullable RcsContactPresenceTuple getCapabilityTuple(@NonNull String serviceId) {
         if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
             return null;
         }
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 6c31466..070fd799 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -63,6 +63,7 @@
      * RcsFeature should not publish capabilities or service capability requests.
      * @hide
      */
+    @SystemApi
     public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
 
     /**@hide*/
@@ -77,12 +78,14 @@
      * An unknown error has caused the request to fail.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_GENERIC_FAILURE = 1;
 
     /**
      * The carrier network does not have UCE support enabled for this subscriber.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_NOT_ENABLED = 2;
 
     /**
@@ -90,12 +93,14 @@
      * 1x only currently).
      * @hide
      */
+    @SystemApi
     public static final int ERROR_NOT_AVAILABLE = 3;
 
     /**
      * The network has responded with SIP 403 error and a reason "User not registered."
      * @hide
      */
+    @SystemApi
     public static final int ERROR_NOT_REGISTERED = 4;
 
     /**
@@ -103,12 +108,14 @@
      * presence" for this subscriber.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_NOT_AUTHORIZED = 5;
 
     /**
      * The network has responded to this request with a SIP 403 error and no reason.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_FORBIDDEN = 6;
 
     /**
@@ -116,6 +123,7 @@
      * subscriber to the carrier network.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_NOT_FOUND = 7;
 
     /**
@@ -123,6 +131,7 @@
      * with a lower number of contact numbers. The number varies per carrier.
      * @hide
      */
+    @SystemApi
     // TODO: Try to integrate this into the API so that the service will split based on carrier.
     public static final int ERROR_REQUEST_TOO_LARGE = 8;
 
@@ -130,18 +139,21 @@
      * The network did not respond to the capabilities request before the request timed out.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_REQUEST_TIMEOUT = 9;
 
     /**
      * The request failed due to the service having insufficient memory.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_INSUFFICIENT_MEMORY = 10;
 
     /**
      * The network was lost while trying to complete the request.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_LOST_NETWORK = 11;
 
     /**
@@ -149,6 +161,7 @@
      * time returned in {@link CapabilitiesCallback#onError} has elapsed.
      * @hide
      */
+    @SystemApi
     public static final int ERROR_SERVER_UNAVAILABLE = 12;
 
     /**@hide*/
@@ -405,6 +418,7 @@
      * @see #requestCapabilities(Executor, List, CapabilitiesCallback)
      * @hide
      */
+    @SystemApi
     public interface CapabilitiesCallback {
 
         /**
@@ -424,10 +438,10 @@
          * The pending request has resulted in an error and may need to be retried, depending on the
          * error code.
          * @param errorCode The reason for the framework being unable to process the request.
-         * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+         * @param retryIntervalMillis The time in milliseconds the requesting application should
          * wait before retrying, if non-zero.
          */
-        void onError(@ErrorCode int errorCode, long retryAfterMilliseconds);
+        void onError(@ErrorCode int errorCode, long retryIntervalMillis);
     }
 
     private final Context mContext;
@@ -458,9 +472,9 @@
      * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
      * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
      *
+     * @param contactNumbers A list of numbers that the capabilities are being requested for.
      * @param executor The executor that will be used when the request is completed and the
      *         {@link CapabilitiesCallback} is called.
-     * @param contactNumbers A list of numbers that the capabilities are being requested for.
      * @param c A one-time callback for when the request for capabilities completes or there is an
      *         error processing the request.
      * @throws ImsException if the subscription associated with this instance of
@@ -469,9 +483,10 @@
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
-            @NonNull List<Uri> contactNumbers,
+    public void requestCapabilities(@NonNull List<Uri> contactNumbers,
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull CapabilitiesCallback c) throws ImsException {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
@@ -495,8 +510,7 @@
             public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
                 final long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    executor.execute(() ->
-                            c.onCapabilitiesReceived(contactCapabilities));
+                    executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
@@ -550,13 +564,17 @@
      * {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
      *
      * @param contactNumber The contact of the capabilities is being requested for.
+     * @param executor The executor that will be used when the request is completed and the
+     * {@link CapabilitiesCallback} is called.
      * @param c A one-time callback for when the request for capabilities completes or there is
      * an error processing the request.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
-    public void requestNetworkAvailability(@NonNull @CallbackExecutor Executor executor,
-            @NonNull Uri contactNumber, @NonNull CapabilitiesCallback c) throws ImsException {
+    public void requestAvailability(@NonNull Uri contactNumber,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull CapabilitiesCallback c) throws ImsException {
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
@@ -569,7 +587,7 @@
 
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
-            Log.e(TAG, "requestNetworkAvailability: IImsRcsController is null");
+            Log.e(TAG, "requestAvailability: IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -579,8 +597,7 @@
             public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
                 final long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    executor.execute(() ->
-                            c.onCapabilitiesReceived(contactCapabilities));
+                    executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
@@ -606,12 +623,12 @@
         };
 
         try {
-            imsRcsController.requestNetworkAvailability(mSubId, mContext.getOpPackageName(),
+            imsRcsController.requestAvailability(mSubId, mContext.getOpPackageName(),
                     mContext.getAttributionTag(), contactNumber, internalCallback);
         } catch (ServiceSpecificException e) {
             throw new ImsException(e.toString(), e.errorCode);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#requestNetworkAvailability", e);
+            Log.e(TAG, "Error calling IImsRcsController#requestAvailability", e);
             throw new ImsException("Remote IMS Service is not available",
                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -683,7 +700,7 @@
         if (imsRcsController == null) {
             Log.e(TAG, "addOnPublishStateChangedListener : IImsRcsController is null");
             throw new ImsException("Cannot find remote IMS service",
-                ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
 
         PublishStateCallbackAdapter stateCallback = addPublishStateCallback(executor, listener);
@@ -694,7 +711,7 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e);
             throw new ImsException("Remote IMS Service is not available",
-                ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
index eddbb10..8762b6a 100644
--- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -280,6 +280,12 @@
             "sip_config_path_header_string";
 
     /**
+     * The SIP User-Agent header value used by the IMS stack during IMS registration.
+     */
+    public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING =
+            "sip_config_sip_user_agent_header_string";
+
+    /**
      * SIP User part string in contact header
      */
     public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING =
@@ -292,12 +298,20 @@
             "sip_config_p_access_network_info_header_string";
 
     /**
-     * SIP P-last-access-network-info header string
+     * The SIP P-last-access-network-info header value, populated for networks that require this
+     * information to be provided in outgoing SIP messages.
      */
     public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING =
             "sip_config_p_last_access_network_info_header_string";
 
     /**
+     * The Cellular-Network-Info header value (See 3GPP 24.229, section 7.2.15), populated for
+     * networks that require this information to be provided as part of outgoing SIP messages.
+     */
+    public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING =
+            "sip_config_cellular_network_info_header_string";
+
+    /**
      * SIP P-associated-uri header string
      */
     public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING =
@@ -320,9 +334,11 @@
             KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING,
             KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING,
             KEY_SIP_CONFIG_PATH_HEADER_STRING,
+            KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING,
             KEY_SIP_CONFIG_URI_USER_PART_STRING,
             KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING,
             KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING,
+            KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING,
             KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING
     })
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 3634989..7a6c28b 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -52,7 +52,7 @@
     // ImsUceAdapter specific
     void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
             in List<Uri> contactNumbers, IRcsUceControllerCallback c);
-    void requestNetworkAvailability(int subId, String callingPackage,
+    void requestAvailability(int subId, String callingPackage,
             String callingFeatureId, in Uri contactNumber,
             IRcsUceControllerCallback c);
     int getUcePublishState(int subId);
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 06c35ea..2e35d27 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -23,6 +23,8 @@
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsEcbmListener;
 
+import java.util.Objects;
+
 /**
  * Base implementation of ImsEcbm, which implements stub versions of the methods
  * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
@@ -36,11 +38,27 @@
 public class ImsEcbmImplBase {
     private static final String TAG = "ImsEcbmImplBase";
 
+    private final Object mLock = new Object();
     private IImsEcbmListener mListener;
-    private IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
+    private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
         @Override
         public void setListener(IImsEcbmListener listener) {
-            mListener = listener;
+            synchronized (mLock) {
+                if (mImsEcbm != null && listener != null && Objects.equals(
+                        mImsEcbm.asBinder(), listener.asBinder())) {
+                    return;
+                }
+                if (listener == null) {
+                    mListener = null;
+                } else if (listener != null && mListener == null) {
+                    mListener = listener;
+                } else {
+                    // Fail fast here instead of silently overwriting the listener to another
+                    // listener due to another connection connecting.
+                    throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
+                            + "another connection.");
+                }
+            }
         }
 
         @Override
@@ -69,9 +87,13 @@
      */
     public final void enteredEcbm() {
         Log.d(TAG, "Entered ECBM.");
-        if (mListener != null) {
+        IImsEcbmListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.enteredECBM();
+                listener.enteredECBM();
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -85,9 +107,13 @@
      */
     public final void exitedEcbm() {
         Log.d(TAG, "Exited ECBM.");
-        if (mListener != null) {
+        IImsEcbmListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.exitedECBM();
+                listener.exitedECBM();
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index d002903..555a47e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -25,6 +25,7 @@
 import com.android.ims.internal.IImsMultiEndpoint;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -41,10 +42,28 @@
     private static final String TAG = "MultiEndpointImplBase";
 
     private IImsExternalCallStateListener mListener;
-    private IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+    private final Object mLock = new Object();
+    private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+
         @Override
         public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
-            mListener = listener;
+            synchronized (mLock) {
+                if (mListener != null && listener != null && Objects.equals(
+                        mListener.asBinder(), listener.asBinder())) {
+                    return;
+                }
+
+                if (listener == null) {
+                    mListener = null;
+                } else if (listener != null && mListener == null) {
+                    mListener = listener;
+                } else {
+                    // Fail fast here instead of silently overwriting the listener to another
+                    // listener due to another connection connecting.
+                    throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
+                            + " set by another connection.");
+                }
+            }
         }
 
         @Override
@@ -65,9 +84,13 @@
      */
     public final void onImsExternalCallStateUpdate(List<ImsExternalCallState> externalCallDialogs) {
         Log.d(TAG, "ims external call state update triggered.");
-        if (mListener != null) {
+        IImsExternalCallStateListener listener;
+        synchronized (mLock) {
+            listener = mListener;
+        }
+        if (listener != null) {
             try {
-                mListener.onImsExternalCallStateUpdate(externalCallDialogs);
+                listener.onImsExternalCallStateUpdate(externalCallDialogs);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index f5219d5..eef4fca 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -29,6 +29,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -116,7 +117,10 @@
      */
     public static final int INVALID_RESULT = -1;
 
-    private IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+    private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+        private final Object mLock = new Object();
+        private ImsUtListener mUtListener;
+
         @Override
         public void close() throws RemoteException {
             ImsUtImplBase.this.close();
@@ -202,7 +206,26 @@
 
         @Override
         public void setListener(IImsUtListener listener) throws RemoteException {
-            ImsUtImplBase.this.setListener(new ImsUtListener(listener));
+            synchronized (mLock) {
+                if (mUtListener != null && listener != null && Objects.equals(
+                        mUtListener.getListenerInterface().asBinder(), listener.asBinder())) {
+                    return;
+                }
+
+                if (listener == null) {
+                    mUtListener = null;
+                } else if (listener != null && mUtListener == null) {
+                    mUtListener = new ImsUtListener(listener);
+                } else {
+                    // This is a limitation of the current API surface, there can only be one
+                    // listener connected. Fail fast instead of silently overwriting the other
+                    // listener.
+                    throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
+                            + "set by another connected interface!");
+                }
+            }
+
+            ImsUtImplBase.this.setListener(mUtListener);
         }
 
         @Override
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index c84e23c..7eba709 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
 import android.util.Log;
@@ -139,18 +140,19 @@
          * Provide the framework with a subsequent network response update to
          * {@link #publishCapabilities(String, PublishResponseCallback)}.
          *
-         * @param code The SIP response code sent from the network for the operation
+         * @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
          * included in the response, that should take precedence over the reason provided in the
-         * status line. If the network provided no reason with the code, the string should be empty.
+         * status line. If the network provided no reason with the sip code, the string should be
+         * empty.
          * @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 code,
+        void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
                 @NonNull String reason) throws ImsException;
     }
 
@@ -173,7 +175,7 @@
 
         /**
          * Send the response of a SIP OPTIONS capability exchange to the framework.
-         * @param code The SIP response code that was sent by the network in response
+         * @param sipCode The SIP response code that was sent by the network in response
          * to the request sent by {@link #sendOptionsCapabilityRequest}.
          * @param reason The optional SIP response reason sent by the network.
          * If none was sent, this should be an empty string.
@@ -186,17 +188,20 @@
          * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
          * cases when the Telephony stack has crashed.
          */
-        void onNetworkResponse(int code, @NonNull String reason,
+        void onNetworkResponse(int sipCode, @NonNull String reason,
                 @Nullable List<String> theirCaps) throws ImsException;
     }
 
     /**
      * Interface used by the framework to receive the response of the subscribe request.
-     * @hide
      */
     public interface SubscribeResponseCallback {
         /**
          * Notify the framework that the command associated with this callback has failed.
+         * <p>
+         * Must only be called when there was an error generating a SUBSCRIBE request due to an
+         * IMS stack error. This is a terminating event, so no other callback event will be
+         * expected after this callback.
          *
          * @param code The reason why the associated command has failed.
          * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
@@ -211,27 +216,38 @@
         /**
          * Notify the framework of the response to the SUBSCRIBE request from
          * {@link #subscribeForCapabilities(List<Uri>, 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.
          *
-         * @param code The SIP response code sent from the network for the operation
+         * @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
-         *  provided no reason with the code, the string should be empty.
+         *  provided no reason with the sip code, the string should be empty.
          * @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 code,
+        void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
                 @NonNull String reason) throws ImsException;
 
         /**
-         * Provides the framework with latest XML PIDF documents included in the
-         * network response for the requested  contacts' capabilities requested by the
-         * Framework using {@link #requestCapabilities(List, int)}. This should be
-         * called every time a new NOTIFY event is received with new capability
-         * information.
+         * 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)}.
+         * <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
+         * responses that contain RLMI information and potentially multiple PIDF XMLs, each
+         * PIDF XML should be separated and added as a separate item in the List. This should be
+         * called every time a new NOTIFY event is received with new capability information.
          *
+         * @param pidfXmls The list of the PIDF XML data for the contact URIs that it subscribed
+         * for.
          * @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
@@ -242,21 +258,42 @@
         void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException;
 
         /**
-         * A resource in the resource list for the presence subscribe event has been terminated.
+         * Notify the framework that a resource in the RLMI XML contained in the NOTIFY response
+         * for the ongoing SUBSCRIBE dialog has been terminated.
          * <p>
-         * This allows the framework to know that there will not be any capability information for
-         * a specific contact URI that they subscribed for.
+         * This will be used to notify the framework that a contact URI that the IMS stack has
+         * subscribed to on the Resource List Server has been terminated as well as the reason why.
+         * Usually this means that there will not be any capability information for the contact URI
+         * that they subscribed for. See RFC 4662 for more information.
+         *
+         * @param uriTerminatedReason The contact URIs which have been terminated. Each pair in the
+         * list is the contact URI and its terminated reason.
+         * @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} {@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 onResourceTerminated(
                 @NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException;
 
         /**
-         * The subscription associated with a previous #requestCapabilities operation
-         * has been terminated. This will mostly be due to the subscription expiring,
-         * but may also happen due to an error.
-         * <p>
-         * This allows the framework to know that there will no longer be any
-         * capability updates for the requested operationToken.
+         * The subscription associated with a previous
+         * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, 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.
+         *
+         * @param reason The reason for the request being unable to process.
+         * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+         * wait before retrying, if non-zero.
+         * @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} {@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 onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException;
     }
@@ -278,18 +315,23 @@
     /**
      * The user capabilities of one or multiple contacts have been requested by the framework.
      * <p>
+     * The implementer must follow up this call with an
+     * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
      * The response from the network to the SUBSCRIBE request must be sent back to the framework
-     * using {@link #onSubscribeNetworkResponse(int, String, int)}. As NOTIFY requests come in from
-     * the network, the requested contact’s capabilities should be sent back to the framework using
-     * {@link #onSubscribeNotifyRequest} and {@link onSubscribeResourceTerminated}
+     * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
+     * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
+     * sent back to the framework using
+     * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
+     * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
      * should be called with the presence information for the contacts specified.
      * <p>
-     * Once the subscription is terminated, {@link #onSubscriptionTerminated} must be called for
-     * the framework to finish listening for NOTIFY responses.
+     * Once the subscription is terminated,
+     * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
+     * framework to finish listening for NOTIFY responses.
+     *
      * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
      * capabilities for.
      * @param cb The callback of the subscribe request.
-     * @hide
      */
     // executor used is defined in the constructor.
     @SuppressLint("ExecutorRegistration")
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e556664..77d46f4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2382,6 +2382,26 @@
      */
     String getMobileProvisioningUrl();
 
+    /*
+     * Remove the EAB contacts from the EAB database.
+     */
+    int removeContactFromEab(int subId, String contacts);
+
+    /**
+     * Get the EAB contact from the EAB database.
+     */
+    String getContactFromEab(String contact);
+
+    /*
+     * Check whether the device supports RCS User Capability Exchange or not.
+     */
+    boolean getDeviceUceEnabled();
+
+    /*
+     * Set the device supports RCS User Capability Exchange.
+     */
+     void setDeviceUceEnabled(boolean isEnabled);
+
     /**
      * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
      * specified thresholds.
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index ef973ac..861d221 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -182,6 +182,24 @@
 
     @SmallTest
     @Test
+    public void setFunctionsNcmAndRndis() {
+        final long rndisPlusNcm = UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM;
+
+        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+                UsbManager.FUNCTION_NCM));
+        assertEquals(UsbManager.FUNCTION_NCM, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+
+        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+                rndisPlusNcm));
+        assertEquals(rndisPlusNcm, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+
+        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+                UsbManager.FUNCTION_NCM));
+        assertEquals(UsbManager.FUNCTION_NCM, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+    }
+
+    @SmallTest
+    @Test
     public void enableAdb() {
         sendBootCompleteMessages(mUsbHandler);
         Message msg = mUsbHandler.obtainMessage(MSG_ENABLE_ADB);
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java b/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
index a0fd9d4..b8bd98e 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import static org.junit.Assert.assertEquals;
+
 import android.content.Context;
 import android.hardware.usb.UsbManager;
 
@@ -23,12 +25,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.usblib.UsbManagerTestLib;
+
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import com.android.server.usblib.UsbManagerTestLib;
-
 /**
  * Unit tests for {@link android.hardware.usb.UsbManager}.
  * Note: NOT claimed MANAGE_USB permission in Manifest
@@ -78,4 +80,35 @@
     public void testUsbApi_SetCurrentFunctions_OnSecurityException() throws Exception {
         mUsbManagerTestLib.testSetCurrentFunctionsEx(UsbManager.FUNCTION_NONE);
     }
+
+    public void assertSettableFunctions(boolean settable, long functions) {
+        assertEquals(
+                "areSettableFunctions(" + UsbManager.usbFunctionsToString(functions) + "):",
+                settable, UsbManager.areSettableFunctions(functions));
+    }
+
+    /**
+     * Tests the behaviour of the static areSettableFunctions method. This method performs no IPCs
+     * and requires no permissions.
+     */
+    @Test
+    public void testUsbManager_AreSettableFunctions() {
+        // NONE is settable.
+        assertSettableFunctions(true, UsbManager.FUNCTION_NONE);
+
+        // MTP, PTP, RNDIS, MIDI, NCM are all settable by themselves.
+        assertSettableFunctions(true, UsbManager.FUNCTION_MTP);
+        assertSettableFunctions(true, UsbManager.FUNCTION_PTP);
+        assertSettableFunctions(true, UsbManager.FUNCTION_RNDIS);
+        assertSettableFunctions(true, UsbManager.FUNCTION_MIDI);
+        assertSettableFunctions(true, UsbManager.FUNCTION_NCM);
+
+        // Setting two functions at the same time is not allowed...
+        assertSettableFunctions(false, UsbManager.FUNCTION_MTP | UsbManager.FUNCTION_PTP);
+        assertSettableFunctions(false, UsbManager.FUNCTION_PTP | UsbManager.FUNCTION_RNDIS);
+        assertSettableFunctions(false, UsbManager.FUNCTION_MIDI | UsbManager.FUNCTION_NCM);
+
+        // ... except in the special case of RNDIS and NCM.
+        assertSettableFunctions(true, UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM);
+    }
 }
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index f6a2846..ffde68e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -36,7 +36,7 @@
         "libvndksupport",
         "libziparchive",
         "libz",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V5-cpp",
     ],
 }
 
@@ -53,6 +53,7 @@
     jarjar_rules: "jarjar-rules.txt",
     static_libs: [
         "androidx.test.rules",
+        "bouncycastle-repackaged-unbundled",
         "FrameworksNetCommonTests",
         "frameworks-base-testutils",
         "frameworks-net-integration-testutils",
diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
new file mode 100644
index 0000000..87cfb34
--- /dev/null
+++ b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
@@ -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 android.net
+
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+private const val TEST_OWNER_UID = 123
+private const val TEST_IFACE = "test_tun0"
+private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class UnderlyingNetworkInfoTest {
+    @Test
+    fun testParcelUnparcel() {
+        val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
+        assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
+        assertEquals(TEST_IFACE, testInfo.iface)
+        assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
+        assertParcelSane(testInfo, 3)
+
+        val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
+        assertEquals(0, emptyInfo.ownerUid)
+        assertEquals(String(), emptyInfo.iface)
+        assertEquals(listOf(), emptyInfo.underlyingIfaces)
+        assertParcelSane(emptyInfo, 3)
+    }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index f2dd27e..c2fddf3 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -32,6 +32,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
 
@@ -368,6 +369,12 @@
                 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
                 eq(testPkgName), eq(null));
         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));
+        reset(mService);
     }
 
     static Message makeMessage(NetworkRequest req, int messageType) {
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index 076e41d..1abd39a 100644
--- a/tests/net/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -30,7 +30,7 @@
 
 import com.android.internal.net.VpnProfile;
 import com.android.net.module.util.ProxyUtils;
-import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
+import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ca73689..b0cc7f1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -64,6 +64,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 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_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
@@ -131,6 +132,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
@@ -200,8 +202,8 @@
 import android.net.SocketKeepalive;
 import android.net.UidRange;
 import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
-import android.net.VpnInfo;
 import android.net.VpnManager;
 import android.net.metrics.IpConnectivityLog;
 import android.net.shared.NetworkMonitorUtils;
@@ -251,6 +253,7 @@
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.net.module.util.ArrayTrackRecord;
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
 import com.android.server.connectivity.ConnectivityConstants;
 import com.android.server.connectivity.MockableSystemProperties;
@@ -379,6 +382,10 @@
     private QosCallbackMockHelper mQosCallbackMockHelper;
     private QosCallbackTracker mQosCallbackTracker;
 
+    // State variables required to emulate NetworkPolicyManagerService behaviour.
+    private int mUidRules = RULE_NONE;
+    private boolean mRestrictBackground = false;
+
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
@@ -901,28 +908,69 @@
     }
 
     /**
-     * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
-     * operations have been processed. Before ConnectivityService can add or remove any requests,
-     * the factory must be told to expect those operations by calling expectAddRequestsWithScores or
-     * expectRemoveRequests.
+     * A NetworkFactory that allows to wait until any in-flight NetworkRequest add or remove
+     * operations have been processed and test for them.
      */
     private static class MockNetworkFactory extends NetworkFactory {
         private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
         private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
         private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
 
-        // Used to expect that requests be removed or added on a separate thread, without sleeping.
-        // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly
-        // once, then cause some other thread to add or remove requests, then call
-        // waitForRequests().
-        // It is not possible to wait for both add and remove requests. When adding, the queue
-        // contains the expected score. When removing, the value is unused, all matters is the
-        // number of objects in the queue.
-        private final LinkedBlockingQueue<Integer> mExpectations;
+        static class RequestEntry {
+            @NonNull
+            public final NetworkRequest request;
 
-        // Whether we are currently expecting requests to be added or removed. Valid only if
-        // mExpectations is non-empty.
-        private boolean mExpectingAdditions;
+            RequestEntry(@NonNull final NetworkRequest request) {
+                this.request = request;
+            }
+
+            static final class Add extends RequestEntry {
+                public final int factorySerialNumber;
+
+                Add(@NonNull final NetworkRequest request, final int factorySerialNumber) {
+                    super(request);
+                    this.factorySerialNumber = factorySerialNumber;
+                }
+            }
+
+            static final class Remove extends RequestEntry {
+                Remove(@NonNull final NetworkRequest request) {
+                    super(request);
+                }
+            }
+        }
+
+        // History of received requests adds and removes.
+        private final ArrayTrackRecord<RequestEntry>.ReadHead mRequestHistory =
+                new ArrayTrackRecord<RequestEntry>().newReadHead();
+
+        private static <T> T failIfNull(@Nullable final T obj, @Nullable final String message) {
+            if (null == obj) fail(null != message ? message : "Must not be null");
+            return obj;
+        }
+
+
+        public RequestEntry.Add expectRequestAdd() {
+            return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
+                    it -> it instanceof RequestEntry.Add), "Expected request add");
+        }
+
+        public void expectRequestAdds(final int count) {
+            for (int i = count; i > 0; --i) {
+                expectRequestAdd();
+            }
+        }
+
+        public RequestEntry.Remove expectRequestRemove() {
+            return failIfNull((RequestEntry.Remove) mRequestHistory.poll(TIMEOUT_MS,
+                    it -> it instanceof RequestEntry.Remove), "Expected request remove");
+        }
+
+        public void expectRequestRemoves(final int count) {
+            for (int i = count; i > 0; --i) {
+                expectRequestRemove();
+            }
+        }
 
         // 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).
@@ -931,7 +979,6 @@
         public MockNetworkFactory(Looper looper, Context context, String logTag,
                 NetworkCapabilities filter) {
             super(looper, context, logTag, filter);
-            mExpectations = new LinkedBlockingQueue<>();
         }
 
         public int getMyRequestCount() {
@@ -965,95 +1012,33 @@
         @Override
         protected void handleAddRequest(NetworkRequest request, int score,
                 int factorySerialNumber) {
-            synchronized (mExpectations) {
-                final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
-
-                assertNotNull("Added more requests than expected (" + request + " score : "
-                        + score + ")", expectedScore);
-                // If we're expecting anything, we must be expecting additions.
-                if (!mExpectingAdditions) {
-                    fail("Can't add requests while expecting requests to be removed");
-                }
-                if (expectedScore != score) {
-                    fail("Expected score was " + expectedScore + " but actual was " + score
-                            + " in added request");
-                }
-
-                // Add the request.
-                mNetworkRequests.put(request.requestId, request);
-                super.handleAddRequest(request, score, factorySerialNumber);
-                mExpectations.notify();
-            }
+            mNetworkRequests.put(request.requestId, request);
+            super.handleAddRequest(request, score, factorySerialNumber);
+            mRequestHistory.add(new RequestEntry.Add(request, factorySerialNumber));
         }
 
         @Override
         protected void handleRemoveRequest(NetworkRequest request) {
-            synchronized (mExpectations) {
-                final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
+            mNetworkRequests.remove(request.requestId);
+            super.handleRemoveRequest(request);
+            mRequestHistory.add(new RequestEntry.Remove(request));
+        }
 
-                assertTrue("Removed more requests than expected", expectedScore != null);
-                // If we're expecting anything, we must be expecting removals.
-                if (mExpectingAdditions) {
-                    fail("Can't remove requests while expecting requests to be added");
-                }
+        public void assertRequestCountEquals(final int count) {
+            assertEquals(count, getMyRequestCount());
+        }
 
-                // Remove the request.
-                mNetworkRequests.remove(request.requestId);
-                super.handleRemoveRequest(request);
-                mExpectations.notify();
-            }
+        @Override
+        public void terminate() {
+            super.terminate();
+            // Make sure there are no remaining requests unaccounted for.
+            assertNull(mRequestHistory.poll(TIMEOUT_MS, r -> true));
         }
 
         // Trigger releasing the request as unfulfillable
         public void triggerUnfulfillable(NetworkRequest r) {
             super.releaseRequestAsUnfulfillableByAnyFactory(r);
         }
-
-        private void assertNoExpectations() {
-            if (mExpectations.size() != 0) {
-                fail("Can't add expectation, " + mExpectations.size() + " already pending");
-            }
-        }
-
-        // Expects that requests with the specified scores will be added.
-        public void expectAddRequestsWithScores(final int... scores) {
-            assertNoExpectations();
-            mExpectingAdditions = true;
-            for (int score : scores) {
-                mExpectations.add(score);
-            }
-        }
-
-        // Expects that count requests will be removed.
-        public void expectRemoveRequests(final int count) {
-            assertNoExpectations();
-            mExpectingAdditions = false;
-            for (int i = 0; i < count; ++i) {
-                mExpectations.add(0); // For removals the score is ignored so any value will do.
-            }
-        }
-
-        // Waits for the expected request additions or removals to happen within a timeout.
-        public void waitForRequests() throws InterruptedException {
-            final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS;
-            synchronized (mExpectations) {
-                while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) {
-                    mExpectations.wait(deadline - SystemClock.elapsedRealtime());
-                }
-            }
-            final long count = mExpectations.size();
-            final String msg = count + " requests still not " +
-                    (mExpectingAdditions ? "added" : "removed") +
-                    " after " + TIMEOUT_MS + " ms";
-            assertEquals(msg, 0, count);
-        }
-
-        public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
-                throws InterruptedException {
-            waitForRequests();
-            assertEquals(count, getMyRequestCount());
-            return mNetworkRequests;
-        }
     }
 
     private Set<UidRange> uidRangesForUid(int uid) {
@@ -1075,7 +1060,7 @@
         private boolean mAgentRegistered = false;
 
         private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
-        private VpnInfo mVpnInfo;
+        private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
 
         // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
         // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
@@ -1249,14 +1234,15 @@
         }
 
         @Override
-        public synchronized VpnInfo getVpnInfo() {
-            if (mVpnInfo != null) return mVpnInfo;
+        public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
+            if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
 
-            return super.getVpnInfo();
+            return super.getUnderlyingNetworkInfo();
         }
 
-        private synchronized void setVpnInfo(VpnInfo vpnInfo) {
-            mVpnInfo = vpnInfo;
+        private synchronized void setUnderlyingNetworkInfo(
+                UnderlyingNetworkInfo underlyingNetworkInfo) {
+            mUnderlyingNetworkInfo = underlyingNetworkInfo;
         }
     }
 
@@ -1276,12 +1262,23 @@
         }
     }
 
+    private void updateUidNetworkingBlocked() {
+        doAnswer(i -> NetworkPolicyManagerInternal.isUidNetworkingBlocked(
+                i.getArgument(0) /* uid */, mUidRules, i.getArgument(1) /* metered */,
+                mRestrictBackground)
+        ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
+    }
+
     private void setUidRulesChanged(int uidRules) throws RemoteException {
-        mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+        mUidRules = uidRules;
+        updateUidNetworkingBlocked();
+        mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
     }
 
     private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
-        mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+        mRestrictBackground = restrictBackground;
+        updateUidNetworkingBlocked();
+        mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
     }
 
     private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -2578,12 +2575,6 @@
         callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
     }
 
-    private int[] makeIntArray(final int size, final int value) {
-        final int[] array = new int[size];
-        Arrays.fill(array, value);
-        return array;
-    }
-
     private void tryNetworkFactoryRequests(int capability) throws Exception {
         // Verify NOT_RESTRICTED is set appropriately
         final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
@@ -2605,9 +2596,9 @@
                 mServiceContext, "testFactory", filter);
         testFactory.setScoreFilter(40);
         ConditionVariable cv = testFactory.getNetworkStartedCV();
-        testFactory.expectAddRequestsWithScores(0);
         testFactory.register();
-        testFactory.waitForNetworkRequests(1);
+        testFactory.expectRequestAdd();
+        testFactory.assertRequestCountEquals(1);
         int expectedRequestCount = 1;
         NetworkCallback networkCallback = null;
         // For non-INTERNET capabilities we cannot rely on the default request being present, so
@@ -2616,13 +2607,12 @@
             assertFalse(testFactory.getMyStartRequested());
             NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
             networkCallback = new NetworkCallback();
-            testFactory.expectAddRequestsWithScores(0);  // New request
             mCm.requestNetwork(request, networkCallback);
             expectedRequestCount++;
-            testFactory.waitForNetworkRequests(expectedRequestCount);
+            testFactory.expectRequestAdd();
         }
         waitFor(cv);
-        assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+        testFactory.assertRequestCountEquals(expectedRequestCount);
         assertTrue(testFactory.getMyStartRequested());
 
         // Now bring in a higher scored network.
@@ -2636,15 +2626,14 @@
         // When testAgent connects, ConnectivityService will re-send us all current requests with
         // the new score. There are expectedRequestCount such requests, and we must wait for all of
         // them.
-        testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50));
         testAgent.connect(false);
         testAgent.addCapability(capability);
         waitFor(cv);
-        testFactory.waitForNetworkRequests(expectedRequestCount);
+        testFactory.expectRequestAdds(expectedRequestCount);
+        testFactory.assertRequestCountEquals(expectedRequestCount);
         assertFalse(testFactory.getMyStartRequested());
 
         // Bring in a bunch of requests.
-        testFactory.expectAddRequestsWithScores(makeIntArray(10, 50));
         assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
         ConnectivityManager.NetworkCallback[] networkCallbacks =
                 new ConnectivityManager.NetworkCallback[10];
@@ -2654,24 +2643,24 @@
             builder.addCapability(capability);
             mCm.requestNetwork(builder.build(), networkCallbacks[i]);
         }
-        testFactory.waitForNetworkRequests(10 + expectedRequestCount);
+        testFactory.expectRequestAdds(10);
+        testFactory.assertRequestCountEquals(10 + expectedRequestCount);
         assertFalse(testFactory.getMyStartRequested());
 
         // Remove the requests.
-        testFactory.expectRemoveRequests(10);
         for (int i = 0; i < networkCallbacks.length; i++) {
             mCm.unregisterNetworkCallback(networkCallbacks[i]);
         }
-        testFactory.waitForNetworkRequests(expectedRequestCount);
+        testFactory.expectRequestRemoves(10);
+        testFactory.assertRequestCountEquals(expectedRequestCount);
         assertFalse(testFactory.getMyStartRequested());
 
         // Drop the higher scored network.
         cv = testFactory.getNetworkStartedCV();
-        // With the default network disconnecting, the requests are sent with score 0 to factories.
-        testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0));
         testAgent.disconnect();
         waitFor(cv);
-        testFactory.waitForNetworkRequests(expectedRequestCount);
+        testFactory.expectRequestAdds(expectedRequestCount);
+        testFactory.assertRequestCountEquals(expectedRequestCount);
         assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
         assertTrue(testFactory.getMyStartRequested());
 
@@ -2714,9 +2703,8 @@
             final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
                     mServiceContext, "testFactory", filter);
             // Register the factory and don't be surprised when the default request arrives.
-            testFactory.expectAddRequestsWithScores(0);
             testFactory.register();
-            testFactory.waitForNetworkRequests(1);
+            testFactory.expectRequestAdd();
 
             testFactory.setScoreFilter(42);
             testFactory.terminate();
@@ -3692,10 +3680,13 @@
 
     @Test
     public void testBackgroundNetworks() throws Exception {
-        // Create a background request. We can't do this ourselves because ConnectivityService
-        // doesn't have an API for it. So just turn on mobile data always on.
-        setAlwaysOnNetworks(true);
+        // Create a cellular background request.
         grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+        final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
+        mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+
+        // Make callbacks for monitoring.
         final NetworkRequest request = new NetworkRequest.Builder().build();
         final NetworkRequest fgRequest = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -3764,6 +3755,7 @@
 
         mCm.unregisterNetworkCallback(callback);
         mCm.unregisterNetworkCallback(fgCallback);
+        mCm.unregisterNetworkCallback(cellBgCallback);
     }
 
     @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
@@ -3855,38 +3847,37 @@
         testFactory.setScoreFilter(40);
 
         // Register the factory and expect it to start looking for a network.
-        testFactory.expectAddRequestsWithScores(0);  // Score 0 as the request is not served yet.
         testFactory.register();
 
         try {
-            testFactory.waitForNetworkRequests(1);
+            testFactory.expectRequestAdd();
+            testFactory.assertRequestCountEquals(1);
             assertTrue(testFactory.getMyStartRequested());
 
             // Bring up wifi. The factory stops looking for a network.
             mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
             // Score 60 - 40 penalty for not validated yet, then 60 when it validates
-            testFactory.expectAddRequestsWithScores(20, 60);
             mWiFiNetworkAgent.connect(true);
-            testFactory.waitForRequests();
+            // Default request and mobile always on request
+            testFactory.expectRequestAdds(2);
             assertFalse(testFactory.getMyStartRequested());
 
-            ContentResolver cr = mServiceContext.getContentResolver();
-
             // Turn on mobile data always on. The factory starts looking again.
-            testFactory.expectAddRequestsWithScores(0);  // Always on requests comes up with score 0
             setAlwaysOnNetworks(true);
-            testFactory.waitForNetworkRequests(2);
+            testFactory.expectRequestAdd();
+            testFactory.assertRequestCountEquals(2);
+
             assertTrue(testFactory.getMyStartRequested());
 
             // Bring up cell data and check that the factory stops looking.
             assertLength(1, mCm.getAllNetworks());
             mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-            testFactory.expectAddRequestsWithScores(10, 50);  // Unvalidated, then validated
             mCellNetworkAgent.connect(true);
             cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-            testFactory.waitForNetworkRequests(2);
-            assertFalse(
-                    testFactory.getMyStartRequested());  // Because the cell network outscores us.
+            testFactory.expectRequestAdds(2); // Unvalidated and validated
+            testFactory.assertRequestCountEquals(2);
+            // The cell network outscores the factory filter, so start is not requested.
+            assertFalse(testFactory.getMyStartRequested());
 
             // Check that cell data stays up.
             waitForIdle();
@@ -3894,9 +3885,8 @@
             assertLength(2, mCm.getAllNetworks());
 
             // Turn off mobile data always on and expect the request to disappear...
-            testFactory.expectRemoveRequests(1);
             setAlwaysOnNetworks(false);
-            testFactory.waitForNetworkRequests(1);
+            testFactory.expectRequestRemove();
 
             // ...  and cell data to be torn down.
             cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -4203,46 +4193,33 @@
         testFactory.setScoreFilter(40);
 
         // Register the factory and expect it to receive the default request.
-        testFactory.expectAddRequestsWithScores(0);
         testFactory.register();
-        SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
-
-        assertEquals(1, requests.size()); // have 1 request at this point
-        int origRequestId = requests.valueAt(0).requestId;
+        testFactory.expectRequestAdd();
 
         // Now file the test request and expect it.
-        testFactory.expectAddRequestsWithScores(0);
         mCm.requestNetwork(nr, networkCallback);
-        requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
+        final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
 
-        int newRequestId = 0;
-        for (int i = 0; i < requests.size(); ++i) {
-            if (requests.valueAt(i).requestId != origRequestId) {
-                newRequestId = requests.valueAt(i).requestId;
-                break;
-            }
-        }
-
-        testFactory.expectRemoveRequests(1);
         if (preUnregister) {
             mCm.unregisterNetworkCallback(networkCallback);
 
             // Simulate the factory releasing the request as unfulfillable: no-op since
             // the callback has already been unregistered (but a test that no exceptions are
             // thrown).
-            testFactory.triggerUnfulfillable(requests.get(newRequestId));
+            testFactory.triggerUnfulfillable(newRequest);
         } else {
             // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
-            testFactory.triggerUnfulfillable(requests.get(newRequestId));
+            testFactory.triggerUnfulfillable(newRequest);
 
             networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-            testFactory.waitForRequests();
 
             // unregister network callback - a no-op (since already freed by the
             // on-unavailable), but should not fail or throw exceptions.
             mCm.unregisterNetworkCallback(networkCallback);
         }
 
+        testFactory.expectRequestRemove();
+
         testFactory.terminate();
         handlerThread.quit();
     }
@@ -5194,20 +5171,22 @@
     private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
             Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
         ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
-        ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
+        ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
+                UnderlyingNetworkInfo[].class);
 
         verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
                 any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
 
         assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
 
-        VpnInfo[] infos = vpnInfosCaptor.getValue();
+        UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
         if (vpnUid != null) {
             assertEquals("Should have exactly one VPN:", 1, infos.length);
-            VpnInfo info = infos[0];
+            UnderlyingNetworkInfo info = infos[0];
             assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
-            assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
-            assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
+            assertEquals("Unexpected VPN interface:", vpnIfname, info.iface);
+            assertSameElementsNoDuplicates(underlyingIfaces,
+                    info.underlyingIfaces.toArray(new String[0]));
         } else {
             assertEquals(0, infos.length);
             return;
@@ -5268,7 +5247,7 @@
         waitForIdle();
         verify(mStatsService, never())
                 .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
-                        eq(new VpnInfo[0]));
+                        eq(new UnderlyingNetworkInfo[0]));
         reset(mStatsService);
 
         // Roaming change should update ifaces
@@ -5351,8 +5330,8 @@
         // network for the VPN...
         verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
                 any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(infos -> infos[0].underlyingIfaces.length == 1
-                        && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
+                argThat(infos -> infos[0].underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
         verifyNoMoreInteractions(mStatsService);
         reset(mStatsService);
 
@@ -5365,8 +5344,8 @@
         waitForIdle();
         verify(mStatsService).forceUpdateIfaces(any(Network[].class),
                 any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
-                        && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
+                argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
         mEthernetNetworkAgent.disconnect();
         waitForIdle();
         reset(mStatsService);
@@ -5963,23 +5942,18 @@
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
                         && nc.hasTransport(TRANSPORT_WIFI));
-
-        // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent.
-        // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
         callback.assertNoCallback();
 
         assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
                 .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-        // BUG: the device has connectivity, so this should return true.
-        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
 
-        // Unsuspend cellular and then switch back to it.
-        // The same bug happens in the opposite direction: the VPN's capabilities correctly have
-        // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED.
+        // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
         mCellNetworkAgent.resume();
         callback.assertNoCallback();
         mWiFiNetworkAgent.disconnect();
@@ -5996,12 +5970,11 @@
                 .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
-        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
-        // BUG: the device has connectivity, so this should return true.
-        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
 
-        // Re-suspending the current network fixes the problem.
+        // Suspend cellular and expect no connectivity.
         mCellNetworkAgent.suspend();
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
@@ -6017,6 +5990,7 @@
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
         assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
 
+        // Resume cellular and expect that connectivity comes back.
         mCellNetworkAgent.resume();
         callback.expectCapabilitiesThat(mMockVpn,
                 nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
@@ -6407,10 +6381,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-        // While the SUSPENDED callback should in theory be sent here, it is not. This is
-        // a bug in ConnectivityService, but as the SUSPENDED and RESUMED callbacks have never
-        // been public and are deprecated and slated for removal, there is no sense in spending
-        // resources fixing this bug now.
+        vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Use both again.
@@ -6422,8 +6393,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
                 && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-        // As above, the RESUMED callback not being sent here is a bug, but not a bug that's
-        // worth anybody's time to fix.
+        vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
         assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
 
         // Disconnect cell. Receive update without even removing the dead network from the
@@ -6843,9 +6813,15 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_REJECT_ALL);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
 
         // ConnectivityService should cache it not to invoke the callback again.
         setUidRulesChanged(RULE_REJECT_METERED);
@@ -6853,32 +6829,60 @@
 
         setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
 
         // Restrict the network based on UID rule and NOT_METERED capability change.
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
                 mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+
         setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.assertNoCallback();
 
-        // Restrict the network based on BackgroundRestricted.
+        // Restrict background data. Networking is not blocked because the network is unmetered.
         setRestrictBackgroundChanged(true);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        assertNull(mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         setRestrictBackgroundChanged(true);
         cellNetworkCallback.assertNoCallback();
-        setRestrictBackgroundChanged(false);
+
+        setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+
+        setRestrictBackgroundChanged(false);
         cellNetworkCallback.assertNoCallback();
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
 
         mCm.unregisterNetworkCallback(cellNetworkCallback);
     }
@@ -7335,39 +7339,68 @@
         b2.expectBroadcast();
     }
 
+    /**
+     * Test mutable and requestable network capabilities such as
+     * {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} and
+     * {@link NetworkCapabilities#NET_CAPABILITY_NOT_VCN_MANAGED}. Verify that the
+     * {@code ConnectivityService} re-assign the networks accordingly.
+     */
     @Test
-    public final void testLoseTrusted() throws Exception {
-        final NetworkRequest trustedRequest = new NetworkRequest.Builder()
-                .addCapability(NET_CAPABILITY_TRUSTED)
-                .build();
-        final TestNetworkCallback trustedCallback = new TestNetworkCallback();
-        mCm.requestNetwork(trustedRequest, trustedCallback);
+    public final void testLoseMutableAndRequestableCaps() throws Exception {
+        final int[] testCaps = new int [] {
+                NET_CAPABILITY_TRUSTED,
+                NET_CAPABILITY_NOT_VCN_MANAGED
+        };
+        for (final int testCap : testCaps) {
+            // Create requests with and without the testing capability.
+            final TestNetworkCallback callbackWithCap = new TestNetworkCallback();
+            final TestNetworkCallback callbackWithoutCap = new TestNetworkCallback();
+            mCm.requestNetwork(new NetworkRequest.Builder().addCapability(testCap).build(),
+                    callbackWithCap);
+            mCm.requestNetwork(new NetworkRequest.Builder().removeCapability(testCap).build(),
+                    callbackWithoutCap);
 
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        mCellNetworkAgent.connect(true);
-        trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            // Setup networks with testing capability and verify the default network changes.
+            mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+            mCellNetworkAgent.addCapability(testCap);
+            mCellNetworkAgent.connect(true);
+            callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+            reset(mMockNetd);
 
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        mWiFiNetworkAgent.connect(true);
-        trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+            mWiFiNetworkAgent.addCapability(testCap);
+            mWiFiNetworkAgent.connect(true);
+            callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+            callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+            verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
+            reset(mMockNetd);
 
-        mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
-        trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-        verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
-        reset(mMockNetd);
+            // Remove the testing capability on wifi, verify the callback and default network
+            // changes back to cellular.
+            mWiFiNetworkAgent.removeCapability(testCap);
+            callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
+            callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
+            // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
+            //  it.
+            if (testCap == NET_CAPABILITY_TRUSTED) {
+                verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+                reset(mMockNetd);
+            }
 
-        mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
-        trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        verify(mMockNetd).networkClearDefault();
+            mCellNetworkAgent.removeCapability(testCap);
+            callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            callbackWithoutCap.assertNoCallback();
+            if (testCap == NET_CAPABILITY_TRUSTED) {
+                verify(mMockNetd).networkClearDefault();
+            }
 
-        mCm.unregisterNetworkCallback(trustedCallback);
+            mCm.unregisterNetworkCallback(callbackWithCap);
+            mCm.unregisterNetworkCallback(callbackWithoutCap);
+        }
     }
 
-    @Ignore // 40%+ flakiness : figure out why and re-enable.
     @Test
     public final void testBatteryStatsNetworkType() throws Exception {
         final LinkProperties cellLp = new LinkProperties();
@@ -7375,8 +7408,8 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
         reset(mBatteryStatsService);
 
         final LinkProperties wifiLp = new LinkProperties();
@@ -7384,18 +7417,20 @@
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
-                TYPE_WIFI);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(wifiLp.getInterfaceName(),
+                new int[] { TRANSPORT_WIFI });
         reset(mBatteryStatsService);
 
         mCellNetworkAgent.disconnect();
+        mWiFiNetworkAgent.disconnect();
 
         cellLp.setInterfaceName("wifi0");
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
+        mCellNetworkAgent.disconnect();
     }
 
     /**
@@ -7468,8 +7503,8 @@
         assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
-        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
-                TYPE_MOBILE);
+        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+                new int[] { TRANSPORT_CELLULAR });
 
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -7489,7 +7524,8 @@
         // Make sure BatteryStats was not told about any v4- interfaces, as none should have
         // come online yet.
         waitForIdle();
-        verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+        verify(mBatteryStatsService, never()).noteNetworkInterfaceForTransports(startsWith("v4-"),
+                any());
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -7542,8 +7578,8 @@
         assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
         for (final LinkProperties stackedLp : stackedLpsAfterChange) {
-            verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
-                    TYPE_MOBILE);
+            verify(mBatteryStatsService).noteNetworkInterfaceForTransports(
+                    stackedLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR });
         }
         reset(mMockNetd);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -8323,8 +8359,9 @@
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
         mMockVpn.setVpnType(vpnType);
 
-        final VpnInfo vpnInfo = new VpnInfo(vpnOwnerUid, null, null);
-        mMockVpn.setVpnInfo(vpnInfo);
+        final UnderlyingNetworkInfo underlyingNetworkInfo =
+                new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+        mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
     }
 
     private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index a10a3c8..e590fb7 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).isDefaultNetwork(any())
+        doReturn(false).`when`(this).isFallbackNetwork(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).isDefaultNetwork(mobileNai1)
+        doReturn(false).`when`(mMockService).isFallbackNetwork(mobileNai1)
         mTracker.add(TYPE_MOBILE, mobileNai1)
         verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
         reset(mMockService)
-        doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
+        doReturn(false).`when`(mMockService).isFallbackNetwork(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/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 68aaaed..f478282 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -148,6 +148,7 @@
         managedProfileA.profileGroupId = primaryUser.id;
     }
 
+    static final Network EGRESS_NETWORK = new Network(101);
     static final String EGRESS_IFACE = "wlan0";
     static final String TEST_VPN_PKG = "com.testvpn.vpn";
     private static final String TEST_VPN_SERVER = "1.2.3.4";
@@ -963,7 +964,7 @@
                         InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
         lp.addRoute(defaultRoute);
 
-        vpn.startLegacyVpn(vpnProfile, mKeyStore, lp);
+        vpn.startLegacyVpn(vpnProfile, mKeyStore, EGRESS_NETWORK, lp);
         return vpn;
     }
 
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
index 1b33930e..a058a46 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -33,7 +33,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.net.NetworkStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
+
+import java.util.Arrays;
 
 /** Superclass with utilities for NetworkStats(Service|Factory)Test */
 abstract class NetworkStatsBaseTest {
@@ -107,11 +109,11 @@
         assertEquals("unexpected operations", operations, entry.operations);
     }
 
-    static VpnInfo createVpnInfo(String[] underlyingIfaces) {
+    static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
         return createVpnInfo(TUN_IFACE, underlyingIfaces);
     }
 
-    static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
-        return new VpnInfo(UID_VPN, vpnIface, underlyingIfaces);
+    static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
+        return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
     }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 76647a6..f3ae9b0 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -36,7 +36,7 @@
 import android.content.res.Resources;
 import android.net.NetworkStats;
 import android.net.TrafficStats;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -79,7 +79,7 @@
         // related to networkStatsFactory is compiled to a minimal native library and loaded here.
         System.loadLibrary("networkstatsfactorytestjni");
         mFactory = new NetworkStatsFactory(mTestProc, false);
-        mFactory.updateVpnInfos(new VpnInfo[0]);
+        mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
     }
 
     @After
@@ -105,8 +105,9 @@
 
     @Test
     public void testVpnRewriteTrafficThroughItself() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -134,8 +135,9 @@
 
     @Test
     public void testVpnWithClat() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
+                createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
         mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
@@ -167,8 +169,9 @@
 
     @Test
     public void testVpnWithOneUnderlyingIface() throws Exception {
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -191,8 +194,9 @@
     @Test
     public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
         // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -219,8 +223,9 @@
     @Test
     public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
         // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -242,8 +247,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is duplicating traffic across both WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -267,10 +273,10 @@
     public void testConcurrentVpns() throws Exception {
         // Assume two VPNs are connected on two different network interfaces. VPN1 is using
         // TEST_IFACE and VPN2 is using TEST_IFACE2.
-        final VpnInfo[] vpnInfos = new VpnInfo[] {
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
                 createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
                 createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -308,8 +314,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
@@ -335,8 +342,9 @@
         // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
         // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
         // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface:
         // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
@@ -357,8 +365,9 @@
     public void testVpnWithIncorrectUnderlyingIface() throws Exception {
         // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
         // but has declared only WiFi (TEST_IFACE) in its underlying network set.
-        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
-        mFactory.updateVpnInfos(vpnInfos);
+        final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+                new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
 
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b4e37de..dde78aa 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -86,7 +86,7 @@
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
-import android.net.VpnInfo;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -286,7 +286,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -328,7 +329,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -401,7 +403,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -441,7 +444,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic on first network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -475,7 +479,8 @@
                 .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
         forcePollAndWaitForIdle();
 
 
@@ -514,7 +519,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -581,7 +587,7 @@
 
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
-                new VpnInfo[0]);
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
         incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -655,7 +661,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some traffic for two apps
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -713,7 +720,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry entry1 = new NetworkStats.Entry(
                 TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -756,7 +764,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         NetworkStats.Entry uidStats = new NetworkStats.Entry(
                 TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -810,7 +819,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -867,7 +877,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some initial traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -906,7 +917,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -943,7 +955,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // create some tethering traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -999,7 +1012,8 @@
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1104,7 +1118,8 @@
                 mService.registerNetworkStatsProvider("TEST", provider);
         assertNotNull(cb);
 
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Verifies that one requestStatsUpdate will be called during iface update.
         provider.expectOnRequestStatsUpdate(0 /* unused */);
@@ -1155,7 +1170,8 @@
         expectDefaultSettings();
         NetworkState[] states =
                 new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Register custom provider and retrieve callback.
         final TestableNetworkStatsProviderBinder provider =
@@ -1204,7 +1220,7 @@
         // 3G network comes online.
         setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
-                new VpnInfo[0]);
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic.
         incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -1274,7 +1290,8 @@
         NetworkState[] states = new NetworkState[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
-        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+        mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
 
         // Create some traffic on mobile network.
         incrementCurrentTime(HOUR_IN_MILLIS);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 9c6b719..f9db408 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -18,14 +18,19 @@
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 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.when;
 
 import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
 
 import org.junit.Before;
@@ -103,4 +108,28 @@
     public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
         mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
     }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy() throws Exception {
+        NetworkCapabilities nc = new NetworkCapabilities();
+        LinkProperties lp = new LinkProperties();
+        when(mMockVcnManagementService.getUnderlyingNetworkPolicy(eq(nc), eq(lp)))
+                .thenReturn(new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, nc));
+
+        VcnUnderlyingNetworkPolicy policy = mVcnManager.getUnderlyingNetworkPolicy(nc, lp);
+
+        assertFalse(policy.isTeardownRequested());
+        assertEquals(nc, policy.getMergedNetworkCapabilities());
+        verify(mMockVcnManagementService).getUnderlyingNetworkPolicy(eq(nc), eq(lp));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testGetUnderlyingNetworkPolicyNullNetworkCapabilities() throws Exception {
+        mVcnManager.getUnderlyingNetworkPolicy(null, new LinkProperties());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
+        mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
+    }
 }
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index f0cdde3..e7d334e 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -21,6 +21,7 @@
 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.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -28,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -37,13 +39,20 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.NetworkCapabilities.Transport;
+import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnConfigTest;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.net.wifi.WifiInfo;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
@@ -63,6 +72,7 @@
 import com.android.server.vcn.VcnNetworkProvider;
 import com.android.server.vcn.util.PersistableBundleUtils;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -192,6 +202,14 @@
         mTestLooper.dispatchAll();
     }
 
+    @Before
+    public void setUp() {
+        doNothing()
+                .when(mMockContext)
+                .enforceCallingOrSelfPermission(
+                        eq(android.Manifest.permission.NETWORK_FACTORY), any());
+    }
+
     private void setupMockedCarrierPrivilege(boolean isPrivileged) {
         doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
                 .when(mSubMgr)
@@ -239,7 +257,14 @@
         verify(mConfigReadWriteHelper).readFromDisk();
     }
 
-    private void triggerSubscriptionTrackerCallback(Set<ParcelUuid> activeSubscriptionGroups) {
+    private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+            Set<ParcelUuid> activeSubscriptionGroups) {
+        return triggerSubscriptionTrackerCbAndGetSnapshot(
+                activeSubscriptionGroups, Collections.emptyMap());
+    }
+
+    private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+            Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
         final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
         doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
 
@@ -253,8 +278,14 @@
                         argThat(val -> activeSubscriptionGroups.contains(val)),
                         eq(TEST_PACKAGE_NAME));
 
+        doAnswer(invocation -> {
+            return subIdToGroupMap.get(invocation.getArgument(0));
+        }).when(snapshot).getGroupForSubId(anyInt());
+
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         cb.onNewSnapshot(snapshot);
+
+        return snapshot;
     }
 
     private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
@@ -273,7 +304,7 @@
 
     @Test
     public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
-        triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_1));
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
         verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG));
     }
 
@@ -282,7 +313,7 @@
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
 
-        triggerSubscriptionTrackerCallback(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
 
         // Verify teardown after delay
         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -297,13 +328,13 @@
         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
 
         // Simulate SIM unloaded
-        triggerSubscriptionTrackerCallback(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
 
         // Simulate new SIM loaded right during teardown delay.
         mTestLooper.moveTimeForward(
                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
         mTestLooper.dispatchAll();
-        triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_2));
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
 
         // Verify that even after the full timeout duration, the VCN instance is not torn down
         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -317,7 +348,7 @@
         final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
 
         // Simulate SIM unloaded
-        triggerSubscriptionTrackerCallback(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
 
         // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
         // vcnInstance.
@@ -455,10 +486,6 @@
 
     @Test
     public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
-        doNothing()
-                .when(mMockContext)
-                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
-
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         verify(mMockIBinder).linkToDeath(any(), anyInt());
@@ -468,17 +495,14 @@
     public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
         doThrow(new SecurityException())
                 .when(mMockContext)
-                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+                .enforceCallingOrSelfPermission(
+                        eq(android.Manifest.permission.NETWORK_FACTORY), any());
 
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
     }
 
     @Test
     public void testRemoveVcnUnderlyingNetworkPolicyListener() {
-        // verify listener added
-        doNothing()
-                .when(mMockContext)
-                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
@@ -488,4 +512,83 @@
     public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
     }
+
+    private void setUpVcnSubscription(int subId, ParcelUuid subGroup) {
+        mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
+    }
+
+    private void verifyMergedNetworkCapabilities(
+            NetworkCapabilities mergedCapabilities, @Transport int transportType) {
+        assertTrue(mergedCapabilities.hasTransport(transportType));
+        assertFalse(
+                mergedCapabilities.hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
+    }
+
+    @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());
+
+        assertFalse(policy.isTeardownRequested());
+        verifyMergedNetworkCapabilities(
+                policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR);
+    }
+
+    @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());
+
+        assertFalse(policy.isTeardownRequested());
+        verifyMergedNetworkCapabilities(
+                policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
+        NetworkCapabilities nc =
+                new NetworkCapabilities.Builder()
+                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                        .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
+                        .build();
+
+        VcnUnderlyingNetworkPolicy policy =
+                mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+
+        assertFalse(policy.isTeardownRequested());
+        assertEquals(nc, policy.getMergedNetworkCapabilities());
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testGetUnderlyingNetworkPolicyInvalidPermission() {
+        doThrow(new SecurityException())
+                .when(mMockContext)
+                .enforceCallingOrSelfPermission(
+                        eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+        mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
new file mode 100644
index 0000000..48e068d
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -0,0 +1,366 @@
+/*
+ * 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 com.android.server.vcn.VcnTestUtils.setupSystemService;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+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.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
+import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback;
+import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+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 NetworkCapabilities INITIAL_NETWORK_CAPABILITIES =
+            new NetworkCapabilities.Builder()
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                    .build();
+    private static final NetworkCapabilities SUSPENDED_NETWORK_CAPABILITIES =
+            new NetworkCapabilities.Builder(INITIAL_NETWORK_CAPABILITIES)
+                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+                    .build();
+    private static final NetworkCapabilities UPDATED_NETWORK_CAPABILITIES =
+            new NetworkCapabilities.Builder()
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    .build();
+
+    private static final LinkProperties INITIAL_LINK_PROPERTIES =
+            getLinkPropertiesWithName("initial_iface");
+    private static final LinkProperties UPDATED_LINK_PROPERTIES =
+            getLinkPropertiesWithName("updated_iface");
+
+    @Mock private Context mContext;
+    @Mock private VcnNetworkProvider mVcnNetworkProvider;
+    @Mock private ConnectivityManager mConnectivityManager;
+    @Mock private SubscriptionManager mSubscriptionManager;
+    @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
+    @Mock private Network mNetwork;
+
+    @Captor private ArgumentCaptor<RouteSelectionCallback> mRouteSelectionCallbackCaptor;
+
+    private TestLooper mTestLooper;
+    private VcnContext mVcnContext;
+    private UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTestLooper = new TestLooper();
+        mVcnContext = spy(new VcnContext(mContext, mTestLooper.getLooper(), mVcnNetworkProvider));
+        doNothing().when(mVcnContext).ensureRunningOnLooperThread();
+
+        setupSystemService(
+                mContext,
+                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);
+
+        mUnderlyingNetworkTracker =
+                new UnderlyingNetworkTracker(
+                        mVcnContext,
+                        SUB_GROUP,
+                        Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
+                        mNetworkTrackerCb);
+    }
+
+    private static LinkProperties getLinkPropertiesWithName(String iface) {
+        LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(iface);
+        return linkProperties;
+    }
+
+    private SubscriptionInfo getSubscriptionInfoForSubId(int subId) {
+        SubscriptionInfo subInfo = mock(SubscriptionInfo.class);
+        when(subInfo.getSubscriptionId()).thenReturn(subId);
+        return subInfo;
+    }
+
+    @Test
+    public void testNetworkCallbacksRegisteredOnStartup() {
+        // verify NetworkCallbacks registered when instantiated
+        verify(mConnectivityManager)
+                .requestBackgroundNetwork(
+                        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));
+        verify(mConnectivityManager)
+                .requestBackgroundNetwork(
+                        eq(getRouteSelectionRequest()),
+                        any(),
+                        any(RouteSelectionCallback.class));
+
+        verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP));
+    }
+
+    private NetworkRequest getWifiRequest() {
+        return getExpectedRequestBase()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .build();
+    }
+
+    private NetworkRequest getCellRequestForSubId(int subId) {
+        return getExpectedRequestBase()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
+                .build();
+    }
+
+    private NetworkRequest getRouteSelectionRequest() {
+        return getExpectedRequestBase().build();
+    }
+
+    private NetworkRequest.Builder getExpectedRequestBase() {
+        return new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+    }
+
+    @Test
+    public void testTeardown() {
+        mUnderlyingNetworkTracker.teardown();
+
+        // Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x
+        // for each subId)
+        verify(mConnectivityManager, times(3))
+                .unregisterNetworkCallback(any(NetworkBringupCallback.class));
+        verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class));
+    }
+
+    @Test
+    public void testUnderlyingNetworkRecordEquals() {
+        UnderlyingNetworkRecord recordA =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        INITIAL_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        UnderlyingNetworkRecord recordB =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        INITIAL_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        UnderlyingNetworkRecord recordC =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        UPDATED_NETWORK_CAPABILITIES,
+                        UPDATED_LINK_PROPERTIES,
+                        false /* isBlocked */);
+
+        assertEquals(recordA, recordB);
+        assertNotEquals(recordA, recordC);
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForNetworkChange() {
+        verifyRegistrationOnAvailableAndGetCallback();
+    }
+
+    private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() {
+        return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
+    }
+
+    private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback(
+            NetworkCapabilities networkCapabilities) {
+        verify(mConnectivityManager)
+                .requestBackgroundNetwork(
+                        eq(getRouteSelectionRequest()),
+                        any(),
+                        mRouteSelectionCallbackCaptor.capture());
+
+        RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue();
+        cb.onAvailable(mNetwork);
+        cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
+        cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
+        cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        networkCapabilities,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        return cb;
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        UPDATED_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        INITIAL_NETWORK_CAPABILITIES,
+                        UPDATED_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onNetworkSuspended(mNetwork);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        SUSPENDED_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForNetworkResumed() {
+        RouteSelectionCallback cb =
+                verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
+
+        cb.onNetworkResumed(mNetwork);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        INITIAL_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        false /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForBlocked() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
+
+        UnderlyingNetworkRecord expectedRecord =
+                new UnderlyingNetworkRecord(
+                        mNetwork,
+                        INITIAL_NETWORK_CAPABILITIES,
+                        INITIAL_LINK_PROPERTIES,
+                        true /* isBlocked */);
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+    }
+
+    @Test
+    public void testRecordTrackerCallbackNotifiedForNetworkLoss() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onLost(mNetwork);
+
+        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null);
+    }
+
+    @Test
+    public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
+        RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
+
+        cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+
+        // Verify no more calls to the UnderlyingNetworkTrackerCallback when the
+        // UnderlyingNetworkRecord does not actually change
+        verifyNoMoreInteractions(mNetworkTrackerCb);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
new file mode 100644
index 0000000..d936183
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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 com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+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.ConnectingState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase {
+    private VcnIkeSession mIkeSession;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mGatewayConnection.transitionTo(mGatewayConnection.mConnectingState);
+        mTestLooper.dispatchAll();
+
+        mIkeSession = mGatewayConnection.getIkeSession();
+    }
+
+    @Test
+    public void testEnterStateCreatesNewIkeSession() throws Exception {
+        verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testNullNetworkTriggersDisconnect() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession).kill();
+    }
+
+    @Test
+    public void testNewNetworkTriggersReconnect() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession).close();
+        verify(mIkeSession, never()).kill();
+    }
+
+    @Test
+    public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testChildSessionClosedTriggersDisconnect() throws Exception {
+        getChildSessionCallback().onClosed();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession).close();
+    }
+
+    @Test
+    public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+        getIkeSessionCallback().onClosed();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+        verify(mIkeSession).close();
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 3467859..4d92fb9 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -32,6 +32,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.vcn.VcnGatewayConnectionConfig;
 import android.net.vcn.VcnGatewayConnectionConfigTest;
@@ -93,7 +94,7 @@
 
         doReturn(mUnderlyingNetworkTracker)
                 .when(mDeps)
-                .newUnderlyingNetworkTracker(any(), any(), any());
+                .newUnderlyingNetworkTracker(any(), any(), any(), any());
     }
 
     @Before
@@ -117,4 +118,11 @@
         verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any());
         return captor.getValue();
     }
+
+    protected ChildSessionCallback getChildSessionCallback() {
+        ArgumentCaptor<ChildSessionCallback> captor =
+                ArgumentCaptor.forClass(ChildSessionCallback.class);
+        verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
+        return captor.getValue();
+    }
 }