Merge "Grant OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD to Shell"
diff --git a/Android.bp b/Android.bp
index 4709323..0b0a9b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,278 +64,13 @@
 }
 
 filegroup {
-    name: "framework-core-sources",
-    srcs: [
-        "core/java/**/*.java",
-        "core/java/**/*.aidl",
-    ],
-    path: "core/java",
-}
-
-// These are subset of framework-core-sources that are needed by the
-// android.test.mock library. The implementation of android.test.mock references
-// private members of various components to allow mocking of classes that cannot
-// be mocked without access to those internal implementation details.
-filegroup {
-    name: "framework-core-sources-for-test-mock",
-    srcs: [
-        "core/java/android/accounts/AccountManagerCallback.java",
-        "core/java/android/accounts/AccountManagerFuture.java",
-        "core/java/android/accounts/AccountManager.java",
-        "core/java/android/accounts/AccountsException.java",
-        "core/java/android/accounts/AuthenticatorException.java",
-        "core/java/android/accounts/OperationCanceledException.java",
-        "core/java/android/annotation/AnimatorRes.java",
-        "core/java/android/annotation/AnimRes.java",
-        "core/java/android/annotation/AnyRes.java",
-        "core/java/android/annotation/ArrayRes.java",
-        "core/java/android/annotation/AttrRes.java",
-        "core/java/android/annotation/BoolRes.java",
-        "core/java/android/annotation/BroadcastBehavior.java",
-        "core/java/android/annotation/CallbackExecutor.java",
-        "core/java/android/annotation/CallSuper.java",
-        "core/java/android/annotation/CheckResult.java",
-        "core/java/android/annotation/ColorInt.java",
-        "core/java/android/annotation/ColorRes.java",
-        "core/java/android/annotation/DimenRes.java",
-        "core/java/android/annotation/DrawableRes.java",
-        "core/java/android/annotation/FontRes.java",
-        "core/java/android/annotation/FractionRes.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntegerRes.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/LayoutRes.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/PluralsRes.java",
-        "core/java/android/annotation/RawRes.java",
-        "core/java/android/annotation/RequiresPermission.java",
-        "core/java/android/annotation/SdkConstant.java",
-        "core/java/android/annotation/Size.java",
-        "core/java/android/annotation/StringDef.java",
-        "core/java/android/annotation/StringRes.java",
-        "core/java/android/annotation/StyleableRes.java",
-        "core/java/android/annotation/StyleRes.java",
-        "core/java/android/annotation/SuppressLint.java",
-        "core/java/android/annotation/SystemApi.java",
-        "core/java/android/annotation/SystemService.java",
-        "core/java/android/annotation/TestApi.java",
-        "core/java/android/annotation/UserIdInt.java",
-        "core/java/android/annotation/XmlRes.java",
-        "core/java/android/app/Application.java",
-        "core/java/android/app/IApplicationThread.aidl",
-        "core/java/android/app/IServiceConnection.aidl",
-        "core/java/android/app/PackageDeleteObserver.java",
-        "core/java/android/content/ComponentCallbacks2.java",
-        "core/java/android/content/ComponentCallbacks.java",
-        "core/java/android/content/ContentInterface.java",
-        "core/java/android/content/ContentProvider.java",
-        "core/java/android/content/ContentProviderNative.java",
-        "core/java/android/content/ContentResolver.java",
-        "core/java/android/content/Context.java",
-        "core/java/android/content/ContextWrapper.java",
-        "core/java/android/content/DialogInterface.java",
-        "core/java/android/content/IContentProvider.java",
-        "core/java/android/content/Intent.java",
-        "core/java/android/content/IntentSender.java",
-        "core/java/android/content/OperationApplicationException.java",
-        "core/java/android/content/pm/ActivityInfo.java",
-        "core/java/android/content/pm/ApplicationInfo.java",
-        "core/java/android/content/pm/InstantAppInfo.java",
-        "core/java/android/content/pm/IPackageDataObserver.aidl",
-        "core/java/android/content/pm/KeySet.java",
-        "core/java/android/content/pm/PackageManager.java",
-        "core/java/android/content/pm/VerifierDeviceIdentity.java",
-        "core/java/android/content/res/Resources.java",
-        "core/java/android/database/CrossProcessCursor.java",
-        "core/java/android/database/CrossProcessCursorWrapper.java",
-        "core/java/android/database/Cursor.java",
-        "core/java/android/database/CursorWrapper.java",
-        "core/java/android/os/Binder.java",
-        "core/java/android/os/Bundle.java",
-        "core/java/android/os/IBinder.java",
-        "core/java/android/os/IInterface.java",
-        "core/java/android/os/Parcelable.java",
-        "core/java/android/os/ParcelFileDescriptor.java",
-        "core/java/android/os/RemoteException.java",
-        "core/java/android/os/storage/VolumeInfo.java",
-        "core/java/android/util/AndroidException.java",
-        "core/java/android/view/DisplayAdjustments.java",
-        "core/java/android/view/ViewDebug.java",
-        "core/java/com/android/internal/annotations/VisibleForTesting.java",
-    ],
-    path: "core/java",
-    visibility: ["//frameworks/base/test-mock"],
-}
-
-filegroup {
-    name: "framework-drm-sources",
-    srcs: [
-        "drm/java/**/*.java",
-    ],
-    path: "drm/java",
-}
-
-filegroup {
-    name: "framework-graphics-sources",
-    srcs: [
-        "graphics/java/**/*.java",
-        "graphics/java/**/*.aidl",
-    ],
-    path: "graphics/java",
-}
-
-filegroup {
-    name: "framework-identity-sources",
-    srcs: [
-        "identity/java/**/*.java",
-    ],
-    path: "identity/java",
-}
-
-filegroup {
-    name: "framework-keystore-sources",
-    srcs: [
-        "keystore/java/**/*.java",
-        "keystore/java/**/*.aidl",
-    ],
-    path: "keystore/java",
-}
-
-filegroup {
-    name: "framework-location-sources",
-    srcs: [
-        "location/java/**/*.java",
-        "location/java/**/*.aidl",
-    ],
-    path: "location/java",
-}
-
-filegroup {
-    name: "framework-lowpan-sources",
-    srcs: [
-        "lowpan/java/**/*.java",
-        "lowpan/java/**/*.aidl",
-    ],
-    path: "lowpan/java",
-}
-
-filegroup {
-    name: "framework-media-sources",
-    srcs: [
-        "media/java/**/*.java",
-        "media/java/**/*.aidl",
-    ],
-    path: "media/java",
-}
-
-filegroup {
-    name: "framework-mca-effect-sources",
-    srcs: [
-        "media/mca/effect/java/**/*.java",
-    ],
-    path: "media/mca/effect/java",
-}
-
-filegroup {
-    name: "framework-mca-filterfw-sources",
-    srcs: [
-        "media/mca/filterfw/java/**/*.java",
-    ],
-    path: "media/mca/filterfw/java",
-}
-
-filegroup {
-    name: "framework-mca-filterpacks-sources",
-    srcs: [
-        "media/mca/filterpacks/java/**/*.java",
-    ],
-    path: "media/mca/filterpacks/java",
-}
-
-filegroup {
-    name: "framework-mime-sources",
-    srcs: [
-        "mime/java/**/*.java",
-    ],
-    path: "mime/java",
-}
-
-filegroup {
-    name: "framework-opengl-sources",
-    srcs: [
-        "opengl/java/**/*.java",
-    ],
-    path: "opengl/java",
-}
-
-filegroup {
-    name: "framework-rs-sources",
-    srcs: [
-        "rs/java/**/*.java",
-    ],
-    path: "rs/java",
-}
-
-filegroup {
-    name: "framework-sax-sources",
-    srcs: [
-        "sax/java/**/*.java",
-    ],
-    path: "sax/java",
-}
-
-filegroup {
-    name: "framework-telecomm-sources",
-    srcs: [
-        "telecomm/java/**/*.java",
-        "telecomm/java/**/*.aidl",
-    ],
-    path: "telecomm/java",
-}
-
-filegroup {
-    name: "framework-telephony-sources",
-    srcs: [
-        "telephony/java/**/*.java",
-        "telephony/java/**/*.aidl",
-    ],
-    path: "telephony/java",
-}
-
-genrule {
-    name: "statslog-telephony-common-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
-        " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
-    out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
-}
-
-filegroup {
-    name: "framework-telephony-common-sources",
-    srcs: [
-        "telephony/common/**/*.java",
-        ":statslog-telephony-common-java-gen",
-    ],
-}
-
-filegroup {
-    name: "framework-mms-sources",
-    srcs: [
-        "mms/java/**/*.java",
-        "mms/java/**/*.aidl",
-    ],
-    path: "mms/java",
-}
-
-filegroup {
     name: "framework-non-updatable-sources",
     srcs: [
         // Java/AIDL sources under frameworks/base
         ":framework-blobstore-sources",
         ":framework-core-sources",
         ":framework-drm-sources",
-        ":framework-graphics-sources",
+        ":framework-graphics-nonupdatable-sources",
         ":framework-jobscheduler-sources", // jobscheduler is not a module for R
         ":framework-keystore-sources",
         ":framework-identity-sources",
@@ -377,12 +112,12 @@
         ":gsiservice_aidl",
         ":incidentcompanion_aidl",
         ":installd_aidl",
-        ":keystore_aidl",
         ":libaudioclient_aidl",
         ":libbinder_aidl",
         ":libbluetooth-binder-aidl",
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
+        ":packagemanager_aidl",
         ":libupdate_engine_aidl",
         ":resourcemanager_aidl",
         ":storaged_aidl",
@@ -398,22 +133,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-updatable-sources",
-    srcs: [
-        ":framework-connectivity-sources",
-        ":framework-mediaprovider-sources",
-        ":framework-permission-sources",
-        ":framework-sdkextensions-sources",
-        ":framework-statsd-sources",
-        ":framework-tethering-srcs",
-        ":framework-wifi-updatable-sources",
-        ":ike-srcs",
-        ":updatable-media-srcs",
-    ],
-    visibility: ["//visibility:private"],
-}
-
 java_library {
     name: "framework-updatable-stubs-module_libs_api",
     static_libs: [
@@ -453,15 +172,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-all-sources",
-    srcs: [
-        ":framework-mime-sources",
-        ":framework-non-updatable-sources",
-        ":framework-updatable-sources",
-    ],
-}
-
 // AIDL files under these paths are mixture of public and private ones.
 // They shouldn't be exported across module boundaries.
 java_defaults {
@@ -586,8 +296,6 @@
         ":framework-connectivity-sources",
         "core/java/**/*.logtags",
     ],
-    // See comment on framework-atb-backward-compatibility module below
-    exclude_srcs: ["core/java/android/content/pm/AndroidTestBaseUpdater.java"],
     aidl: {
         generate_get_transaction_name: true,
     },
@@ -668,20 +376,6 @@
     src: ":framework-minus-apex",
 }
 
-// A temporary build target that is conditionally included on the bootclasspath if
-// android.test.base library has been removed and which provides support for
-// maintaining backwards compatibility for APKs that target pre-P and depend on
-// android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
-// specified on the build command line.
-java_library {
-    name: "framework-atb-backward-compatibility",
-    installable: true,
-    libs: ["app-compat-annotations"],
-    srcs: [
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
-    ],
-}
-
 genrule {
     name: "statslog-framework-java-gen",
     tools: ["stats-log-api-gen"],
@@ -763,13 +457,21 @@
 filegroup {
     name: "framework-annotations",
     srcs: [
+        "core/java/android/annotation/AnyThread.java",
+        "core/java/android/annotation/AppIdInt.java",
+        "core/java/android/annotation/BytesLong.java",
         "core/java/android/annotation/CallbackExecutor.java",
+        "core/java/android/annotation/CallSuper.java",
         "core/java/android/annotation/CheckResult.java",
         "core/java/android/annotation/CurrentTimeMillisLong.java",
+        "core/java/android/annotation/CurrentTimeSecondsLong.java",
+        "core/java/android/annotation/DrawableRes.java",
+        "core/java/android/annotation/DurationMillisLong.java",
         "core/java/android/annotation/Hide.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/LongDef.java",
+        "core/java/android/annotation/MainThread.java",
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/Nullable.java",
         "core/java/android/annotation/RequiresPermission.java",
@@ -778,10 +480,11 @@
         "core/java/android/annotation/SystemApi.java",
         "core/java/android/annotation/SystemService.java",
         "core/java/android/annotation/TestApi.java",
+        "core/java/android/annotation/UserIdInt.java",
         "core/java/android/annotation/WorkerThread.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
-        "core/java/com/android/internal/annotations/VisibleForTesting.java",
         "core/java/com/android/internal/annotations/Immutable.java",
+        "core/java/com/android/internal/annotations/VisibleForTesting.java",
     ],
 }
 
@@ -795,7 +498,6 @@
     name: "framework-ike-shared-srcs",
     visibility: ["//packages/modules/IPsec"],
     srcs: [
-        "core/java/android/annotation/StringDef.java",
         "core/java/android/net/annotations/PolicyDirection.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IState.java",
@@ -821,7 +523,6 @@
         "core/java/com/android/internal/util/RingBufferIndices.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "core/java/com/android/internal/util/TokenBucket.java",
     ],
@@ -847,7 +548,6 @@
         "core/java/com/android/internal/util/MessageUtils.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
     ],
 }
@@ -1069,6 +769,14 @@
     path: "core/java",
 }
 
+filegroup {
+    name: "activity_manager_procstate_aidl",
+    srcs: [
+        // internal only
+    ],
+    path: "core/java",
+}
+
 aidl_interface {
     name: "libincremental_aidl",
     unstable: true,
@@ -1148,38 +856,6 @@
     },
 }
 
-// TODO(b/77285514): remove this once the last few hidl interfaces have been
-// updated to use hwbinder.stubs.
-java_library {
-    name: "hwbinder",
-    sdk_version: "core_platform",
-
-    srcs: [
-        "core/java/android/os/HidlSupport.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/SystemApi.java",
-        "core/java/android/annotation/TestApi.java",
-        "core/java/android/os/HidlMemory.java",
-        "core/java/android/os/HwBinder.java",
-        "core/java/android/os/HwBlob.java",
-        "core/java/android/os/HwParcel.java",
-        "core/java/android/os/IHwBinder.java",
-        "core/java/android/os/IHwInterface.java",
-        "core/java/android/os/DeadObjectException.java",
-        "core/java/android/os/DeadSystemException.java",
-        "core/java/android/os/NativeHandle.java",
-        "core/java/android/os/RemoteException.java",
-        "core/java/android/util/AndroidException.java",
-    ],
-    libs: ["unsupportedappusage"],
-
-    dxflags: ["--core-library"],
-    installable: false,
-}
-
 python_defaults {
     name: "base_default",
     version: {
@@ -1206,36 +882,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-media-annotation-srcs",
-    srcs: [
-        ":framework-annotations",
-        "core/java/android/annotation/CallbackExecutor.java",
-        "core/java/android/annotation/CallSuper.java",
-        "core/java/android/annotation/DrawableRes.java",
-        "core/java/android/annotation/LongDef.java",
-        "core/java/android/annotation/StringDef.java",
-    ],
-}
-
-filegroup {
-    name: "framework-mediaprovider-annotation-sources",
-    srcs: [
-        ":framework-annotations",
-        "core/java/android/annotation/BytesLong.java",
-        "core/java/android/annotation/CurrentTimeSecondsLong.java",
-        "core/java/android/annotation/DurationMillisLong.java",
-    ],
-}
-
-// Creates an index of AIDL methods; used for adding UnsupportedAppUsage
-// annotations to private apis
-aidl_mapping {
-    name: "framework-aidl-mappings",
-    srcs: [":framework-all-sources"],
-    output: "framework-aidl-mappings.txt",
-}
-
 // Avoid including Parcelable classes as we don't want to have two copies of
 // Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
 // and TeleService app (packages/services/Telephony).
@@ -1357,6 +1003,19 @@
     "--api-lint-ignore-prefix junit. " +
     "--api-lint-ignore-prefix org. "
 
+filegroup {
+    name: "framework-non-updatable-stub-sources",
+    srcs: [
+        ":framework-mime-sources", // mimemap builds separately but has no separate droidstubs.
+        ":framework-non-updatable-sources",
+        ":opt-telephony-srcs",
+        ":opt-net-voip-srcs",
+        "core/java/**/*.logtags",
+        "**/package.html",
+    ],
+    visibility: ["//visibility:private"],
+}
+
 build = [
     "StubLibraries.bp",
     "ApiDocs.bp",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ada80bb..d3bef7f 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -58,16 +58,24 @@
 stubs_defaults {
     name: "framework-doc-stubs-default",
     srcs: [
-        ":framework-mime-sources",
-        ":framework-non-updatable-sources",
-        ":framework-updatable-sources",
-        "core/java/**/*.logtags",
-        "test-base/src/**/*.java",
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
+        ":framework-non-updatable-stub-sources",
+
+        // Module sources
         ":art.module.public.api{.public.stubs.source}",
         ":conscrypt.module.public.api{.public.stubs.source}",
+        ":framework-connectivity-sources",
+        ":framework-mediaprovider-sources",
+        ":framework-permission-sources",
+        ":framework-sdkextensions-sources",
+        ":framework-statsd-sources",
+        ":framework-tethering-srcs",
+        ":framework-wifi-updatable-sources",
         ":i18n.module.public.api{.public.stubs.source}",
+        ":ike-srcs",
+        ":updatable-media-srcs",
+
+        // No longer part of the stubs, but are included in the docs.
+        "test-base/src/**/*.java",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
     ],
diff --git a/StubLibraries.bp b/StubLibraries.bp
index fd614a7e3..1644a55 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -42,13 +42,7 @@
 
 stubs_defaults {
     name: "metalava-non-updatable-api-stubs-default",
-    srcs: [
-        ":framework-non-updatable-sources",
-        "core/java/**/*.logtags",
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        "**/package.html",
-    ],
+    srcs: [":framework-non-updatable-stub-sources"],
     sdk_version: "none",
     system_modules: "none",
     java_version: "1.8",
@@ -434,6 +428,7 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
+    libs: ["framework-annotations-lib"],
     installable: false,
     sdk_version: "core_platform",
     annotations_enabled: true,
@@ -447,7 +442,7 @@
 java_library_static {
     name: "hwbinder.stubs",
     sdk_version: "core_current",
-    libs: ["stub-annotations"],
+    libs: ["framework-annotations-lib"],
     srcs: [
         ":hwbinder-stubs-docs",
     ],
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 2f5f555..26010ef6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -532,18 +532,23 @@
         /**
          * Write out a tag with data identifying this job's constraints. If the constraint isn't here
          * it doesn't apply.
+         * TODO: b/183455312 Update this code to use proper serialization for NetworkRequest,
+         *       because currently store is not including everything (like, UIDs, bandwidth,
+         *       signal strength etc. are lost).
          */
         private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
             out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
             if (jobStatus.hasConnectivityConstraint()) {
                 final NetworkRequest network = jobStatus.getJob().getRequiredNetwork();
+                // STOPSHIP b/183071974: improve the scheme for backward compatibility and
+                // mainline cleanliness.
                 out.attribute(null, "net-capabilities", Long.toString(
-                        BitUtils.packBits(network.networkCapabilities.getCapabilities())));
+                        BitUtils.packBits(network.getCapabilities())));
                 out.attribute(null, "net-unwanted-capabilities", Long.toString(
-                        BitUtils.packBits(network.networkCapabilities.getUnwantedCapabilities())));
+                        BitUtils.packBits(network.getUnwantedCapabilities())));
 
                 out.attribute(null, "net-transport-types", Long.toString(
-                        BitUtils.packBits(network.networkCapabilities.getTransportTypes())));
+                        BitUtils.packBits(network.getTransportTypes())));
             }
             if (jobStatus.hasIdleConstraint()) {
                 out.attribute(null, "idle", Boolean.toString(true));
@@ -967,18 +972,23 @@
                     null, "net-unwanted-capabilities");
             final String netTransportTypes = parser.getAttributeValue(null, "net-transport-types");
             if (netCapabilities != null && netTransportTypes != null) {
-                final NetworkRequest request = new NetworkRequest.Builder().build();
+                final NetworkRequest.Builder builder = new NetworkRequest.Builder()
+                        .clearCapabilities();
                 final long unwantedCapabilities = netUnwantedCapabilities != null
                         ? Long.parseLong(netUnwantedCapabilities)
-                        : BitUtils.packBits(request.networkCapabilities.getUnwantedCapabilities());
-
+                        : BitUtils.packBits(builder.build().getUnwantedCapabilities());
                 // We're okay throwing NFE here; caught by caller
-                request.networkCapabilities.setCapabilities(
-                        BitUtils.unpackBits(Long.parseLong(netCapabilities)),
-                        BitUtils.unpackBits(unwantedCapabilities));
-                request.networkCapabilities.setTransportTypes(
-                        BitUtils.unpackBits(Long.parseLong(netTransportTypes)));
-                jobBuilder.setRequiredNetwork(request);
+                for (int capability : BitUtils.unpackBits(Long.parseLong(netCapabilities))) {
+                    builder.addCapability(capability);
+                }
+                for (int unwantedCapability : BitUtils.unpackBits(
+                        Long.parseLong(netUnwantedCapabilities))) {
+                    builder.addUnwantedCapability(unwantedCapability);
+                }
+                for (int transport : BitUtils.unpackBits(Long.parseLong(netTransportTypes))) {
+                    builder.addTransportType(transport);
+                }
+                jobBuilder.setRequiredNetwork(builder.build());
             } else {
                 // Read legacy values
                 val = parser.getAttributeValue(null, "connectivity");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 4f472df..5487e87 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -21,6 +21,7 @@
 
 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.job.JobInfo;
 import android.net.ConnectivityManager;
@@ -373,15 +374,23 @@
         }
     }
 
+    private static NetworkCapabilities.Builder copyCapabilities(
+            @NonNull final NetworkRequest request) {
+        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+        for (int transport : request.getTransportTypes()) builder.addTransportType(transport);
+        for (int capability : request.getCapabilities()) builder.addCapability(capability);
+        return builder;
+    }
+
     private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
         // A restricted job that's out of quota MUST use an unmetered network.
         if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
                 && !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
-            final NetworkCapabilities required = new NetworkCapabilities.Builder(
-                    jobStatus.getJob().getRequiredNetwork().networkCapabilities)
-                    .addCapability(NET_CAPABILITY_NOT_METERED).build();
-            return required.satisfiedByNetworkCapabilities(capabilities);
+            final NetworkCapabilities.Builder builder =
+                    copyCapabilities(jobStatus.getJob().getRequiredNetwork());
+            builder.addCapability(NET_CAPABILITY_NOT_METERED);
+            return builder.build().satisfiedByNetworkCapabilities(capabilities);
         } else {
             return jobStatus.getJob().getRequiredNetwork().canBeSatisfiedBy(capabilities);
         }
@@ -395,10 +404,10 @@
         }
 
         // See if we match after relaxing any unmetered request
-        final NetworkCapabilities relaxed = new NetworkCapabilities.Builder(
-                jobStatus.getJob().getRequiredNetwork().networkCapabilities)
-                        .removeCapability(NET_CAPABILITY_NOT_METERED).build();
-        if (relaxed.satisfiedByNetworkCapabilities(capabilities)) {
+        final NetworkCapabilities.Builder builder =
+                copyCapabilities(jobStatus.getJob().getRequiredNetwork());
+        builder.removeCapability(NET_CAPABILITY_NOT_METERED);
+        if (builder.build().satisfiedByNetworkCapabilities(capabilities)) {
             // TODO: treat this as "maybe" response; need to check quotas
             return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
         } else {
@@ -684,13 +693,6 @@
                     StateControllerProto.ConnectivityController.REQUESTED_STANDBY_EXCEPTION_UIDS,
                     mRequestedWhitelistJobs.keyAt(i));
         }
-        for (int i = 0; i < mAvailableNetworks.size(); i++) {
-            Network network = mAvailableNetworks.keyAt(i);
-            if (network != null) {
-                network.dumpDebug(proto,
-                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
-            }
-        }
         for (int i = 0; i < mTrackedJobs.size(); i++) {
             final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i);
             for (int j = 0; j < jobs.size(); j++) {
@@ -704,12 +706,6 @@
                         StateControllerProto.ConnectivityController.TrackedJob.INFO);
                 proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID,
                         js.getSourceUid());
-                NetworkRequest rn = js.getJob().getRequiredNetwork();
-                if (rn != null) {
-                    rn.dumpDebug(proto,
-                            StateControllerProto.ConnectivityController.TrackedJob
-                                    .REQUIRED_NETWORK);
-                }
                 proto.end(jsToken);
             }
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index ea8e7bc..a346812 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1911,9 +1911,6 @@
             if (uriPerms != null) {
                 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
             }
-            if (job.getRequiredNetwork() != null) {
-                job.getRequiredNetwork().dumpDebug(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
-            }
             if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
                 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_DOWNLOAD_BYTES,
                         mTotalNetworkDownloadBytes);
@@ -2002,10 +1999,6 @@
             }
         }
 
-        if (network != null) {
-            network.dumpDebug(proto, JobStatusDumpProto.NETWORK);
-        }
-
         if (pendingWork != null) {
             for (int i = 0; i < pendingWork.size(); i++) {
                 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 3dd0da7..0501a45 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -41,9 +41,7 @@
     installable: true,
 
     sdk_version: "module_current",
-    libs: [
-        "framework_media_annotation",
-    ],
+    libs: ["framework-annotations-lib"],
     static_libs: [
         "exoplayer2-extractor"
     ],
@@ -107,20 +105,9 @@
     srcs: [
         ":updatable-media-srcs",
     ],
-
-    libs: [
-        "framework_media_annotation",
-    ],
     impl_library_visibility: ["//frameworks/av/apex:__subpackages__"],
 }
 
-java_library {
-    name: "framework_media_annotation",
-    srcs: [":framework-media-annotation-srcs"],
-    installable: false,
-    sdk_version: "core_current",
-}
-
 cc_library_shared {
     name: "libmediaparser-jni",
     srcs: [
diff --git a/api/dump_api_shas.sh b/api/dump_api_shas.sh
new file mode 100755
index 0000000..c023b31
--- /dev/null
+++ b/api/dump_api_shas.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+# This script dumps the git SHAs of all commits inside api tracking directories.
+# It can used by tools wanting to track API changes, and the primary original
+# purpose is to verify verify all API change SHAs have been tracked by the
+# server-side API-council tools.
+#
+# The only argument is used to specify a git commit range to filter by.
+#
+# Example invocation (API changes between O and P):
+# frameworks/base/api/dump_api_shas.sh origin/oreo-dev..origin/pie-dev
+
+set -o pipefail
+
+eecho() { echo $@ >&2 ; }
+
+if [[ $1 == *..* ]]; then
+    exclude=${1/..*}
+    include=${1/*..}
+else
+    eecho No range or invalid range specified, defaulting to all commits from HEAD.
+    exclude=
+    include=HEAD
+fi
+
+eecho -n building queryview...
+{ source build/envsetup.sh && lunch aosp_arm && m queryview; } >/dev/null 2>&1 \
+  || { eecho failed; exit 1; }
+eecho "done"
+
+# This finds the directories where the dependant java_sdk_libs are defined
+bpdirs=$(
+  bazel query --config=queryview --output=package \
+    'kind(java_sdk_library, deps(//frameworks/base/api/..., 1))' 2>/dev/null
+  echo frameworks/base/core/api # Not a java_sdk_library.
+  echo frameworks/base/services/api # Not a java_sdk_library.
+)
+
+# Find relevant api subdirectories
+apidirs=$(
+  find $bpdirs -type f -name '*current.txt' -path '*/api/*' \
+    | xargs realpath --relative-to=$(pwd) | xargs dirname | sort | uniq
+)
+
+# Dump sorted SHAs of commits in these directories
+{ for d in $apidirs; do
+    ( cd $d
+      eecho inspecting $d
+      exclude_arg=$(test -n "$exclude" && {
+        git rev-parse -q --verify $exclude > /dev/null && echo "--not $exclude" \
+          || eecho "$d has no revision $exclude, including all commits"; } || true)
+      for f in $(find . -name '*current.txt'); do
+        git --no-pager log --pretty=format:%H --no-merges --follow $include $exclude_arg -- $f
+        echo # No trailing newline with --no-pager
+      done
+    )
+done; } | sort | uniq
diff --git a/boot/Android.bp b/boot/Android.bp
index 4f7c44e..71edea2 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -23,7 +23,24 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-boot_image {
-    name: "framework-boot-image",
-    image_name: "boot",
+// This module provides access to information Soong has related to the
+// whole platform bootclasspath. Currently, that information is provided solely
+// through configuration but additional information will be added here.
+//
+// This will provide support for the following:
+// * Hidden API processing for those parts of the bootclasspath that are not
+//   part of an APEX.
+// * Compatibility checking to ensure that the hidden API bits encoded into the
+//   dex files by the modularized hidden API processing is compatible with the
+//   runtimes of earlier releases which expect the bits to have been computed
+//   over the entirety of the bootclasspath in one go not separately.
+// * Dexpreopting apps and other libraries not on the platform bootclasspath.
+// * Generating and installing the appropriate files to the device which will
+//   allow it to generate the bootclasspath related environment variables
+//   dynamically.
+//
+// This module needs to be present in the build for the above processing to be
+// done correctly.
+platform_bootclasspath {
+    name: "platform-bootclasspath",
 }
diff --git a/boot/OWNERS b/boot/OWNERS
new file mode 100644
index 0000000..0648888
--- /dev/null
+++ b/boot/OWNERS
@@ -0,0 +1,2 @@
+# soong-team@ as the platform_bootclasspath module is tightly coupled with Soong
+file:platform/build/soong:/OWNERS
diff --git a/boot/hiddenapi/OWNERS b/boot/hiddenapi/OWNERS
new file mode 100644
index 0000000..5d869fc
--- /dev/null
+++ b/boot/hiddenapi/OWNERS
@@ -0,0 +1,7 @@
+# compat-team@ for changes to hiddenapi files
+andreionea@google.com
+mathewi@google.com
+satayev@google.com
+
+# Escalations:
+per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/config/hiddenapi-force-blocked.txt b/boot/hiddenapi/hiddenapi-force-blocked.txt
similarity index 100%
rename from config/hiddenapi-force-blocked.txt
rename to boot/hiddenapi/hiddenapi-force-blocked.txt
diff --git a/config/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
similarity index 100%
rename from config/hiddenapi-max-target-o.txt
rename to boot/hiddenapi/hiddenapi-max-target-o.txt
diff --git a/config/hiddenapi-max-target-p.txt b/boot/hiddenapi/hiddenapi-max-target-p.txt
similarity index 100%
rename from config/hiddenapi-max-target-p.txt
rename to boot/hiddenapi/hiddenapi-max-target-p.txt
diff --git a/config/hiddenapi-max-target-q.txt b/boot/hiddenapi/hiddenapi-max-target-q.txt
similarity index 100%
rename from config/hiddenapi-max-target-q.txt
rename to boot/hiddenapi/hiddenapi-max-target-q.txt
diff --git a/config/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
similarity index 100%
rename from config/hiddenapi-max-target-r-loprio.txt
rename to boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
diff --git a/config/hiddenapi-unsupported-packages.txt b/boot/hiddenapi/hiddenapi-unsupported-packages.txt
similarity index 100%
rename from config/hiddenapi-unsupported-packages.txt
rename to boot/hiddenapi/hiddenapi-unsupported-packages.txt
diff --git a/config/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
similarity index 99%
rename from config/hiddenapi-unsupported.txt
rename to boot/hiddenapi/hiddenapi-unsupported.txt
index 8a377ac..48a9782 100644
--- a/config/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -209,7 +209,6 @@
 Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
 Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
-Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
 Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
 Landroid/service/notification/INotificationListener$Stub;-><init>()V
 Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
diff --git a/core/api/current.txt b/core/api/current.txt
index 6b137ea..5a2b8bd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12139,6 +12139,7 @@
     field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
     field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
     field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+    field public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
     field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
     field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential";
@@ -25702,12 +25703,13 @@
 
   public final class VcnGatewayConnectionConfig {
     method @NonNull public int[] getExposedCapabilities();
+    method @NonNull public String getGatewayConnectionName();
     method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
     method @NonNull public long[] getRetryInterval();
   }
 
   public static final class VcnGatewayConnectionConfig.Builder {
-    ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
+    ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.vcn.VcnControlPlaneConfig);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
@@ -25731,7 +25733,7 @@
 
   public abstract static class VcnManager.VcnStatusCallback {
     ctor public VcnManager.VcnStatusCallback();
-    method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
+    method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable);
     method public abstract void onStatusChanged(int);
   }
 
@@ -33996,8 +33998,8 @@
 
   public static final class SimPhonebookContract.SimRecords {
     method @NonNull public static android.net.Uri getContentUri(int, int);
-    method @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
-    method @NonNull public static android.net.Uri getItemUri(int, int, int);
+    method @IntRange(from=0) @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
+    method @NonNull public static android.net.Uri getItemUri(int, int, @IntRange(from=1) int);
     field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-contact_v2";
     field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-contact_v2";
     field public static final String ELEMENTARY_FILE_TYPE = "elementary_file_type";
@@ -40411,6 +40413,7 @@
   public final class PreciseDataConnectionState implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.telephony.data.ApnSetting getApnSetting();
+    method public int getId();
     method public int getLastCauseCode();
     method @Nullable public android.net.LinkProperties getLinkProperties();
     method public int getNetworkType();
@@ -41366,6 +41369,7 @@
     field public static final int PROTOCOL_NON_IP = 4; // 0x4
     field public static final int PROTOCOL_PPP = 3; // 0x3
     field public static final int PROTOCOL_UNSTRUCTURED = 5; // 0x5
+    field public static final int TYPE_BIP = 8192; // 0x2000
     field public static final int TYPE_CBS = 128; // 0x80
     field public static final int TYPE_DEFAULT = 17; // 0x11
     field public static final int TYPE_DUN = 8; // 0x8
@@ -41377,6 +41381,7 @@
     field public static final int TYPE_MCX = 1024; // 0x400
     field public static final int TYPE_MMS = 2; // 0x2
     field public static final int TYPE_SUPL = 4; // 0x4
+    field public static final int TYPE_VSIM = 4096; // 0x1000
     field public static final int TYPE_XCAP = 2048; // 0x800
   }
 
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ee53be5..e9dba8e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -23,13 +23,10 @@
 package android.content {
 
   public abstract class Context {
+    field public static final String PAC_PROXY_SERVICE = "pac_proxy";
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
-  }
-
 }
 
 package android.net {
@@ -50,7 +47,6 @@
     method @NonNull public static String blockedReasonsToString(int);
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network);
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int);
-    method public static boolean isUidBlocked(int, boolean);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4676523..f31cd63 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -155,6 +155,7 @@
     field public static final String NETWORK_SIGNAL_STRENGTH_WAKEUP = "android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP";
     field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
     field public static final String NETWORK_STATS_PROVIDER = "android.permission.NETWORK_STATS_PROVIDER";
+    field public static final String NFC_SET_CONTROLLER_ALWAYS_ON = "android.permission.NFC_SET_CONTROLLER_ALWAYS_ON";
     field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
     field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
     field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -6442,9 +6443,11 @@
     method public void notifyAlertReached();
     method public void notifyLimitReached();
     method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
+    method public void notifyWarningReached();
     method public abstract void onRequestStatsUpdate(int);
     method public abstract void onSetAlert(long);
     method public abstract void onSetLimit(@NonNull String, long);
+    method public void onSetWarningAndLimit(@NonNull String, long, long);
     field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
   }
 
@@ -6723,14 +6726,20 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnEnabled();
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnSupported();
+    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
+    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
+    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setAlwaysOn(boolean);
+    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnStateCallback(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
     field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
   }
 
+  public static interface NfcAdapter.ControllerAlwaysOnStateCallback {
+    method public void onStateChanged(boolean);
+  }
+
   public static interface NfcAdapter.NfcUnlockHandler {
     method public boolean onUnlockAttempted(android.nfc.Tag);
   }
@@ -9431,7 +9440,14 @@
     method @NonNull public static android.os.PersistableBundle getDefaultConfig();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void updateConfigForPhoneId(int, String);
+    field public static final int GBA_DIGEST = 3; // 0x3
+    field public static final int GBA_ME = 1; // 0x1
+    field public static final int GBA_U = 2; // 0x2
     field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
+    field public static final String KEY_GBA_MODE_INT = "gba_mode_int";
+    field public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT = "gba_ua_security_organization_int";
+    field public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int";
+    field public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int";
     field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
   }
 
@@ -9785,7 +9801,6 @@
     method @Deprecated public int getDataConnectionApnTypeBitMask();
     method @Deprecated public int getDataConnectionFailCause();
     method @Deprecated public int getDataConnectionState();
-    method public int getId();
   }
 
   public final class PreciseDisconnectCause {
@@ -10542,6 +10557,7 @@
     method public static int getApnTypeInt(@NonNull String);
     method @NonNull public static String getApnTypeString(int);
     field public static final String TYPE_ALL_STRING = "*";
+    field public static final String TYPE_BIP_STRING = "bip";
     field public static final String TYPE_CBS_STRING = "cbs";
     field public static final String TYPE_DEFAULT_STRING = "default";
     field public static final String TYPE_DUN_STRING = "dun";
@@ -10553,6 +10569,7 @@
     field public static final String TYPE_MCX_STRING = "mcx";
     field public static final String TYPE_MMS_STRING = "mms";
     field public static final String TYPE_SUPL_STRING = "supl";
+    field public static final String TYPE_VSIM_STRING = "vsim";
     field public static final String TYPE_XCAP_STRING = "xcap";
   }
 
@@ -11974,10 +11991,11 @@
     method public int describeContents();
     method @Nullable public String getCallIdParameter();
     method @NonNull public byte[] getContent();
-    method @NonNull public byte[] getEncodedMessage();
+    method @Deprecated @NonNull public byte[] getEncodedMessage();
     method @NonNull public String getHeaderSection();
     method @NonNull public String getStartLine();
-    method @Nullable public String getViaBranchParameter();
+    method @NonNull public String getViaBranchParameter();
+    method @NonNull public byte[] toEncodedMessage();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
   }
@@ -12066,13 +12084,13 @@
     ctor @Deprecated public RcsFeature();
     ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
-    method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+    method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+    method public void destroyCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
     method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
     method public boolean queryCapabilityConfiguration(int, int);
     method @NonNull public final android.telephony.ims.feature.RcsFeature.RcsImsCapabilities queryCapabilityStatus();
-    method public void removeCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
   }
 
   public static class RcsFeature.RcsImsCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
@@ -12284,7 +12302,7 @@
   }
 
   public class RcsCapabilityExchangeImplBase {
-    ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
+    ctor public RcsCapabilityExchangeImplBase();
     method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
     method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
     method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
@@ -12481,7 +12499,7 @@
   public final class DistanceMeasurement implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
-    method public double getErrorMeters();
+    method @FloatRange(from=0.0) public double getErrorMeters();
     method public double getMeters();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
@@ -12490,8 +12508,8 @@
   public static final class DistanceMeasurement.Builder {
     ctor public DistanceMeasurement.Builder();
     method @NonNull public android.uwb.DistanceMeasurement build();
-    method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
-    method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+    method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double);
+    method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(@FloatRange(from=0.0) double);
     method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1d094c3..0c57f4e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -9,8 +9,10 @@
     field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
     field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
     field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+    field public static final String CLEAR_FREEZE_PERIOD = "android.permission.CLEAR_FREEZE_PERIOD";
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
+    field public static final String FORCE_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
     field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
@@ -19,10 +21,11 @@
     field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
     field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
     field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
-    field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
+    field public static final String QUERY_AUDIO_STATE = "android.permission.QUERY_AUDIO_STATE";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
@@ -1064,6 +1067,7 @@
     field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
     field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
     field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
+    field public static final int NFC_UID = 1027; // 0x403
     field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
   }
 
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 2fdf9c1..919f1e2 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -10,6 +10,15 @@
 }
 
 filegroup {
+    name: "framework-core-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+filegroup {
     name: "IKeyAttestationApplicationIdProvider.aidl",
     srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
 }
@@ -23,3 +32,98 @@
     name: "ITracingServiceProxy.aidl",
     srcs: ["android/tracing/ITracingServiceProxy.aidl"],
 }
+
+// These are subset of framework-core-sources that are needed by the
+// android.test.mock library. The implementation of android.test.mock references
+// private members of various components to allow mocking of classes that cannot
+// be mocked without access to those internal implementation details.
+filegroup {
+    name: "framework-core-sources-for-test-mock",
+    srcs: [
+        "android/accounts/AccountManagerCallback.java",
+        "android/accounts/AccountManagerFuture.java",
+        "android/accounts/AccountManager.java",
+        "android/accounts/AccountsException.java",
+        "android/accounts/AuthenticatorException.java",
+        "android/accounts/OperationCanceledException.java",
+        "android/annotation/AnimatorRes.java",
+        "android/annotation/AnimRes.java",
+        "android/annotation/AnyRes.java",
+        "android/annotation/ArrayRes.java",
+        "android/annotation/AttrRes.java",
+        "android/annotation/BoolRes.java",
+        "android/annotation/BroadcastBehavior.java",
+        "android/annotation/CallbackExecutor.java",
+        "android/annotation/CallSuper.java",
+        "android/annotation/CheckResult.java",
+        "android/annotation/ColorInt.java",
+        "android/annotation/ColorRes.java",
+        "android/annotation/DimenRes.java",
+        "android/annotation/DrawableRes.java",
+        "android/annotation/FontRes.java",
+        "android/annotation/FractionRes.java",
+        "android/annotation/IntDef.java",
+        "android/annotation/IntegerRes.java",
+        "android/annotation/IntRange.java",
+        "android/annotation/LayoutRes.java",
+        "android/annotation/NonNull.java",
+        "android/annotation/Nullable.java",
+        "android/annotation/PluralsRes.java",
+        "android/annotation/RawRes.java",
+        "android/annotation/RequiresPermission.java",
+        "android/annotation/SdkConstant.java",
+        "android/annotation/Size.java",
+        "android/annotation/StringDef.java",
+        "android/annotation/StringRes.java",
+        "android/annotation/StyleableRes.java",
+        "android/annotation/StyleRes.java",
+        "android/annotation/SuppressLint.java",
+        "android/annotation/SystemApi.java",
+        "android/annotation/SystemService.java",
+        "android/annotation/TestApi.java",
+        "android/annotation/UserIdInt.java",
+        "android/annotation/XmlRes.java",
+        "android/app/Application.java",
+        "android/app/IApplicationThread.aidl",
+        "android/app/IServiceConnection.aidl",
+        "android/app/PackageDeleteObserver.java",
+        "android/content/ComponentCallbacks2.java",
+        "android/content/ComponentCallbacks.java",
+        "android/content/ContentInterface.java",
+        "android/content/ContentProvider.java",
+        "android/content/ContentProviderNative.java",
+        "android/content/ContentResolver.java",
+        "android/content/Context.java",
+        "android/content/ContextWrapper.java",
+        "android/content/DialogInterface.java",
+        "android/content/IContentProvider.java",
+        "android/content/Intent.java",
+        "android/content/IntentSender.java",
+        "android/content/OperationApplicationException.java",
+        "android/content/pm/ActivityInfo.java",
+        "android/content/pm/ApplicationInfo.java",
+        "android/content/pm/InstantAppInfo.java",
+        "android/content/pm/IPackageDataObserver.aidl",
+        "android/content/pm/KeySet.java",
+        "android/content/pm/PackageManager.java",
+        "android/content/pm/VerifierDeviceIdentity.java",
+        "android/content/res/Resources.java",
+        "android/database/CrossProcessCursor.java",
+        "android/database/CrossProcessCursorWrapper.java",
+        "android/database/Cursor.java",
+        "android/database/CursorWrapper.java",
+        "android/os/Binder.java",
+        "android/os/Bundle.java",
+        "android/os/IBinder.java",
+        "android/os/IInterface.java",
+        "android/os/Parcelable.java",
+        "android/os/ParcelFileDescriptor.java",
+        "android/os/RemoteException.java",
+        "android/os/storage/VolumeInfo.java",
+        "android/util/AndroidException.java",
+        "android/view/DisplayAdjustments.java",
+        "android/view/ViewDebug.java",
+        "com/android/internal/annotations/VisibleForTesting.java",
+    ],
+    visibility: ["//frameworks/base/test-mock"],
+}
diff --git a/core/java/android/annotation/MainThread.java b/core/java/android/annotation/MainThread.java
index 556fdb4..a070246 100644
--- a/core/java/android/annotation/MainThread.java
+++ b/core/java/android/annotation/MainThread.java
@@ -21,8 +21,6 @@
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.os.Looper;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
@@ -40,8 +38,7 @@
  * </code>
  * </pre>
  *
- * @memberDoc This method must be called from the
- *            {@linkplain Looper#getMainLooper() main thread} of your app.
+ * @memberDoc This method must be called from the main thread of your app.
  * @hide
  */
 @Retention(SOURCE)
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fe9ed27..4293ab0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4026,6 +4026,7 @@
      * @see android.net.PacProxyManager
      * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final String PAC_PROXY_SERVICE = "pac_proxy";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4d68e90..0fad63f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2324,14 +2324,6 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
     /**
-     * Clear DNS Cache Action: This is broadcast when networks have changed and old
-     * DNS entries should be tossed.
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
-    /**
      * Alarm Changed Action: This is broadcast when the AlarmClock
      * application's alarm is set or unset.  It is used by the
      * AlarmClock application and the StatusBar service.
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 01b554a..1735aa2 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -5,6 +5,7 @@
 per-file IntentFilter.java = patb@google.com
 per-file Intent.java = toddke@google.com
 per-file Intent.java = patb@google.com
+per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
 per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
 per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6ec1169..ad9e31b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2167,7 +2167,10 @@
         return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
     }
 
-    /** @hide */
+    /**
+     * True if the application is pre-installed on the OEM partition of the system image.
+     * @hide
+     */
     @SystemApi
     public boolean isOem() {
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
@@ -2215,13 +2218,19 @@
         return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
-    /** @hide */
+    /**
+     * True if the application is pre-installed on the vendor partition of the system image.
+     * @hide
+     */
     @SystemApi
     public boolean isVendor() {
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
-    /** @hide */
+    /**
+     * True if the application is pre-installed on the product partition of the system image.
+     * @hide
+     */
     @SystemApi
     public boolean isProduct() {
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7e17256..23f5e3a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3167,8 +3167,57 @@
     public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
 
     /**
-     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
-     * The device has a StrongBox hardware-backed Keystore.
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+     * the Android Keystore backed by an isolated execution environment. The version indicates
+     * which features are implemented in the isolated execution environment:
+     * <ul>
+     * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+     * for app-generated attestation keys (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+     * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+     * <li>40: Support for wrapped key import (see {@link
+     * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+     * attestation (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+     * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+     * hardware, and support for requiring user authentication before a key can be used.
+     * </ul>
+     * This feature version is guaranteed to be set for all devices launching with Android 12 and
+     * may be set on devices launching with an earlier version. If the feature version is set, it
+     * will at least have the value 40. If it's not set the device may have a version of
+     * hardware-backed keystore but it may not support all features listed above.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures}, {@link #hasSystemFeature(String)}, and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+     * the Android Keystore backed by a dedicated secure processor referred to as
+     * <a href="https://source.android.com/security/best-practices/hardware#strongbox-keymaster">
+     * StrongBox</a>. If this feature has a version, the version number indicates which features are
+     * implemented in StrongBox:
+     * <ul>
+     * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+     * for app-generated attestation keys (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+     * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+     * <li>40: Support for wrapped key import (see {@link
+     * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+     * attestation (see {@link
+     * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+     * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+     * hardware, and support for requiring user authentication before a key can be used.
+     * </ul>
+     * If a device has StrongBox, this feature version number is guaranteed to be set for all
+     * devices launching with Android 12 and may be set on devices launching with an earlier
+     * version. If the feature version is set, it will at least have the value 40. If it's not
+     * set the device may have StrongBox but it may not support all features listed above.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_STRONGBOX_KEYSTORE =
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 933dee3..609da31 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1363,6 +1363,8 @@
                     // devices going offline (in real world scenarios, these permissions aren't
                     // changeable). Future calls to getCameraIdList() will reflect the changes in
                     // the camera id list after getCameraIdListNoLazy() is called.
+                    // We need to remove the torch ids which may have been associated with the
+                    // devices removed as well. This is the same situation.
                     cameraStatuses = mCameraService.addListener(testListener);
                     mCameraService.removeListener(testListener);
                     for (CameraStatus c : cameraStatuses) {
@@ -1381,6 +1383,7 @@
                     }
                     for (String id : deviceIdsToRemove) {
                         onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, id);
+                        mTorchStatus.remove(id);
                     }
                 } catch (ServiceSpecificException e) {
                     // Unexpected failure
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index f13326b..d06bc1d 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -84,7 +84,6 @@
      *         of the result
      */
     public void oneTouchPlay(OneTouchPlayCallback callback) {
-        // TODO: Use PendingResult.
         try {
             mService.oneTouchPlay(getCallbackWrapper(callback));
         } catch (RemoteException e) {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 171c6a2..f50aa99 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -78,5 +78,4 @@
 
     boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
     boolean isUidRestrictedOnMeteredNetworks(int uid);
-    boolean checkUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered, boolean isBackgroundRestricted);
 }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index b037261..1eef7d9 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -198,15 +198,11 @@
         final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
 
         if (legacyType == TYPE_WIFI) {
-            if (snapshot.networkCapabilities.getSsid() != null) {
-                networkId = snapshot.networkCapabilities.getSsid();
-                if (networkId == null) {
-                    // TODO: Figure out if this code path never runs. If so, remove them.
-                    final WifiManager wifi = (WifiManager) context.getSystemService(
-                            Context.WIFI_SERVICE);
-                    final WifiInfo info = wifi.getConnectionInfo();
-                    networkId = info != null ? info.getSSID() : null;
-                }
+            networkId = snapshot.networkCapabilities.getSsid();
+            if (networkId == null) {
+                final WifiManager wifi = context.getSystemService(WifiManager.class);
+                final WifiInfo info = wifi.getConnectionInfo();
+                networkId = info != null ? info.getSSID() : null;
             }
         }
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 40fbfbb..b074fad 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.procStateToString;
 import static android.content.pm.PackageManager.GET_SIGNATURES;
-import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -204,9 +203,6 @@
     })
     public @interface SubscriptionOverrideMask {}
 
-    /** @hide */
-    public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
-
     /**
      * Flag to indicate that app is not exempt from any network restrictions.
      *
@@ -568,31 +564,6 @@
     }
 
     /**
-     * Figure out if networking is blocked for a given set of conditions.
-     *
-     * This is used by ConnectivityService via passing stale copies of conditions, so it must not
-     * take any locks.
-     *
-     * @param uid The target uid.
-     * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
-     * @param isNetworkMetered True if the network is metered.
-     * @param isBackgroundRestricted True if data saver is enabled.
-     *
-     * @return true if networking is blocked for the UID under the specified conditions.
-     *
-     * @hide
-     */
-    public boolean checkUidNetworkingBlocked(int uid, int uidRules,
-            boolean isNetworkMetered, boolean isBackgroundRestricted) {
-        try {
-            return mService.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
-                    isBackgroundRestricted);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Check that the given uid is restricted from doing networking on metered networks.
      *
      * @param uid The target uid.
@@ -789,36 +760,6 @@
     }
 
     /**
-     * Returns whether network access of an UID is blocked or not based on {@code blockedReasons}
-     * corresponding to it.
-     *
-     * {@code blockedReasons} would be a bitwise {@code OR} combination of the
-     * {@code BLOCKED_REASON_*} and/or {@code BLOCKED_METERED_REASON_*} constants.
-     *
-     * @param blockedReasons Value indicating the reasons for why the network access of an UID is
-     *                       blocked. If the value is equal to
-     *                       {@link ConnectivityManager#BLOCKED_REASON_NONE}, then
-     *                       it indicates that an app's network access is not blocked.
-     * @param meteredNetwork Value indicating whether the network is metered or not.
-     * @return Whether network access is blocked or not.
-     * @hide
-     */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public static boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
-        if (blockedReasons == BLOCKED_REASON_NONE) {
-            return false;
-        }
-        final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
-        if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
-            return true;
-        }
-        if (meteredNetwork) {
-            return blockedReasons != BLOCKED_REASON_NONE;
-        }
-        return false;
-    }
-
-    /**
      * Returns the {@code string} representation of {@code blockedReasons} argument.
      *
      * @param blockedReasons Value indicating the reasons for why the network access of an UID is
@@ -831,6 +772,12 @@
         return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons);
     }
 
+    /** @hide */
+    @NonNull
+    public static String allowedReasonsToString(int allowedReasons) {
+        return DebugUtils.flagsToString(NetworkPolicyManager.class, "ALLOWED_", allowedReasons);
+    }
+
     /**
      * Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status
      * of apps.
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
index 4078b24..74c3ba4 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
@@ -23,6 +23,6 @@
  */
 oneway interface INetworkStatsProvider {
     void onRequestStatsUpdate(int token);
-    void onSetLimit(String iface, long quotaBytes);
     void onSetAlert(long quotaBytes);
+    void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes);
 }
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index bd336dd..7eaa01e 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,6 @@
 oneway interface INetworkStatsProviderCallback {
     void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
     void notifyAlertReached();
-    void notifyLimitReached();
+    void notifyWarningOrLimitReached();
     void unregister();
 }
diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
index 7639d22..23fc069 100644
--- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
@@ -29,7 +29,8 @@
 @SystemApi
 public abstract class NetworkStatsProvider {
     /**
-     * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit.
+     * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit}
+     * indicates there is no limit.
      */
     public static final int QUOTA_UNLIMITED = -1;
 
@@ -42,13 +43,13 @@
         }
 
         @Override
-        public void onSetLimit(String iface, long quotaBytes) {
-            NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
+        public void onSetAlert(long quotaBytes) {
+            NetworkStatsProvider.this.onSetAlert(quotaBytes);
         }
 
         @Override
-        public void onSetAlert(long quotaBytes) {
-            NetworkStatsProvider.this.onSetAlert(quotaBytes);
+        public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {
+            NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes);
         }
     };
 
@@ -145,11 +146,25 @@
     }
 
     /**
-     * Notify system that the quota set by {@code onSetLimit} has been reached.
+     * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
+     */
+    public void notifyWarningReached() {
+        try {
+            // Reuse the code path to notify warning reached with limit reached
+            // since framework handles them in the same way.
+            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Notify system that the quota set by {@link #onSetLimit} or limit set by
+     * {@link #onSetWarningAndLimit} has been reached.
      */
     public void notifyLimitReached() {
         try {
-            getProviderCallbackBinderOrThrow().notifyLimitReached();
+            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -183,6 +198,28 @@
     public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
 
     /**
+     * Called by {@code NetworkStatsService} when setting the interface quotas for the specified
+     * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
+     * will not call {@link #onSetLimit}. When this method is called, the implementation
+     * should behave as follows:
+     *   1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
+     *      {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
+     *   2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
+     *   {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
+     *
+     * @param iface the interface requiring the operation.
+     * @param warningBytes the warning defined as the number of bytes, starting from zero and
+     *                     counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
+     *                     there is no warning.
+     * @param limitBytes the limit defined as the number of bytes, starting from zero and counting
+     *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
+     */
+    public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
+        // Backward compatibility for those who didn't override this function.
+        onSetLimit(iface, limitBytes);
+    }
+
+    /**
      * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
      * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
      * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index 236ae8b..11bc443 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -20,7 +20,7 @@
 oneway interface IVcnStatusCallback {
     void onVcnStatusChanged(int statusCode);
     void onGatewayConnectionError(
-            in int[] gatewayNetworkCapabilities,
+            in String gatewayConnectionName,
             int errorCode,
             in String exceptionClass,
             in String exceptionMessage);
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 52cc218..d41c0b4 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -183,12 +183,25 @@
          *
          * @param gatewayConnectionConfig the configuration for an individual gateway connection
          * @return this {@link Builder} instance, for chaining
+         * @throws IllegalArgumentException if a VcnGatewayConnectionConfig has already been set for
+         *     this {@link VcnConfig} with the same GatewayConnection name (as returned via {@link
+         *     VcnGatewayConnectionConfig#getGatewayConnectionName()}).
          */
         @NonNull
         public Builder addGatewayConnectionConfig(
                 @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
             Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null");
 
+            for (final VcnGatewayConnectionConfig vcnGatewayConnectionConfig :
+                    mGatewayConnectionConfigs) {
+                if (vcnGatewayConnectionConfig
+                        .getGatewayConnectionName()
+                        .equals(gatewayConnectionConfig.getGatewayConnectionName())) {
+                    throw new IllegalArgumentException(
+                            "GatewayConnection for specified name already exists");
+                }
+            }
+
             mGatewayConnectionConfigs.add(gatewayConnectionConfig);
             return this;
         }
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index d4e8e2d..75db382 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -148,6 +148,8 @@
                 TimeUnit.MINUTES.toMillis(5),
                 TimeUnit.MINUTES.toMillis(15)
             };
+    private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
+    @NonNull private final String mGatewayConnectionName;
 
     private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig";
     @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig;
@@ -166,11 +168,13 @@
 
     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
     private VcnGatewayConnectionConfig(
+            @NonNull String gatewayConnectionName,
             @NonNull VcnControlPlaneConfig ctrlPlaneConfig,
             @NonNull Set<Integer> exposedCapabilities,
             @NonNull Set<Integer> underlyingCapabilities,
             @NonNull long[] retryIntervalsMs,
             @IntRange(from = MIN_MTU_V6) int maxMtu) {
+        mGatewayConnectionName = gatewayConnectionName;
         mCtrlPlaneConfig = ctrlPlaneConfig;
         mExposedCapabilities = new TreeSet(exposedCapabilities);
         mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
@@ -192,6 +196,7 @@
         final PersistableBundle underlyingCapsBundle =
                 in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
 
+        mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
         mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle);
         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
@@ -204,6 +209,7 @@
     }
 
     private void validate() {
+        Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
         Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null");
 
         Preconditions.checkArgument(
@@ -242,6 +248,20 @@
     }
 
     /**
+     * Returns the configured Gateway Connection name.
+     *
+     * <p>This name is used by the configuring apps to distinguish between
+     * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as
+     * the identifier in VcnStatusCallback invocations.
+     *
+     * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
+     */
+    @NonNull
+    public String getGatewayConnectionName() {
+        return mGatewayConnectionName;
+    }
+
+    /**
      * Returns control plane configuration.
      *
      * @hide
@@ -364,6 +384,7 @@
                         new ArrayList<>(mUnderlyingCapabilities),
                         PersistableBundleUtils.INTEGER_SERIALIZER);
 
+        result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
         result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle);
         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
         result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
@@ -376,6 +397,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(
+                mGatewayConnectionName,
                 mExposedCapabilities,
                 mUnderlyingCapabilities,
                 Arrays.hashCode(mRetryIntervalsMs),
@@ -389,7 +411,8 @@
         }
 
         final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
-        return mExposedCapabilities.equals(rhs.mExposedCapabilities)
+        return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
+                && mExposedCapabilities.equals(rhs.mExposedCapabilities)
                 && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
                 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
                 && mMaxMtu == rhs.mMaxMtu;
@@ -399,6 +422,7 @@
      * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
      */
     public static final class Builder {
+        @NonNull private final String mGatewayConnectionName;
         @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig;
         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
         @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@@ -412,12 +436,22 @@
         /**
          * Construct a Builder object.
          *
+         * @param gatewayConnectionName the String GatewayConnection name for this
+         *     VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link
+         *     VcnConfig} must be given a unique name. This name is used by the caller to
+         *     distinguish between VcnGatewayConnectionConfigs configured on a single {@link
+         *     VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
          * @param ctrlPlaneConfig the control plane configuration
          * @see VcnControlPlaneConfig
+         * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
          */
-        public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+        public Builder(
+                @NonNull String gatewayConnectionName,
+                @NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+            Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
             Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null");
 
+            mGatewayConnectionName = gatewayConnectionName;
             mCtrlPlaneConfig = ctrlPlaneConfig;
         }
 
@@ -562,6 +596,7 @@
         @NonNull
         public VcnGatewayConnectionConfig build() {
             return new VcnGatewayConnectionConfig(
+                    mGatewayConnectionName,
                     mCtrlPlaneConfig,
                     mExposedCapabilities,
                     mUnderlyingCapabilities,
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index abd41da..344b20c 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -437,7 +437,7 @@
          * Invoked when status of the VCN for this callback's subscription group changes.
          *
          * @param statusCode the code for the status change encountered by this {@link
-         *     VcnStatusCallback}'s subscription group.
+         *     VcnStatusCallback}'s subscription group. This value will be one of VCN_STATUS_CODE_*.
          */
         public abstract void onStatusChanged(@VcnStatusCode int statusCode);
 
@@ -445,18 +445,17 @@
          * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
          * encounters an error.
          *
-         * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
-         *     for the Gateway Connection that encountered the error, for identification purposes.
-         *     These will be a sorted list with no duplicates and will match {@link
-         *     VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link
-         *     VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
-         *     group.
-         * @param errorCode the code to indicate the error that occurred
+         * @param gatewayConnectionName the String GatewayConnection name for the GatewayConnection
+         *     encountering an error. This will match the name for exactly one {@link
+         *     VcnGatewayConnectionConfig} for the {@link VcnConfig} configured for this callback's
+         *     subscription group
+         * @param errorCode the code to indicate the error that occurred. This value will be one of
+         *     VCN_ERROR_CODE_*.
          * @param detail Throwable to provide additional information about the error, or {@code
          *     null} if none
          */
         public abstract void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable Throwable detail);
     }
@@ -586,7 +585,7 @@
         // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
@@ -597,7 +596,7 @@
                             mExecutor.execute(
                                     () ->
                                             mCallback.onGatewayConnectionError(
-                                                    networkCapabilities, errorCode, cause)));
+                                                    gatewayConnectionName, errorCode, cause)));
         }
 
         private static Throwable createThrowableByClassName(
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index bc3d5c4..d5cc01a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -24,6 +24,7 @@
 import android.nfc.TechListParcel;
 import android.nfc.IAppCallback;
 import android.nfc.INfcAdapterExtras;
+import android.nfc.INfcControllerAlwaysOnStateCallback;
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
 import android.nfc.INfcFCardEmulation;
@@ -72,7 +73,9 @@
     boolean deviceSupportsNfcSecure();
     boolean setNfcSecure(boolean enable);
 
-    boolean setAlwaysOn(boolean value);
-    boolean isAlwaysOnEnabled();
-    boolean isAlwaysOnSupported();
+    boolean setControllerAlwaysOn(boolean value);
+    boolean isControllerAlwaysOn();
+    boolean isControllerAlwaysOnSupported();
+    void registerControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
+    void unregisterControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
 }
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
new file mode 100644
index 0000000..1e4fdd7
--- /dev/null
+++ b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+/**
+ * @hide
+ */
+oneway interface INfcControllerAlwaysOnStateCallback {
+  /**
+   * Called whenever the controller always on state changes
+   *
+   * @param isEnabled true if the state is enabled, false otherwise
+   */
+  void onControllerAlwaysOnStateChanged(boolean isEnabled);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e85eb93..bbf802c 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,7 @@
 
 package android.nfc;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -47,6 +48,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Represents the local NFC adapter.
@@ -65,6 +67,8 @@
 public final class NfcAdapter {
     static final String TAG = "NFC";
 
+    private final NfcControllerAlwaysOnStateListener mControllerAlwaysOnStateListener;
+
     /**
      * Intent to start an activity when a tag with NDEF payload is discovered.
      *
@@ -350,22 +354,6 @@
             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
 
     /** @hide */
-    public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
-            "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
-
-    /**
-     * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
-     * intents to request the current power state. Possible values are:
-     * {@link #STATE_OFF},
-     * {@link #STATE_TURNING_ON},
-     * {@link #STATE_ON},
-     * {@link #STATE_TURNING_OFF},
-     * @hide
-     */
-    public static final String EXTRA_ALWAYS_ON_STATE =
-            "android.nfc.extra.ALWAYS_ON_STATE";
-
-    /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
     /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -430,6 +418,22 @@
     }
 
     /**
+     * A callback to be invoked when NFC controller always on state changes.
+     * <p>Register your {@code ControllerAlwaysOnStateCallback} implementation with {@link
+     * NfcAdapter#registerControllerAlwaysOnStateCallback} and disable it with {@link
+     * NfcAdapter#unregisterControllerAlwaysOnStateCallback}.
+     * @see #registerControllerAlwaysOnStateCallback
+     * @hide
+     */
+    @SystemApi
+    public interface ControllerAlwaysOnStateCallback {
+        /**
+         * Called on NFC controller always on state changes
+         */
+        void onStateChanged(boolean isEnabled);
+    }
+
+    /**
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
      * @see #setOnNdefPushCompleteCallback
@@ -744,6 +748,7 @@
         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
         mTagRemovedListener = null;
         mLock = new Object();
+        mControllerAlwaysOnStateListener = new NfcControllerAlwaysOnStateListener(getService());
     }
 
     /**
@@ -2239,14 +2244,16 @@
     /**
      * Sets NFC controller always on feature.
      * <p>This API is for the NFCC internal state management. It allows to discriminate
-     * the controller function from the NFC function by keeping the NFC Controller on without
+     * the controller function from the NFC function by keeping the NFC controller on without
      * any NFC RF enabled if necessary.
-     * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
-     * broadcasts to find out when the operation is complete.
-     * <p>If this returns true, then either NFCC is already on, or
-     * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
-     * a state transition.
-     * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+     * <p>This call is asynchronous. Register a callback {@link #ControllerAlwaysOnStateCallback}
+     * by {@link #registerControllerAlwaysOnStateCallback} to find out when the operation is
+     * complete.
+     * <p>If this returns true, then either NFCC always on state has been set based on the value,
+     * or a {@link ControllerAlwaysOnStateCallback#onStateChanged(boolean)} will be invoked to
+     * indicate the state change.
+     * If this returns false, then there is some problem that prevents an attempt to turn NFCC
+     * always on.
      * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
      * disabled), if false the NFCC will follow completely the Nfc adapter state.
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
@@ -2254,13 +2261,13 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public boolean setAlwaysOn(boolean value) {
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public boolean setControllerAlwaysOn(boolean value) {
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
         try {
-            return sService.setAlwaysOn(value);
+            return sService.setControllerAlwaysOn(value);
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             // Try one more time
@@ -2269,7 +2276,7 @@
                 return false;
             }
             try {
-                return sService.setAlwaysOn(value);
+                return sService.setControllerAlwaysOn(value);
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to recover NFC Service.");
             }
@@ -2284,12 +2291,11 @@
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      * @hide
      */
-
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public boolean isAlwaysOnEnabled() {
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public boolean isControllerAlwaysOn() {
         try {
-            return sService.isAlwaysOnEnabled();
+            return sService.isControllerAlwaysOn();
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             // Try one more time
@@ -2298,7 +2304,7 @@
                 return false;
             }
             try {
-                return sService.isAlwaysOnEnabled();
+                return sService.isControllerAlwaysOn();
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to recover NFC Service.");
             }
@@ -2313,15 +2319,14 @@
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      * @hide
      */
-
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public boolean isAlwaysOnSupported() {
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public boolean isControllerAlwaysOnSupported() {
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
         try {
-            return sService.isAlwaysOnSupported();
+            return sService.isControllerAlwaysOnSupported();
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             // Try one more time
@@ -2330,11 +2335,46 @@
                 return false;
             }
             try {
-                return sService.isAlwaysOnSupported();
+                return sService.isControllerAlwaysOnSupported();
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to recover NFC Service.");
             }
             return false;
         }
     }
+
+    /**
+     * Register a {@link ControllerAlwaysOnStateCallback} to listen for NFC controller always on
+     * state changes
+     * <p>The provided callback will be invoked by the given {@link Executor}.
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public void registerControllerAlwaysOnStateCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull ControllerAlwaysOnStateCallback callback) {
+        mControllerAlwaysOnStateListener.register(executor, callback);
+    }
+
+    /**
+     * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+     * <p>The same {@link ControllerAlwaysOnStateCallback} object used when calling
+     * {@link #registerControllerAlwaysOnStateCallback(Executor, ControllerAlwaysOnStateCallback)}
+     * must be used.
+     *
+     * <p>Callbacks are automatically unregistered when application process goes away
+     *
+     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public void unregisterControllerAlwaysOnStateCallback(
+            @NonNull ControllerAlwaysOnStateCallback callback) {
+        mControllerAlwaysOnStateListener.unregister(callback);
+    }
 }
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
new file mode 100644
index 0000000..69a9ec7
--- /dev/null
+++ b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class NfcControllerAlwaysOnStateListener extends INfcControllerAlwaysOnStateCallback.Stub {
+    private static final String TAG = "NfcControllerAlwaysOnStateListener";
+
+    private final INfcAdapter mAdapter;
+
+    private final Map<ControllerAlwaysOnStateCallback, Executor> mCallbackMap = new HashMap<>();
+
+    private boolean mCurrentState = false;
+    private boolean mIsRegistered = false;
+
+    public NfcControllerAlwaysOnStateListener(@NonNull INfcAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Register a {@link ControllerAlwaysOnStateCallback} with this
+     * {@link NfcControllerAlwaysOnStateListener}
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+     */
+    public void register(@NonNull Executor executor,
+            @NonNull ControllerAlwaysOnStateCallback callback) {
+        synchronized (this) {
+            if (mCallbackMap.containsKey(callback)) {
+                return;
+            }
+
+            mCallbackMap.put(callback, executor);
+            if (!mIsRegistered) {
+                try {
+                    mAdapter.registerControllerAlwaysOnStateCallback(this);
+                    mIsRegistered = true;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to register ControllerAlwaysOnStateListener");
+                }
+            }
+        }
+    }
+
+    /**
+     * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+     *
+     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+     */
+    public void unregister(@NonNull ControllerAlwaysOnStateCallback callback) {
+        synchronized (this) {
+            if (!mCallbackMap.containsKey(callback)) {
+                return;
+            }
+
+            mCallbackMap.remove(callback);
+
+            if (mCallbackMap.isEmpty() && mIsRegistered) {
+                try {
+                    mAdapter.unregisterControllerAlwaysOnStateCallback(this);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to unregister ControllerAlwaysOnStateListener");
+                }
+                mIsRegistered = false;
+            }
+        }
+    }
+
+    private void sendCurrentState(@NonNull ControllerAlwaysOnStateCallback callback) {
+        synchronized (this) {
+            Executor executor = mCallbackMap.get(callback);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                executor.execute(() -> callback.onStateChanged(
+                        mCurrentState));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
+    public void onControllerAlwaysOnStateChanged(boolean isEnabled) {
+        synchronized (this) {
+            mCurrentState = isEnabled;
+            for (ControllerAlwaysOnStateCallback cb : mCallbackMap.keySet()) {
+                sendCurrentState(cb);
+            }
+        }
+    }
+}
+
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 6425c25..f5130bc 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -543,6 +543,16 @@
     public final native void markVintfStability();
 
     /**
+     * Use a VINTF-stability binder w/o VINTF requirements. Should be called
+     * on a binder before it is sent out of process.
+     *
+     * This must be called before the object is sent to another process.
+     *
+     * @hide
+     */
+    public final native void forceDowngradeToSystemStability();
+
+    /**
      * Flush any Binder commands pending in the current thread to the kernel
      * driver.  This can be
      * useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 189a8ac..03caafd 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -115,15 +115,20 @@
     public static final String HARDWARE = getString("ro.hardware");
 
     /**
-     * The SKU of the hardware (from the kernel command line). The SKU is reported by the bootloader
-     * to configure system software features.
+     * The SKU of the hardware (from the kernel command line).
+     *
+     * <p>The SKU is reported by the bootloader to configure system software features.
+     * If no value is supplied by the bootloader, this is reported as {@link #UNKNOWN}.
+
      */
     @NonNull
     public static final String SKU = getString("ro.boot.hardware.sku");
 
     /**
-     * The SKU of the device as set by the original design manufacturer (ODM). This is a
-     * runtime-initialized property set during startup to configure device services.
+     * The SKU of the device as set by the original design manufacturer (ODM).
+     *
+     * <p>This is a runtime-initialized property set during startup to configure device
+     * services. If no value is set, this is reported as {@link #UNKNOWN}.
      *
      * <p>The ODM SKU may have multiple variants for the same system SKU in case a manufacturer
      * produces variants of the same design. For example, the same build may be released with
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9d16f18..9b29fb1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -127,6 +127,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @TestApi
     public static final int NFC_UID = 1027;
 
     /**
diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java
index 030b863..fb89eb0 100644
--- a/core/java/android/provider/SimPhonebookContract.java
+++ b/core/java/android/provider/SimPhonebookContract.java
@@ -17,13 +17,14 @@
 package android.provider;
 
 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN_PATH_SEGMENT;
 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN_PATH_SEGMENT;
 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN_PATH_SEGMENT;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_ADN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_FDN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_SDN;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.WorkerThread;
@@ -78,11 +79,11 @@
     public static String getEfUriPath(@ElementaryFiles.EfType int efType) {
         switch (efType) {
             case EF_ADN:
-                return EF_ADN_PATH_SEGMENT;
+                return PATH_SEGMENT_EF_ADN;
             case EF_FDN:
-                return EF_FDN_PATH_SEGMENT;
+                return PATH_SEGMENT_EF_FDN;
             case EF_SDN:
-                return EF_SDN_PATH_SEGMENT;
+                return PATH_SEGMENT_EF_SDN;
             default:
                 throw new IllegalArgumentException("Unsupported EfType " + efType);
         }
@@ -109,9 +110,9 @@
      * the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH}
      * characters. The {@link SimRecords#NAME} column can contain at most
      * {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM.
-     * Encoding is done internally and so the name should be provided unencoded but the number of
-     * bytes required to encode it will vary depending on the characters it contains. This length
-     * can be determined by calling
+     * Encoding is done internally and so the name should be provided to these provider APIs as a
+     * Java String but the number of bytes required to encode it for storage will vary depending on
+     * the characters it contains. This length can be determined by calling
      * {@link SimRecords#getEncodedNameLength(ContentResolver, String)}.
      * </p>
      * <h3>Operations </h3>
@@ -308,7 +309,8 @@
          */
         @NonNull
         public static Uri getItemUri(
-                int subscriptionId, @ElementaryFiles.EfType int efType, int recordNumber) {
+                int subscriptionId, @ElementaryFiles.EfType int efType,
+                @IntRange(from = 1) int recordNumber) {
             // Elementary file record indices are 1-based.
             Preconditions.checkArgument(recordNumber > 0, "Invalid recordNumber");
 
@@ -332,6 +334,7 @@
          * @see ElementaryFiles#NAME_MAX_LENGTH
          */
         @WorkerThread
+        @IntRange(from = 0)
         public static int getEncodedNameLength(
                 @NonNull ContentResolver resolver, @NonNull String name) {
             Objects.requireNonNull(name);
@@ -442,12 +445,27 @@
          * methods operating on this Uri will throw UnsupportedOperationException
          */
         public static final int EF_SDN = 3;
-        /** @hide */
-        public static final String EF_ADN_PATH_SEGMENT = "adn";
-        /** @hide */
-        public static final String EF_FDN_PATH_SEGMENT = "fdn";
-        /** @hide */
-        public static final String EF_SDN_PATH_SEGMENT = "sdn";
+        /**
+         * The Uri path segment used to target the ADN elementary file for SimPhonebookProvider
+         * content operations.
+         *
+         * @hide
+         */
+        public static final String PATH_SEGMENT_EF_ADN = "adn";
+        /**
+         * The Uri path segment used to target the FDN elementary file for SimPhonebookProvider
+         * content operations.
+         *
+         * @hide
+         */
+        public static final String PATH_SEGMENT_EF_FDN = "fdn";
+        /**
+         * The Uri path segment used to target the SDN elementary file for SimPhonebookProvider
+         * content operations.
+         *
+         * @hide
+         */
+        public static final String PATH_SEGMENT_EF_SDN = "sdn";
         /** The MIME type of CONTENT_URI providing a directory of ADN-like elementary files. */
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-elementary-file";
         /** The MIME type of a CONTENT_URI subdirectory of a single ADN-like elementary file. */
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 2329037..d8c44ad 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -106,32 +105,6 @@
     private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
             ConfirmationCallback callback) {
         switch (responseCode) {
-            case KeyStore.CONFIRMATIONUI_OK:
-                callback.onConfirmed(dataThatWasConfirmed);
-                break;
-
-            case KeyStore.CONFIRMATIONUI_CANCELED:
-                callback.onDismissed();
-                break;
-
-            case KeyStore.CONFIRMATIONUI_ABORTED:
-                callback.onCanceled();
-                break;
-
-            case KeyStore.CONFIRMATIONUI_SYSTEM_ERROR:
-                callback.onError(new Exception("System error returned by ConfirmationUI."));
-                break;
-
-            default:
-                callback.onError(new Exception("Unexpected responseCode=" + responseCode
-                                + " from onConfirmtionPromptCompleted() callback."));
-                break;
-        }
-    }
-
-    private void doCallback2(int responseCode, byte[] dataThatWasConfirmed,
-            ConfirmationCallback callback) {
-        switch (responseCode) {
             case AndroidProtectedConfirmation.ERROR_OK:
                 callback.onConfirmed(dataThatWasConfirmed);
                 break;
@@ -155,31 +128,6 @@
         }
     }
 
-    private final android.os.IBinder mCallbackBinder =
-            new android.security.IConfirmationPromptCallback.Stub() {
-                @Override
-                public void onConfirmationPromptCompleted(
-                        int responseCode, final byte[] dataThatWasConfirmed)
-                        throws android.os.RemoteException {
-                    if (mCallback != null) {
-                        ConfirmationCallback callback = mCallback;
-                        Executor executor = mExecutor;
-                        mCallback = null;
-                        mExecutor = null;
-                        if (executor == null) {
-                            doCallback(responseCode, dataThatWasConfirmed, callback);
-                        } else {
-                            executor.execute(new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        doCallback(responseCode, dataThatWasConfirmed, callback);
-                                    }
-                                });
-                        }
-                    }
-                }
-            };
-
     private final android.security.apc.IConfirmationCallback mConfirmationCallback =
             new android.security.apc.IConfirmationCallback.Stub() {
                 @Override
@@ -191,11 +139,11 @@
                         mCallback = null;
                         mExecutor = null;
                         if (executor == null) {
-                            doCallback2(result, dataThatWasConfirmed, callback);
+                            doCallback(result, dataThatWasConfirmed, callback);
                         } else {
                             executor.execute(new Runnable() {
                                 @Override public void run() {
-                                    doCallback2(result, dataThatWasConfirmed, callback);
+                                    doCallback(result, dataThatWasConfirmed, callback);
                                 }
                             });
                         }
@@ -266,29 +214,7 @@
         mExtraData = extraData;
     }
 
-    private static final int UI_OPTION_ACCESSIBILITY_INVERTED_FLAG = 1 << 0;
-    private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
-
     private int getUiOptionsAsFlags() {
-        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            return getUiOptionsAsFlags2();
-        }
-        int uiOptionsAsFlags = 0;
-        ContentResolver contentResolver = mContext.getContentResolver();
-        int inversionEnabled = Settings.Secure.getInt(contentResolver,
-                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
-        if (inversionEnabled == 1) {
-            uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
-        }
-        float fontScale = Settings.System.getFloat(contentResolver,
-                Settings.System.FONT_SCALE, (float) 1.0);
-        if (fontScale > 1.0) {
-            uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
-        }
-        return uiOptionsAsFlags;
-    }
-
-    private int getUiOptionsAsFlags2() {
         int uiOptionsAsFlags = 0;
         ContentResolver contentResolver = mContext.getContentResolver();
         int inversionEnabled = Settings.Secure.getInt(contentResolver,
@@ -349,52 +275,26 @@
         mExecutor = executor;
 
         String locale = Locale.getDefault().toLanguageTag();
-        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            int uiOptionsAsFlags = getUiOptionsAsFlags2();
-            int responseCode = getService().presentConfirmationPrompt(
-                    mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
-                    uiOptionsAsFlags);
-            switch (responseCode) {
-                case AndroidProtectedConfirmation.ERROR_OK:
-                    return;
+        int uiOptionsAsFlags = getUiOptionsAsFlags();
+        int responseCode = getService().presentConfirmationPrompt(
+                mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
+                uiOptionsAsFlags);
+        switch (responseCode) {
+            case AndroidProtectedConfirmation.ERROR_OK:
+                return;
 
-                case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
-                    throw new ConfirmationAlreadyPresentingException();
+            case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
+                throw new ConfirmationAlreadyPresentingException();
 
-                case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
-                    throw new ConfirmationNotAvailableException();
+            case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
+                throw new ConfirmationNotAvailableException();
 
-                default:
-                    // Unexpected error code.
-                    Log.w(TAG,
-                            "Unexpected responseCode=" + responseCode
-                                    + " from presentConfirmationPrompt() call.");
-                    throw new IllegalArgumentException();
-            }
-        } else {
-            int uiOptionsAsFlags = getUiOptionsAsFlags();
-            int responseCode = mKeyStore.presentConfirmationPrompt(
-                    mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
-            switch (responseCode) {
-                case KeyStore.CONFIRMATIONUI_OK:
-                    return;
-
-                case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
-                    throw new ConfirmationAlreadyPresentingException();
-
-                case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
-                    throw new ConfirmationNotAvailableException();
-
-                case KeyStore.CONFIRMATIONUI_UIERROR:
-                    throw new IllegalArgumentException();
-
-                default:
-                    // Unexpected error code.
-                    Log.w(TAG,
-                            "Unexpected responseCode=" + responseCode
-                                    + " from presentConfirmationPrompt() call.");
-                    throw new IllegalArgumentException();
-            }
+            default:
+                // Unexpected error code.
+                Log.w(TAG,
+                        "Unexpected responseCode=" + responseCode
+                                + " from presentConfirmationPrompt() call.");
+                throw new IllegalArgumentException();
         }
     }
 
@@ -408,33 +308,18 @@
      * @throws IllegalStateException if no prompt is currently being presented.
      */
     public void cancelPrompt() {
-        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            int responseCode =
-                    getService().cancelConfirmationPrompt(mConfirmationCallback);
-            if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
-                return;
-            } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
-                throw new IllegalStateException();
-            } else {
-                // Unexpected error code.
-                Log.w(TAG,
-                        "Unexpected responseCode=" + responseCode
-                                + " from cancelConfirmationPrompt() call.");
-                throw new IllegalStateException();
-            }
+        int responseCode =
+                getService().cancelConfirmationPrompt(mConfirmationCallback);
+        if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
+            return;
+        } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
+            throw new IllegalStateException();
         } else {
-            int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
-            if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
-                return;
-            } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
-                throw new IllegalStateException();
-            } else {
-                // Unexpected error code.
-                Log.w(TAG,
-                        "Unexpected responseCode=" + responseCode
-                                + " from cancelConfirmationPrompt() call.");
-                throw new IllegalStateException();
-            }
+            // Unexpected error code.
+            Log.w(TAG,
+                    "Unexpected responseCode=" + responseCode
+                            + " from cancelConfirmationPrompt() call.");
+            throw new IllegalStateException();
         }
     }
 
@@ -448,9 +333,6 @@
         if (isAccessibilityServiceRunning(context)) {
             return false;
         }
-        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
-        }
-        return KeyStore.getInstance().isConfirmationPromptSupported();
+        return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
     }
 }
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
new file mode 100644
index 0000000..e01db7a
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.keymaster;
+
+parcelable KeymasterCertificateChain;
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 1dc7f71..17ad5f1 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -712,18 +712,10 @@
      */
     @NonNull Key getKeyFromGrant(@NonNull String grantAlias)
             throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) {
-            return AndroidKeyStoreProvider
-                    .loadAndroidKeyStoreSecretKeyFromKeystore(
-                            KeyStore2.getInstance(),
-                            getGrantDescriptor(grantAlias));
-        }
-        // TODO(b/171305545): remove KeyStore1 logic.
-        return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
-            mKeyStore,
-            grantAlias,
-            KeyStore.UID_SELF);
-
+        return AndroidKeyStoreProvider
+                .loadAndroidKeyStoreSecretKeyFromKeystore(
+                        KeyStore2.getInstance(),
+                        getGrantDescriptor(grantAlias));
     }
 
     private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS
new file mode 100644
index 0000000..32f4822
--- /dev/null
+++ b/core/java/android/speech/OWNERS
@@ -0,0 +1,3 @@
+volnov@google.com
+eugeniom@google.com
+schfan@google.com
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index aea94bf..b29598e 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -205,6 +205,17 @@
      * command to the created {@code SpeechRecognizer}, otherwise no notifications will be
      * received.
      *
+     * <p>For apps targeting Android 11 (API level 30) interaction with a speech recognition
+     * service requires <queries> element to be added to the manifest file:
+     * <pre>{@code
+     * <queries>
+     *   <intent>
+     *     <action
+     *        android:name="android.speech.RecognitionService" />
+     *   </intent>
+     * </queries>
+     * }</pre>
+     *
      * @param context in which to create {@code SpeechRecognizer}
      * @return a new {@code SpeechRecognizer}
      */
@@ -222,7 +233,18 @@
      * {@link SpeechRecognizer} to. Normally you would not use this; use
      * {@link #createSpeechRecognizer(Context)} instead to use the system default recognition
      * service.
-     * 
+     *
+     * <p>For apps targeting Android 11 (API level 30) interaction with a speech recognition
+     * service requires <queries> element to be added to the manifest file:
+     * <pre>{@code
+     * <queries>
+     *   <intent>
+     *     <action
+     *        android:name="android.speech.RecognitionService" />
+     *   </intent>
+     * </queries>
+     * }</pre>
+     *
      * @param context in which to create {@code SpeechRecognizer}
      * @param serviceComponent the {@link ComponentName} of a specific service to direct this
      *        {@code SpeechRecognizer} to
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index cd6585c..5fd0c33 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -30,6 +30,7 @@
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
 import java.time.LocalTime;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -43,11 +44,39 @@
 public class TimeUtils {
     /** @hide */ public TimeUtils() {}
     /** {@hide} */
-    private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    private static final SimpleDateFormat sLoggingFormat =
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
     /** @hide */
     public static final SimpleDateFormat sDumpDateFormat =
             new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+    /**
+     * This timestamp is used in TimeUtils methods and by the SettingsUI to filter time zones
+     * to only "effective" ones in a country. It is compared against the notUsedAfter metadata that
+     * Android records for some time zones.
+     *
+     * <p>What is notUsedAfter?</p>
+     * Android chooses to avoid making users choose between functionally identical time zones at the
+     * expense of not being able to represent local times in the past.
+     *
+     * notUsedAfter exists because some time zones can "merge" with other time zones after a given
+     * point in time (i.e. they change to have identical transitions, offsets, display names, etc.).
+     * From the notUsedAfter time, the zone will express the same local time as the one it merged
+     * with.
+     *
+     * <p>Why hardcoded?</p>
+     * Rather than using System.currentTimeMillis(), a timestamp known to be in the recent past is
+     * used to ensure consistent behavior across devices and time, and avoid assumptions that the
+     * system clock on a device is currently set correctly. The fixed value should be updated
+     * occasionally, but it doesn't have to be very often as effective time zones for a country
+     * don't change very often.
+     *
+     * @hide
+     */
+    public static final Instant MIN_USE_DATE_OF_TIMEZONE =
+            Instant.ofEpochMilli(1546300800000L); // 1/1/2019 00:00 UTC
+
     /**
      * Tries to return a time zone that would have had the specified offset
      * and DST value at the specified moment in the specified country.
@@ -109,7 +138,7 @@
 
         List<String> timeZoneIds = new ArrayList<>();
         for (TimeZoneMapping timeZoneMapping : countryTimeZones.getTimeZoneMappings()) {
-            if (timeZoneMapping.isShownInPicker()) {
+            if (timeZoneMapping.isShownInPickerAt(MIN_USE_DATE_OF_TIMEZONE)) {
                 timeZoneIds.add(timeZoneMapping.getTimeZoneId());
             }
         }
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 2a9bbdf..9856553 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -60,6 +60,7 @@
      *
      * @return error of distance measurement in meters
      */
+    @FloatRange(from = 0.0)
     public double getErrorMeters() {
         return mErrorMeters;
     }
@@ -162,7 +163,7 @@
          * @throws IllegalArgumentException if error is negative or NaN
          */
         @NonNull
-        public Builder setErrorMeters(double errorMeters) {
+        public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
             if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
                 throw new IllegalArgumentException(
                         "errorMeters must be >= 0.0 and not NaN: " + errorMeters);
@@ -178,7 +179,8 @@
          * @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
          */
         @NonNull
-        public Builder setConfidenceLevel(double confidenceLevel) {
+        public Builder setConfidenceLevel(
+                @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
             if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
                 throw new IllegalArgumentException(
                         "confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 4036892..30da248 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -160,14 +160,4 @@
    * closed.
    */
   const int RANGING_SESSION_CLOSE_THRESHOLD_MS = 3000; // Value TBD
-
-  /**
-   * Ranging scheduling time unit (RSTU) for High Rate Pulse (HRP) PHY
-   */
-  const int HIGH_RATE_PULSE_CHIRPS_PER_RSTU = 416;
-
-  /**
-   * Ranging scheduling time unit (RSTU) for Low Rate Pulse (LRP) PHY
-   */
-  const int LOW_RATE_PULSE_CHIRPS_PER_RSTU = 1;
 }
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 31f6f6a..cdf1e46 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -9,6 +9,7 @@
 ogunwale@google.com
 jjaggi@google.com
 roosa@google.com
+jreck@google.com
 
 # Display
 per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
@@ -58,6 +59,10 @@
 per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
 per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
+per-file OnReceiveContentListener.java = file:/core/java/android/service/autofill/OWNERS
+per-file OnReceiveContentListener.java = file:/core/java/android/widget/OWNERS
+per-file ContentInfo.java = file:/core/java/android/service/autofill/OWNERS
+per-file ContentInfo.java = file:/core/java/android/widget/OWNERS
 
 # WindowManager
 per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a785a1a..51396db 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4679,6 +4679,7 @@
                     0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
             mTouchMode = TOUCH_MODE_FLING;
             mSuppressIdleStateChangeCall = false;
+            removeCallbacks(this);
             postOnAnimation(this);
 
             if (PROFILE_FLINGING) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index beef982..0b78a2b 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -32,7 +32,7 @@
 
 interface IBatteryStats {
     // These first methods are also called by native code, so must
-    // be kept in sync with frameworks/native/libs/binder/include/binder/IBatteryStats.h
+    // be kept in sync with frameworks/native/libs/binder/include_batterystats/batterystats/IBatteryStats.h
     void noteStartSensor(int uid, int sensor);
     void noteStopSensor(int uid, int sensor);
     void noteStartVideo(int uid);
diff --git a/core/java/com/android/internal/os/BINDER_OWNERS b/core/java/com/android/internal/os/BINDER_OWNERS
new file mode 100644
index 0000000..9f68a32
--- /dev/null
+++ b/core/java/com/android/internal/os/BINDER_OWNERS
@@ -0,0 +1,2 @@
+dplotnikov@google.com
+gaillard@google.com
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 3f01ebb..ea3b3a7 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,6 +1,7 @@
 per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
 per-file *Zygote* = file:/ZYGOTE_OWNERS
 per-file *Cpu* = file:CPU_OWNERS
+per-file *Binder* = file:BINDER_OWNERS
 
 # BatteryStats
 per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5fea76a..a541089 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,6 +41,7 @@
 import android.os.ZygoteProcess;
 import android.os.storage.StorageManager;
 import android.provider.DeviceConfig;
+import android.security.keystore2.AndroidKeyStoreProvider;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -222,10 +223,8 @@
         long startTime = SystemClock.uptimeMillis();
         Trace.traceBegin(
                 Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider");
-        // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
-        // preferred providers. Note this is not done via security.properties as the JCA providers
-        // are not on the classpath in the case of, for example, raw dalvikvm runtimes.
-        android.security.keystore2.AndroidKeyStoreProvider.install();
+
+        AndroidKeyStoreProvider.install();
         Log.i(TAG, "Installed AndroidKeyStoreProvider in "
                 + (SystemClock.uptimeMillis() - startTime) + "ms.");
         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index f71b314..4d2266b 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -547,7 +547,7 @@
                         try {
                             ZygoteConnection connection = peers.get(pollIndex);
                             boolean multipleForksOK = !isUsapPoolEnabled()
-                                    && ZygoteHooks.indefiniteThreadSuspensionOK();
+                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                             final Runnable command =
                                     connection.processCommand(this, multipleForksOK);
 
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0e35c84..965971d 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -60,7 +60,6 @@
     void notifyDataConnectionForSubscriber(
             int phoneId, int subId, in PreciseDataConnectionState preciseState);
     // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
-    void notifyCellLocation(in CellIdentity cellLocation);
     void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
diff --git a/core/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java
index 413be48..131114c 100644
--- a/core/java/com/android/internal/util/TrafficStatsConstants.java
+++ b/core/java/com/android/internal/util/TrafficStatsConstants.java
@@ -21,24 +21,8 @@
  * @hide
  */
 public class TrafficStatsConstants {
-    // These tags are used by the network stack to do traffic for its own purposes. Traffic
-    // tagged with these will be counted toward the network stack and must stay inside the
-    // range defined by
-    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and
-    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}.
-    public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01;
-    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02;
-    public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03;
 
     public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
     public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
     public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
-
-    // These tags are used by the network stack to do traffic on behalf of apps. Traffic
-    // tagged with these will be counted toward the app on behalf of which the network
-    // stack is doing this traffic. These values must stay inside the range defined by
-    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and
-    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}.
-    public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81;
-    public static final int TAG_SYSTEM_DNS = 0xFFFFFF82;
 }
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index c0c4b70..07fb729 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -50,7 +50,6 @@
 per-file Android.bp = file:platform/build/soong:/OWNERS
 per-file android_animation_* = file:/core/java/android/animation/OWNERS
 per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS
-per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
 per-file android_hardware_Usb* = file:/services/usb/OWNERS
 per-file android_hardware_display_* = file:/core/java/android/hardware/display/OWNERS
 per-file android_hardware_input_* = file:/core/java/android/hardware/input/OWNERS
@@ -63,3 +62,11 @@
 per-file android_security_* = file:/core/java/android/security/OWNERS
 per-file android_view_* = file:/core/java/android/view/OWNERS
 per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS
+
+### Graphics ###
+per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
+# These are highly common-use files
+per-file Android.bp = file:/graphics/java/android/graphics/OWNERS
+per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS
+# Although marked "view" this is mostly graphics stuff
+per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
\ No newline at end of file
diff --git a/core/jni/android_net_NetworkUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
index a781a37..1cee895 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -102,11 +102,6 @@
     return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
 }
 
-static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
-{
-    return (jboolean) !queryUserAccess(uid, netId);
-}
-
 static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
 {
     if (env->GetArrayLength(addr) != len) {
@@ -246,7 +241,6 @@
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
-    { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
     { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
     { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2499504..e4dddd2 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -486,9 +486,15 @@
     }
 
     void markVintf() {
+        AutoMutex _l(mLock);
         mVintf = true;
     }
 
+    void forceDowngradeToSystemStability() {
+        AutoMutex _l(mLock);
+        mVintf = false;
+    }
+
     sp<IBinder> getExtension() {
         AutoMutex _l(mLock);
         sp<JavaBBinder> b = mBinder.promote();
@@ -1013,6 +1019,12 @@
     jbh->markVintf();
 }
 
+static void android_os_Binder_forceDowngradeToSystemStability(JNIEnv* env, jobject clazz) {
+    JavaBBinderHolder* jbh =
+        (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+    jbh->forceDowngradeToSystemStability();
+}
+
 static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
 {
     IPCThreadState::self()->flushCommands();
@@ -1076,6 +1088,7 @@
     { "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
     { "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
     { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
+    { "forceDowngradeToSystemStability", "()V", (void*)android_os_Binder_forceDowngradeToSystemStability},
     { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
     { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
     { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 836074f..6ac43bd3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1015,21 +1015,6 @@
   gUsapPoolCount = 0;
 }
 
-NO_PAC_FUNC
-static void PAuthKeyChange(JNIEnv* env) {
-#ifdef __aarch64__
-  unsigned long int hwcaps = getauxval(AT_HWCAP);
-  if (hwcaps & HWCAP_PACA) {
-    const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
-                                   PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
-    if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
-      ALOGE("Failed to change the PAC keys: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "PAC key change failed.");
-    }
-  }
-#endif
-}
-
 // Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
 // from the actual app data directory in data mirror.
 static bool createAndMountAppData(std::string_view package_name,
@@ -1980,7 +1965,6 @@
 }
 
 // Utility routine to fork a process from the zygote.
-NO_PAC_FUNC
 pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                          const std::vector<int>& fds_to_close,
                          const std::vector<int>& fds_to_ignore,
@@ -2035,7 +2019,6 @@
     }
 
     // The child process.
-    PAuthKeyChange(env);
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
@@ -2067,7 +2050,6 @@
   PreApplicationInit();
 }
 
-NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
         jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
@@ -2117,7 +2099,6 @@
     return pid;
 }
 
-NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -2189,7 +2170,6 @@
  * @param is_priority_fork  Controls the nice level assigned to the newly created process
  * @return child pid in the parent, 0 in the child
  */
-NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
                                                          jclass,
                                                          jint read_pipe_fd,
@@ -2204,7 +2184,6 @@
                             args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
 }
 
-NO_PAC_FUNC
 int zygote::forkApp(JNIEnv* env,
                     int read_pipe_fd,
                     int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
index d2da914..b87396c 100644
--- a/core/jni/com_android_internal_os_Zygote.h
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -20,18 +20,6 @@
 #define LOG_TAG "Zygote"
 #define ATRACE_TAG ATRACE_TAG_DALVIK
 
-/* Functions in the callchain during the fork shall not be protected with
-   Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
-#ifdef __ARM_FEATURE_PAC_DEFAULT
-#ifdef __ARM_FEATURE_BTI_DEFAULT
-#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
-#else
-#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
-#endif /* __ARM_FEATURE_BTI_DEFAULT */
-#else /* !__ARM_FEATURE_PAC_DEFAULT */
-#define NO_PAC_FUNC
-#endif /* __ARM_FEATURE_PAC_DEFAULT */
-
 #include <jni.h>
 #include <vector>
 #include <android-base/stringprintf.h>
@@ -42,7 +30,6 @@
 namespace android {
 namespace zygote {
 
-NO_PAC_FUNC
 pid_t ForkCommon(JNIEnv* env,bool is_system_server,
                  const std::vector<int>& fds_to_close,
                  const std::vector<int>& fds_to_ignore,
@@ -57,7 +44,6 @@
  * communication is required. Is_priority_fork should be true if this is on the app startup
  * critical path. Purge specifies that unused pages should be purged before the fork.
  */
-NO_PAC_FUNC
 int forkApp(JNIEnv* env,
             int read_pipe_fd,
             int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 011e8f8..24fef48 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -365,7 +365,6 @@
 // We only process fork commands if the peer uid matches expected_uid.
 // For every fork command after the first, we check that the requested uid is at
 // least minUid.
-NO_PAC_FUNC
 jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
             JNIEnv* env,
             jclass,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f65d7a7..cc4e2bb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -313,7 +313,6 @@
     <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
 
     <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
-    <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
     <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
     <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
     <protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
@@ -333,7 +332,7 @@
     <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
     <protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
 
-    <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
+    <protected-broadcast android:name="android.net.action.CLEAR_DNS_CACHE" />
     <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
 
     <protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
@@ -1882,6 +1881,12 @@
         android:label="@string/permlab_preferredPaymentInfo"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi Allows access to set NFC controller always on states.
+         <p>Protection level: signature|privileged
+         @hide -->
+    <permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an internal user to use privileged SecureElement APIs.
          Applications holding this permission can access OMAPI reset system API
          and bypass OMAPI AccessControlEnforcer.
@@ -2545,10 +2550,6 @@
     <permission android:name="android.permission.CREATE_USERS"
         android:protectionLevel="signature" />
 
-    <!-- @TestApi @hide Allows an application to query user info for all users on the device. -->
-    <permission android:name="android.permission.QUERY_USERS"
-                android:protectionLevel="signature" />
-
     <!-- @hide Allows an application to set the profile owners and the device owner.
          This permission is not available to third party applications.-->
     <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
@@ -2556,6 +2557,16 @@
         android:label="@string/permlab_manageProfileAndDeviceOwners"
         android:description="@string/permdesc_manageProfileAndDeviceOwners" />
 
+    <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+         periods. -->
+    <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+                android:protectionLevel="signature" />
+
+    <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+         DPC. -->
+    <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+                android:protectionLevel="signature" />
+
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
@@ -4101,6 +4112,11 @@
     <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @TestApi Allows an application to query audio related state.
+         @hide -->
+    <permission android:name="android.permission.QUERY_AUDIO_STATE"
+                android:protectionLevel="signature" />
+
     <!-- Allows an application to modify what effects are applied to all audio
          (matching certain criteria) from any application.
          <p>Not for use by third-party applications.</p>
@@ -4578,6 +4594,11 @@
     <permission android:name="android.permission.SET_INITIAL_LOCK"
         android:protectionLevel="signature|setup"/>
 
+    <!-- @TestApi Allows applications to set and verify lockscreen credentials.
+        @hide -->
+    <permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"
+                android:protectionLevel="signature"/>
+
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8db991b..bfe7802 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3415,10 +3415,6 @@
     <!-- True if assistant app should be pinned via Pinner Service -->
     <bool name="config_pinnerAssistantApp">false</bool>
 
-    <!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 -->
-    <string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles">
-    </string-array>
-
     <!-- Number of days preloaded file cache should be preserved on a device before it can be
          deleted -->
     <integer name="config_keepPreloadsMinDays">7</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 46efd2c..2901de5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3062,7 +3062,6 @@
   <java-symbol type="bool" name="config_pinnerCameraApp" />
   <java-symbol type="bool" name="config_pinnerHomeApp" />
   <java-symbol type="bool" name="config_pinnerAssistantApp" />
-  <java-symbol type="array" name="config_jitzygoteBootImagePinnerServiceFiles" />
 
   <java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 510578e..5045e3b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -61,7 +61,6 @@
         "org.apache.http.legacy",
         "android.test.base",
         "android.test.mock",
-        "framework-atb-backward-compatibility",
         "framework",
         "ext",
         "framework-res",
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index fa1aa5e..74cdd21 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -1,3 +1,6 @@
+# Accessibility
+per-file WindowInfoTest.java = file:/services/accessibility/OWNERS
+
 # Input
 per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
 per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
@@ -9,6 +12,7 @@
 per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Window*  = file:/services/core/java/com/android/server/wm/OWNERS
 
 # Scroll Capture
 per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/tests/coretests/src/android/window/OWNERS b/core/tests/coretests/src/android/window/OWNERS
new file mode 100644
index 0000000..6c80cf9
--- /dev/null
+++ b/core/tests/coretests/src/android/window/OWNERS
@@ -0,0 +1,2 @@
+include /services/core/java/com/android/server/wm/OWNERS
+charlesccchen@google.com
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 549e074..5aacfdd 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -13,3 +13,4 @@
 yamasani@google.com
 
 per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
+per-file services.core.protolog.json =  file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 81347d1..aef68d0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -445,6 +445,8 @@
         <permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
         <!-- Permissions required for CTS test - CtsHdmiCecHostTestCases -->
         <permission name="android.permission.HDMI_CEC"/>
+        <!-- Permission required for CTS test - MediaPlayerTest -->
+        <permission name="android.permission.BIND_IMS_SERVICE" />
         <!-- Permission needed for CTS test - WifiManagerTest -->
         <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
         <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
@@ -453,6 +455,10 @@
         <permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
         <permission name="android.permission.MODIFY_QUIET_MODE" />
         <permission name="android.permission.MANAGE_APP_HIBERNATION"/>
+        <!-- Permission required for CTS test - ResourceObserverNativeTest -->
+        <permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
+        <!-- Permission required for CTS test - CtsAlarmManagerTestCases -->
+        <permission name="android.permission.SCHEDULE_PRIORITIZED_ALARM" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index d2b47c6..4c214b5 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -60,7 +60,7 @@
     <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
 
     <family name="serif">
-        <font weight="400" style="normal">NotoSerif.ttf</font>
+        <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
         <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
         <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
         <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
@@ -112,33 +112,33 @@
 
     <!-- fallback fonts -->
     <family lang="und-Arab" variant="elegant">
-        <font weight="400" style="normal">NotoNaskhArabic.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
     </family>
     <family lang="und-Arab" variant="compact">
-        <font weight="400" style="normal">NotoNaskhArabicUI.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
     </family>
     <family lang="und-Ethi">
-        <font weight="400" style="normal">NotoSansEthiopic.ttf</font>
+        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.otf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Bold.otf</font>
     </family>
     <family lang="und-Hebr">
-        <font weight="400" style="normal">NotoSansHebrew.ttf</font>
+        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
     </family>
     <family lang="und-Thai" variant="elegant">
-        <font weight="400" style="normal">NotoSansThai.ttf</font>
+        <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
     </family>
     <family lang="und-Thai" variant="compact">
-        <font weight="400" style="normal">NotoSansThaiUI.ttf</font>
+        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
     </family>
     <family lang="und-Armn">
@@ -149,28 +149,28 @@
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Bold.otf</font>
     </family>
     <family lang="und-Geor,und-Geok">
-        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf
+        <font weight="400" style="normal">NotoSansGeorgian-VF.ttf
             <axis tag="wght" stylevalue="400" />
         </font>
-        <font weight="500" style="normal">NotoSansGeorgian-Regular.ttf
+        <font weight="500" style="normal">NotoSansGeorgian-VF.ttf
             <axis tag="wght" stylevalue="500" />
         </font>
-        <font weight="600" style="normal">NotoSansGeorgian-Regular.ttf
+        <font weight="600" style="normal">NotoSansGeorgian-VF.ttf
             <axis tag="wght" stylevalue="600" />
         </font>
-        <font weight="700" style="normal">NotoSansGeorgian-Regular.ttf
+        <font weight="700" style="normal">NotoSansGeorgian-VF.ttf
             <axis tag="wght" stylevalue="700" />
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
             <axis tag="wght" stylevalue="400" />
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
             <axis tag="wght" stylevalue="500" />
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
             <axis tag="wght" stylevalue="600" />
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
             <axis tag="wght" stylevalue="700" />
         </font>
     </family>
@@ -178,7 +178,7 @@
         <font weight="400" style="normal">NotoSansDevanagari-Regular.otf</font>
         <font weight="500" style="normal">NotoSansDevanagari-Medium.otf</font>
         <font weight="700" style="normal">NotoSansDevanagari-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-Bold.ttf</font>
     </family>
     <family lang="und-Deva" variant="compact">
@@ -191,23 +191,23 @@
          danda characters.
     -->
     <family lang="und-Gujr" variant="elegant">
-        <font weight="400" style="normal">NotoSansGujarati.ttf</font>
+        <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-Bold.ttf</font>
     </family>
     <family lang="und-Gujr" variant="compact">
-        <font weight="400" style="normal">NotoSansGujaratiUI.ttf</font>
+        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
     </family>
     <family lang="und-Guru" variant="elegant">
-        <font weight="400" style="normal">NotoSansGurmukhi.ttf</font>
+        <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.otf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Bold.otf</font>
     </family>
     <family lang="und-Guru" variant="compact">
-        <font weight="400" style="normal">NotoSansGurmukhiUI.ttf</font>
+        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
     </family>
     <family lang="und-Taml" variant="elegant">
@@ -226,7 +226,7 @@
         <font weight="400" style="normal">NotoSansMalayalam-Regular.otf</font>
         <font weight="500" style="normal">NotoSansMalayalam-Medium.otf</font>
         <font weight="700" style="normal">NotoSansMalayalam-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-Bold.ttf</font>
     </family>
     <family lang="und-Mlym" variant="compact">
@@ -238,7 +238,7 @@
         <font weight="400" style="normal">NotoSansBengali-Regular.otf</font>
         <font weight="500" style="normal">NotoSansBengali-Medium.otf</font>
         <font weight="700" style="normal">NotoSansBengali-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-Bold.ttf</font>
     </family>
     <family lang="und-Beng" variant="compact">
@@ -247,31 +247,31 @@
         <font weight="700" style="normal">NotoSansBengaliUI-Bold.otf</font>
     </family>
     <family lang="und-Telu" variant="elegant">
-        <font weight="400" style="normal">NotoSansTelugu.ttf</font>
+        <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-Bold.ttf</font>
     </family>
     <family lang="und-Telu" variant="compact">
-        <font weight="400" style="normal">NotoSansTeluguUI.ttf</font>
+        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
     </family>
     <family lang="und-Knda" variant="elegant">
-        <font weight="400" style="normal">NotoSansKannada.ttf</font>
+        <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-Bold.ttf</font>
     </family>
     <family lang="und-Knda" variant="compact">
-        <font weight="400" style="normal">NotoSansKannadaUI.ttf</font>
+        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
     </family>
     <family lang="und-Orya" variant="elegant">
-        <font weight="400" style="normal">NotoSansOriya.ttf</font>
+        <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
     </family>
     <family lang="und-Orya" variant="compact">
-        <font weight="400" style="normal">NotoSansOriyaUI.ttf</font>
+        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
     </family>
 
@@ -288,39 +288,39 @@
         <font weight="700" style="normal">NotoSansSinhalaUI-Bold.otf</font>
     </family>
     <family lang="und-Khmr" variant="elegant">
-        <font weight="100" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="100" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="26.0" />
         </font>
-        <font weight="200" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="200" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="39.0" />
         </font>
-        <font weight="300" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="300" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="58.0" />
         </font>
-        <font weight="400" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="400" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="90.0" />
         </font>
-        <font weight="500" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="500" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="108.0" />
         </font>
-        <font weight="600" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="600" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="128.0" />
         </font>
-        <font weight="700" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="700" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="151.0" />
         </font>
-        <font weight="800" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="800" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="169.0" />
         </font>
-        <font weight="900" style="normal">NotoSansKhmer-Regular.ttf
+        <font weight="900" style="normal">NotoSansKhmer-VF.ttf
             <axis tag="wdth" stylevalue="100.0" />
             <axis tag="wght" stylevalue="190.0" />
         </font>
@@ -328,17 +328,17 @@
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
       </family>
     <family lang="und-Khmr" variant="compact">
-        <font weight="400" style="normal">NotoSansKhmerUI.ttf</font>
+        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
     </family>
     <family lang="und-Laoo" variant="elegant">
-        <font weight="400" style="normal">NotoSansLao.ttf</font>
+        <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
     </family>
     <family lang="und-Laoo" variant="compact">
-        <font weight="400" style="normal">NotoSansLaoUI.ttf</font>
+        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
     </family>
     <family lang="und-Mymr" variant="elegant">
@@ -354,56 +354,56 @@
         <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
     </family>
     <family lang="und-Thaa">
-        <font weight="400" style="normal">NotoSansThaana.ttf</font>
+        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
     </family>
     <family lang="und-Cham">
-        <font weight="400" style="normal">NotoSansCham.ttf</font>
+        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
     </family>
     <family lang="und-Ahom">
         <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
     </family>
     <family lang="und-Adlm">
-        <font weight="400" style="normal">NotoSansAdlam-Regular.ttf
+        <font weight="400" style="normal">NotoSansAdlam-VF.ttf
             <axis tag="wght" stylevalue="400" />
         </font>
-        <font weight="500" style="normal">NotoSansAdlam-Regular.ttf
+        <font weight="500" style="normal">NotoSansAdlam-VF.ttf
             <axis tag="wght" stylevalue="500" />
         </font>
-        <font weight="600" style="normal">NotoSansAdlam-Regular.ttf
+        <font weight="600" style="normal">NotoSansAdlam-VF.ttf
             <axis tag="wght" stylevalue="600" />
         </font>
-        <font weight="700" style="normal">NotoSansAdlam-Regular.ttf
+        <font weight="700" style="normal">NotoSansAdlam-VF.ttf
             <axis tag="wght" stylevalue="700" />
         </font>
     </family>
     <family lang="und-Avst">
-        <font weight="400" style="normal">NotoSansAvestan.ttf</font>
+        <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font>
     </family>
     <family lang="und-Bali">
-        <font weight="400" style="normal">NotoSansBalinese.ttf</font>
+        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
     </family>
     <family lang="und-Bamu">
-        <font weight="400" style="normal">NotoSansBamum.ttf</font>
+        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
     </family>
     <family lang="und-Batk">
-        <font weight="400" style="normal">NotoSansBatak.ttf</font>
+        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
     </family>
     <family lang="und-Brah">
-        <font weight="400" style="normal">NotoSansBrahmi.ttf</font>
+        <font weight="400" style="normal">NotoSansBrahmi-Regular.ttf</font>
     </family>
     <family lang="und-Bugi">
-        <font weight="400" style="normal">NotoSansBuginese.ttf</font>
+        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
     </family>
     <family lang="und-Buhd">
-        <font weight="400" style="normal">NotoSansBuhid.ttf</font>
+        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
     </family>
     <family lang="und-Cans">
-        <font weight="400" style="normal">NotoSansCanadianAboriginal.ttf</font>
+        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
     </family>
     <family lang="und-Cari">
-        <font weight="400" style="normal">NotoSansCarian.ttf</font>
+        <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
     </family>
     <family lang="und-Cakm">
         <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
@@ -412,184 +412,184 @@
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
     </family>
     <family lang="und-Copt">
-        <font weight="400" style="normal">NotoSansCoptic.ttf</font>
+        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
     </family>
     <family lang="und-Xsux">
-        <font weight="400" style="normal">NotoSansCuneiform.ttf</font>
+        <font weight="400" style="normal">NotoSansCuneiform-Regular.ttf</font>
     </family>
     <family lang="und-Cprt">
-        <font weight="400" style="normal">NotoSansCypriot.ttf</font>
+        <font weight="400" style="normal">NotoSansCypriot-Regular.ttf</font>
     </family>
     <family lang="und-Dsrt">
-        <font weight="400" style="normal">NotoSansDeseret.ttf</font>
+        <font weight="400" style="normal">NotoSansDeseret-Regular.ttf</font>
     </family>
     <family lang="und-Egyp">
-        <font weight="400" style="normal">NotoSansEgyptianHieroglyphs.ttf</font>
+        <font weight="400" style="normal">NotoSansEgyptianHieroglyphs-Regular.ttf</font>
     </family>
     <family lang="und-Elba">
         <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
     </family>
     <family lang="und-Glag">
-        <font weight="400" style="normal">NotoSansGlagolitic.ttf</font>
+        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
     </family>
     <family lang="und-Goth">
-        <font weight="400" style="normal">NotoSansGothic.ttf</font>
+        <font weight="400" style="normal">NotoSansGothic-Regular.ttf</font>
     </family>
     <family lang="und-Hano">
-        <font weight="400" style="normal">NotoSansHanunoo.ttf</font>
+        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
     </family>
     <family lang="und-Armi">
-        <font weight="400" style="normal">NotoSansImperialAramaic.ttf</font>
+        <font weight="400" style="normal">NotoSansImperialAramaic-Regular.ttf</font>
     </family>
     <family lang="und-Phli">
-        <font weight="400" style="normal">NotoSansInscriptionalPahlavi.ttf</font>
+        <font weight="400" style="normal">NotoSansInscriptionalPahlavi-Regular.ttf</font>
     </family>
     <family lang="und-Prti">
-        <font weight="400" style="normal">NotoSansInscriptionalParthian.ttf</font>
+        <font weight="400" style="normal">NotoSansInscriptionalParthian-Regular.ttf</font>
     </family>
     <family lang="und-Java">
         <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
     </family>
     <family lang="und-Kthi">
-        <font weight="400" style="normal">NotoSansKaithi.ttf</font>
+        <font weight="400" style="normal">NotoSansKaithi-Regular.ttf</font>
     </family>
     <family lang="und-Kali">
-        <font weight="400" style="normal">NotoSansKayahLi.ttf</font>
+        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
     </family>
     <family lang="und-Khar">
-        <font weight="400" style="normal">NotoSansKharoshthi.ttf</font>
+        <font weight="400" style="normal">NotoSansKharoshthi-Regular.ttf</font>
     </family>
     <family lang="und-Lepc">
-        <font weight="400" style="normal">NotoSansLepcha.ttf</font>
+        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
     </family>
     <family lang="und-Limb">
-        <font weight="400" style="normal">NotoSansLimbu.ttf</font>
+        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
     </family>
     <family lang="und-Linb">
-        <font weight="400" style="normal">NotoSansLinearB.ttf</font>
+        <font weight="400" style="normal">NotoSansLinearB-Regular.ttf</font>
     </family>
     <family lang="und-Lisu">
-        <font weight="400" style="normal">NotoSansLisu.ttf</font>
+        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
     </family>
     <family lang="und-Lyci">
-        <font weight="400" style="normal">NotoSansLycian.ttf</font>
+        <font weight="400" style="normal">NotoSansLycian-Regular.ttf</font>
     </family>
     <family lang="und-Lydi">
-        <font weight="400" style="normal">NotoSansLydian.ttf</font>
+        <font weight="400" style="normal">NotoSansLydian-Regular.ttf</font>
     </family>
     <family lang="und-Mand">
-        <font weight="400" style="normal">NotoSansMandaic.ttf</font>
+        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
     </family>
     <family lang="und-Mtei">
-        <font weight="400" style="normal">NotoSansMeeteiMayek.ttf</font>
+        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
     </family>
     <family lang="und-Talu">
-        <font weight="400" style="normal">NotoSansNewTaiLue.ttf</font>
+        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
     </family>
     <family lang="und-Nkoo">
-        <font weight="400" style="normal">NotoSansNKo.ttf</font>
+        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
     </family>
     <family lang="und-Ogam">
-        <font weight="400" style="normal">NotoSansOgham.ttf</font>
+        <font weight="400" style="normal">NotoSansOgham-Regular.ttf</font>
     </family>
     <family lang="und-Olck">
-        <font weight="400" style="normal">NotoSansOlChiki.ttf</font>
+        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
     </family>
     <family lang="und-Ital">
-        <font weight="400" style="normal">NotoSansOldItalic.ttf</font>
+        <font weight="400" style="normal">NotoSansOldItalic-Regular.ttf</font>
     </family>
     <family lang="und-Xpeo">
-        <font weight="400" style="normal">NotoSansOldPersian.ttf</font>
+        <font weight="400" style="normal">NotoSansOldPersian-Regular.ttf</font>
     </family>
     <family lang="und-Sarb">
-        <font weight="400" style="normal">NotoSansOldSouthArabian.ttf</font>
+        <font weight="400" style="normal">NotoSansOldSouthArabian-Regular.ttf</font>
     </family>
     <family lang="und-Orkh">
-        <font weight="400" style="normal">NotoSansOldTurkic.ttf</font>
+        <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font>
     </family>
     <family lang="und-Osge">
         <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
     </family>
     <family lang="und-Osma">
-        <font weight="400" style="normal">NotoSansOsmanya.ttf</font>
+        <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font>
     </family>
     <family lang="und-Phnx">
-        <font weight="400" style="normal">NotoSansPhoenician.ttf</font>
+        <font weight="400" style="normal">NotoSansPhoenician-Regular.ttf</font>
     </family>
     <family lang="und-Rjng">
-        <font weight="400" style="normal">NotoSansRejang.ttf</font>
+        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
     </family>
     <family lang="und-Runr">
-        <font weight="400" style="normal">NotoSansRunic.ttf</font>
+        <font weight="400" style="normal">NotoSansRunic-Regular.ttf</font>
     </family>
     <family lang="und-Samr">
-        <font weight="400" style="normal">NotoSansSamaritan.ttf</font>
+        <font weight="400" style="normal">NotoSansSamaritan-Regular.ttf</font>
     </family>
     <family lang="und-Saur">
-        <font weight="400" style="normal">NotoSansSaurashtra.ttf</font>
+        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
     </family>
     <family lang="und-Shaw">
-        <font weight="400" style="normal">NotoSansShavian.ttf</font>
+        <font weight="400" style="normal">NotoSansShavian-Regular.ttf</font>
     </family>
     <family lang="und-Sund">
-        <font weight="400" style="normal">NotoSansSundanese.ttf</font>
+        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
     </family>
     <family lang="und-Sylo">
-        <font weight="400" style="normal">NotoSansSylotiNagri.ttf</font>
+        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
     </family>
     <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
     <family lang="und-Syre">
-        <font weight="400" style="normal">NotoSansSyriacEstrangela.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
     </family>
     <family lang="und-Syrn">
-        <font weight="400" style="normal">NotoSansSyriacEastern.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacEastern-Regular.ttf</font>
     </family>
     <family lang="und-Syrj">
-        <font weight="400" style="normal">NotoSansSyriacWestern.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacWestern-Regular.ttf</font>
     </family>
     <family lang="und-Tglg">
-        <font weight="400" style="normal">NotoSansTagalog.ttf</font>
+        <font weight="400" style="normal">NotoSansTagalog-Regular.ttf</font>
     </family>
     <family lang="und-Tagb">
-        <font weight="400" style="normal">NotoSansTagbanwa.ttf</font>
+        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
     <family lang="und-Lana">
-        <font weight="400" style="normal">NotoSansTaiTham.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
     </family>
     <family lang="und-Tavt">
-        <font weight="400" style="normal">NotoSansTaiViet.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
     </family>
     <family lang="und-Tibt">
-        <font weight="400" style="normal">NotoSansTibetan.ttf</font>
+        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
     </family>
     <family lang="und-Tfng">
         <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
     </family>
     <family lang="und-Ugar">
-        <font weight="400" style="normal">NotoSansUgaritic.ttf</font>
+        <font weight="400" style="normal">NotoSansUgaritic-Regular.ttf</font>
     </family>
     <family lang="und-Vaii">
-        <font weight="400" style="normal">NotoSansVai.ttf</font>
+        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
     </family>
     <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
     </family>
     <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
     </family>
     <family lang="ko">
-        <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
     </family>
     <family lang="und-Zsye">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
@@ -602,16 +602,16 @@
         override the East Asian punctuation for Chinese.
     -->
     <family lang="und-Tale">
-        <font weight="400" style="normal">NotoSansTaiLe.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
     </family>
     <family lang="und-Yiii">
-        <font weight="400" style="normal">NotoSansYi.ttf</font>
+        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family lang="und-Mong">
-        <font weight="400" style="normal">NotoSansMongolian.ttf</font>
+        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
     </family>
     <family lang="und-Phag">
-        <font weight="400" style="normal">NotoSansPhagsPa.ttf</font>
+        <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font>
     </family>
     <family lang="und-Hluw">
         <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
diff --git a/drm/java/Android.bp b/drm/java/Android.bp
new file mode 100644
index 0000000..21fc018
--- /dev/null
+++ b/drm/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-drm-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/graphics/java/Android.bp b/graphics/java/Android.bp
new file mode 100644
index 0000000..63d1f6d
--- /dev/null
+++ b/graphics/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-graphics-nonupdatable-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index c0e0a24..4a24b42 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -21,6 +21,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.view.DisplayListCanvas;
 import android.view.TextureLayer;
+import android.os.SystemProperties;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -41,7 +42,14 @@
     private static final int POOL_LIMIT = 25;
 
     /** @hide */
-    public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
+    private static int getPanelFrameSize() {
+        final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
+        return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
+                DefaultSize);
+    }
+
+    /** @hide */
+    public static final int MAX_BITMAP_SIZE = getPanelFrameSize();
 
     private static final SynchronizedPool<RecordingCanvas> sPool =
             new SynchronizedPool<>(POOL_LIMIT);
diff --git a/identity/Android.bp b/identity/Android.bp
new file mode 100644
index 0000000..826d6f8
--- /dev/null
+++ b/identity/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["frameworks_base_identity_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_identity_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
diff --git a/identity/java/Android.bp b/identity/java/Android.bp
new file mode 100644
index 0000000..a193d97
--- /dev/null
+++ b/identity/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_identity_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_identity_license"],
+}
+
+filegroup {
+    name: "framework-identity-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/identity/java/android/security/identity/TEST_MAPPING b/identity/java/android/security/identity/TEST_MAPPING
new file mode 100644
index 0000000..87707a8
--- /dev/null
+++ b/identity/java/android/security/identity/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsIdentityTestCases"
+    }
+  ]
+}
diff --git a/keystore/java/Android.bp b/keystore/java/Android.bp
new file mode 100644
index 0000000..21edff1
--- /dev/null
+++ b/keystore/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_keystore_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_keystore_license"],
+}
+
+filegroup {
+    name: "framework-keystore-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 72cea0c..82639de 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -47,7 +47,6 @@
      * @hide
      */
     public static int onUserAdded(@NonNull int userId) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().onUserAdded(userId);
             return 0;
@@ -68,7 +67,6 @@
      * @hide
      */
     public static int onUserRemoved(int userId) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().onUserRemoved(userId);
             return 0;
@@ -91,7 +89,6 @@
      * @hide
      */
     public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().onUserPasswordChanged(userId, password);
             return 0;
@@ -109,7 +106,6 @@
      * be cleared.
      */
     public static int clearNamespace(@Domain int domain, long namespace) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().clearNamespace(domain, namespace);
             return 0;
@@ -144,7 +140,6 @@
      * Informs Keystore 2.0 that an off body event was detected.
      */
     public static void onDeviceOffBody() {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
         try {
             getService().onDeviceOffBody();
         } catch (Exception e) {
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 50a9082..bd72d45 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -48,7 +48,6 @@
      * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
      */
     public static int addAuthToken(@NonNull HardwareAuthToken authToken) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             getService().addAuthToken(authToken);
             return 0;
@@ -80,7 +79,6 @@
      */
     public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
             @Nullable byte[] syntheticPassword) {
-        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
         try {
             if (locked) {
                 getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index ae9f866..28c601b 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -208,78 +208,4 @@
             pr.close();
         }
     }
-
-    /**
-     * Delete all types (private key, user certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if the alias no longer contains any types.
-     */
-    public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
-        return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
-    }
-
-    /**
-     * Delete all types (private key, user certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if the alias no longer contains any types.
-     */
-    public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
-        /*
-         * Make sure every type is deleted. There can be all three types, so
-         * don't use a conditional here.
-         */
-        return deleteUserKeyTypeForAlias(keystore, alias, uid)
-                & deleteCertificateTypesForAlias(keystore, alias, uid);
-    }
-
-    /**
-     * Delete certificate types (user certificate, CA certificate) for a
-     * particular {@code alias}. Both can exist for any given alias.
-     * Returns {@code true} if the alias no longer contains either type.
-     */
-    public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
-        return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
-    }
-
-    /**
-     * Delete certificate types (user certificate, CA certificate) for a
-     * particular {@code alias}. Both can exist for any given alias.
-     * Returns {@code true} if the alias no longer contains either type.
-     */
-    public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
-        /*
-         * Make sure every certificate type is deleted. There can be two types,
-         * so don't use a conditional here.
-         */
-        return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
-                & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
-    }
-
-    /**
-     * Delete user key for a particular {@code alias}.
-     * Returns {@code true} if the entry no longer exists.
-     */
-    public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias) {
-        return deleteUserKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
-    }
-
-    /**
-     * Delete user key for a particular {@code alias}.
-     * Returns {@code true} if the entry no longer exists.
-     */
-    public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
-        int ret = keystore.delete2(Credentials.USER_PRIVATE_KEY + alias, uid);
-        if (ret == KeyStore.KEY_NOT_FOUND) {
-            return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
-        }
-        return ret == KeyStore.NO_ERROR;
-    }
-
-    /**
-     * Delete legacy prefixed entry for a particular {@code alias}
-     * Returns {@code true} if the entry no longer exists.
-     */
-    public static boolean deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid) {
-        return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
-    }
 }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index d59ca98..fd0db93 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -37,7 +37,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
 import android.system.keystore2.Domain;
@@ -676,23 +675,13 @@
             return null;
         }
 
-        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            try {
-                return android.security.keystore2.AndroidKeyStoreProvider
-                        .loadAndroidKeyStoreKeyPairFromKeystore(
-                                KeyStore2.getInstance(),
-                                getGrantDescriptor(keyId));
-            } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
-                throw new KeyChainException(e);
-            }
-        } else {
-            try {
-                return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                        KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
-            } catch (RuntimeException | UnrecoverableKeyException
-                    | KeyPermanentlyInvalidatedException e) {
-                throw new KeyChainException(e);
-            }
+        try {
+            return android.security.keystore2.AndroidKeyStoreProvider
+                    .loadAndroidKeyStoreKeyPairFromKeystore(
+                            KeyStore2.getInstance(),
+                            getGrantDescriptor(keyId));
+        } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
+            throw new KeyChainException(e);
         }
     }
 
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index b05149e..a954344 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,53 +16,11 @@
 
 package android.security;
 
-import android.app.ActivityThread;
-import android.app.Application;
-import android.app.KeyguardManager;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
-import android.os.Binder;
 import android.os.Build;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.IKeystoreService;
-import android.security.keystore.KeyExpiredException;
-import android.security.keystore.KeyNotYetValidException;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeystoreResponse;
-import android.security.keystore.UserNotAuthenticatedException;
 import android.security.maintenance.UserState;
 import android.system.keystore2.Domain;
-import android.util.Log;
-
-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;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
 
 /**
  * @hide This should not be made public in its present form because it
@@ -75,79 +33,10 @@
     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static final int NO_ERROR = 1;
-    public static final int LOCKED = 2;
-    public static final int UNINITIALIZED = 3;
-    public static final int SYSTEM_ERROR = 4;
-    public static final int PROTOCOL_ERROR = 5;
-    public static final int PERMISSION_DENIED = 6;
-    public static final int KEY_NOT_FOUND = 7;
-    public static final int VALUE_CORRUPTED = 8;
-    public static final int UNDEFINED_ACTION = 9;
-    public static final int WRONG_PASSWORD = 10;
-    public static final int KEY_ALREADY_EXISTS = 16;
-    public static final int CANNOT_ATTEST_IDS = -66;
-    public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
-
-    /**
-     * Per operation authentication is needed before this operation is valid.
-     * This is returned from {@link #begin} when begin succeeds but the operation uses
-     * per-operation authentication and must authenticate before calling {@link #update} or
-     * {@link #finish}.
-     */
-    public static final int OP_AUTH_NEEDED = 15;
-
-    // Used when a user changes their pin, invalidating old auth bound keys.
-    public static final int KEY_PERMANENTLY_INVALIDATED = 17;
 
     // Used for UID field to indicate the calling UID.
     public static final int UID_SELF = -1;
 
-    // Flags for "put" "import" and "generate"
-    public static final int FLAG_NONE = 0;
-
-    /**
-     * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
-     * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
-     *
-     * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
-     * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
-     * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
-     * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
-     * unlocks the secure lock screen after boot.
-     *
-     * @see KeyguardManager#isDeviceSecure()
-     */
-    public static final int FLAG_ENCRYPTED = 1;
-
-    /**
-     * Select Software keymaster device, which as of this writing is the lowest security
-     * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
-     * A TEE based keymaster implementation is implied.
-     *
-     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
-     * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
-     */
-    public static final int FLAG_SOFTWARE = 1 << 1;
-
-    /**
-     * A private flag that's only available to system server to indicate that this key is part of
-     * device encryption flow so it receives special treatment from keystore. For example this key
-     * will not be super encrypted, and it will be stored separately under an unique UID instead
-     * of the caller UID i.e. SYSTEM.
-     *
-     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
-     */
-    public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
-
-    /**
-     * Select Strongbox keymaster device, which as of this writing the the highest security level
-     * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
-     * A TEE based keymaster implementation is implied.
-     *
-     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
-     */
-    public static final int FLAG_STRONGBOX = 1 << 4;
-
     // States
     public enum State {
         @UnsupportedAppUsage
@@ -157,853 +46,87 @@
         UNINITIALIZED
     };
 
-    private int mError = NO_ERROR;
-
-    private final IKeystoreService mBinder;
-    private final Context mContext;
-
-    private IBinder mToken;
-
-    private KeyStore(IKeystoreService binder) {
-        mBinder = binder;
-        mContext = getApplicationContext();
-    }
-
-    @UnsupportedAppUsage
-    public static Context getApplicationContext() {
-        Application application = ActivityThread.currentApplication();
-        if (application == null) {
-            throw new IllegalStateException(
-                    "Failed to obtain application Context from ActivityThread");
-        }
-        return application;
-    }
+    private static final KeyStore KEY_STORE = new KeyStore();
 
     @UnsupportedAppUsage
     public static KeyStore getInstance() {
-        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
-                .getService("android.security.keystore"));
-        return new KeyStore(keystore);
+        return KEY_STORE;
     }
 
-    private synchronized IBinder getToken() {
-        if (mToken == null) {
-            mToken = new Binder();
-        }
-        return mToken;
-    }
-
+    /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public State state(int userId) {
-        final int ret;
-        try {
-            if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
-                int userState = AndroidKeyStoreMaintenance.getState(userId);
-                switch (userState) {
-                    case UserState.UNINITIALIZED:
-                        return KeyStore.State.UNINITIALIZED;
-                    case UserState.LSKF_UNLOCKED:
-                        return KeyStore.State.UNLOCKED;
-                    case UserState.LSKF_LOCKED:
-                        return KeyStore.State.LOCKED;
-                    default:
-                        throw new AssertionError(userState);
-                }
-            }
-            ret = mBinder.getState(userId);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            throw new AssertionError(e);
-        }
-
-        switch (ret) {
-            case NO_ERROR: return State.UNLOCKED;
-            case LOCKED: return State.LOCKED;
-            case UNINITIALIZED: return State.UNINITIALIZED;
-            default: throw new AssertionError(mError);
+        int userState = AndroidKeyStoreMaintenance.getState(userId);
+        switch (userState) {
+            case UserState.UNINITIALIZED:
+                return KeyStore.State.UNINITIALIZED;
+            case UserState.LSKF_UNLOCKED:
+                return KeyStore.State.UNLOCKED;
+            case UserState.LSKF_LOCKED:
+                return KeyStore.State.LOCKED;
+            default:
+                throw new AssertionError(userState);
         }
     }
 
+    /** @hide */
     @UnsupportedAppUsage
     public State state() {
         return state(UserHandle.myUserId());
     }
 
-    public boolean isUnlocked() {
-        return state() == State.UNLOCKED;
-    }
-
-    public byte[] get(String key, int uid) {
-        return get(key, uid, false);
-    }
-
+    /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public byte[] get(String key) {
-        return get(key, UID_SELF);
+        return null;
     }
 
-    public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
-        try {
-            key = key != null ? key : "";
-            return mBinder.get(key, uid);
-        } catch (RemoteException e) {
-             Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (android.os.ServiceSpecificException e) {
-            if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
-                Log.w(TAG, "KeyStore exception", e);
-            }
-            return null;
-        }
-    }
-
-    public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
-        return get(key, UID_SELF, suppressKeyNotFoundWarning);
-    }
-
-
-    public boolean put(String key, byte[] value, int uid, int flags) {
-        return insert(key, value, uid, flags) == NO_ERROR;
-    }
-
-    public int insert(String key, byte[] value, int uid, int flags) {
-        try {
-            if (value == null) {
-                value = new byte[0];
-            }
-            int error = mBinder.insert(key, value, uid, flags);
-            if (error == KEY_ALREADY_EXISTS) {
-                mBinder.del(key, uid);
-                error = mBinder.insert(key, value, uid, flags);
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    int delete2(String key, int uid) {
-        try {
-            return mBinder.del(key, uid);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    public boolean delete(String key, int uid) {
-        int ret = delete2(key, uid);
-        return ret == NO_ERROR || ret == KEY_NOT_FOUND;
-    }
-
+    /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean delete(String key) {
-        return delete(key, UID_SELF);
-    }
-
-    public boolean contains(String key, int uid) {
-        try {
-            return mBinder.exist(key, uid) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    public boolean contains(String key) {
-        return contains(key, UID_SELF);
-    }
-
-    /**
-     * List all entries in the keystore for {@code uid} starting with {@code prefix}.
-     */
-    public String[] list(String prefix, int uid) {
-        try {
-            return mBinder.list(prefix, uid);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (android.os.ServiceSpecificException e) {
-            Log.w(TAG, "KeyStore exception", e);
-            return null;
-        }
+        return false;
     }
 
     /**
      * List uids of all keys that are auth bound to the current user.
      * Only system is allowed to call this method.
+     * @hide
+     * @deprecated This function always returns null.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public int[] listUidsOfAuthBoundKeys() {
-        // uids are returned as a list of strings because list of integers
-        // as an output parameter is not supported by aidl-cpp.
-        List<String> uidsOut = new ArrayList<>();
-        try {
-            int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
-            if (rc != NO_ERROR) {
-                Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
-                return null;
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (android.os.ServiceSpecificException e) {
-            Log.w(TAG, "KeyStore exception", e);
-            return null;
-        }
-        // Turn list of strings into an array of uid integers.
-        return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
-   }
-
-    public String[] list(String prefix) {
-        return list(prefix, UID_SELF);
+        return null;
     }
 
+
     /**
-     * Attempt to lock the keystore for {@code user}.
-     *
-     * @param userId Android user to lock.
-     * @return whether {@code user}'s keystore was locked.
+     * @hide
+     * @deprecated This function has no effect.
      */
-    public boolean lock(int userId) {
-        try {
-            return mBinder.lock(userId) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    public boolean lock() {
-        return lock(UserHandle.myUserId());
-    }
-
-    /**
-     * Attempt to unlock the keystore for {@code user} with the password {@code password}.
-     * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
-     * created.
-     *
-     * @param userId Android user ID to operate on
-     * @param password user's keystore password. Should be the most recent value passed to
-     * {@link #onUserPasswordChanged} for the user.
-     *
-     * @return whether the keystore was unlocked.
-     */
-    public boolean unlock(int userId, String password) {
-        try {
-            password = password != null ? password : "";
-            mError = mBinder.unlock(userId, password);
-            return mError == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean unlock(String password) {
-        return unlock(UserHandle.getUserId(Process.myUid()), password);
+        return false;
     }
 
     /**
-     * Check if the keystore for {@code userId} is empty.
+     *
+     * @return
+     * @deprecated This function always returns true.
+     * @hide
      */
-    public boolean isEmpty(int userId) {
-        try {
-            return mBinder.isEmpty(userId) != 0;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isEmpty() {
-        return isEmpty(UserHandle.myUserId());
-    }
-
-    public String grant(String key, int uid) {
-        try {
-            String grantAlias =  mBinder.grant(key, uid);
-            if (grantAlias == "") return null;
-            return grantAlias;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        }
-    }
-
-    public boolean ungrant(String key, int uid) {
-        try {
-            return mBinder.ungrant(key, uid) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    /**
-     * Returns the last modification time of the key in milliseconds since the
-     * epoch. Will return -1L if the key could not be found or other error.
-     */
-    public long getmtime(String key, int uid) {
-        try {
-            final long millis = mBinder.getmtime(key, uid);
-            if (millis == -1L) {
-                return -1L;
-            }
-
-            return millis * 1000L;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return -1L;
-        }
-    }
-
-    public long getmtime(String key) {
-        return getmtime(key, UID_SELF);
-    }
-
-    // TODO: remove this when it's removed from Settings
-    public boolean isHardwareBacked() {
-        return isHardwareBacked("RSA");
-    }
-
-    public boolean isHardwareBacked(String keyType) {
-        try {
-            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    public boolean clearUid(int uid) {
-        try {
-            if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
-                return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
-            }
-            return mBinder.clear_uid(uid) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    public int getLastError() {
-        return mError;
-    }
-
-    public boolean addRngEntropy(byte[] data, int flags) {
-        KeystoreResultPromise promise = new KeystoreResultPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            int errorCode = mBinder.addRngEntropy(promise, data, flags);
-            if (errorCode == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
-            } else {
-                return false;
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "AddRngEntropy completed with exception", e);
-            return false;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    private class KeyCharacteristicsCallbackResult {
-        private KeystoreResponse keystoreResponse;
-        private KeyCharacteristics keyCharacteristics;
-
-        public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
-                                                KeyCharacteristics keyCharacteristics) {
-            this.keystoreResponse = keystoreResponse;
-            this.keyCharacteristics = keyCharacteristics;
-        }
-
-        public KeystoreResponse getKeystoreResponse() {
-            return keystoreResponse;
-        }
-
-        public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
-            this.keystoreResponse = keystoreResponse;
-        }
-
-        public KeyCharacteristics getKeyCharacteristics() {
-            return keyCharacteristics;
-        }
-
-        public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
-            this.keyCharacteristics = keyCharacteristics;
-        }
-    }
-
-    private class KeyCharacteristicsPromise
-            extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
-            implements IBinder.DeathRecipient {
-        final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
-                new CompletableFuture<KeyCharacteristicsCallbackResult>();
-        @Override
-        public void onFinished(KeystoreResponse keystoreResponse,
-                               KeyCharacteristics keyCharacteristics)
-                                       throws android.os.RemoteException {
-            future.complete(
-                    new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
-        }
-        public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
-            return future;
-        }
-        @Override
-        public void binderDied() {
-            future.completeExceptionally(new RemoteException("Keystore died"));
-        }
-    };
-
-    private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
-            int flags, KeyCharacteristics outCharacteristics)
-                    throws RemoteException, ExecutionException {
-        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        int error = NO_ERROR;
-        KeyCharacteristicsCallbackResult result = null;
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
-            if (error != NO_ERROR) {
-                Log.e(TAG, "generateKeyInternal failed on request " + error);
-                return error;
-            }
-            result = interruptedPreservingGet(promise.getFuture());
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-
-        error = result.getKeystoreResponse().getErrorCode();
-        if (error != NO_ERROR) {
-            Log.e(TAG, "generateKeyInternal failed on response " + error);
-            return error;
-        }
-        KeyCharacteristics characteristics = result.getKeyCharacteristics();
-        if (characteristics == null) {
-            Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
-            return SYSTEM_ERROR;
-        }
-        outCharacteristics.shallowCopyFrom(characteristics);
-        return NO_ERROR;
-    }
-
-    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
-            int flags, KeyCharacteristics outCharacteristics) {
-        try {
-            entropy = entropy != null ? entropy : new byte[0];
-            args = args != null ? args : new KeymasterArguments();
-            int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
-            if (error == KEY_ALREADY_EXISTS) {
-                mBinder.del(alias, uid);
-                error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "generateKey completed with exception", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
-            KeyCharacteristics outCharacteristics) {
-        return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
-    }
-
-    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
-            int uid, KeyCharacteristics outCharacteristics) {
-        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
-            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
-
-            int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-            error = result.getKeystoreResponse().getErrorCode();
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristics characteristics = result.getKeyCharacteristics();
-            if (characteristics == null) return SYSTEM_ERROR;
-            outCharacteristics.shallowCopyFrom(characteristics);
-            return NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
-            return SYSTEM_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
-            KeyCharacteristics outCharacteristics) {
-        return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
-    }
-
-    private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
-            int uid, int flags, KeyCharacteristics outCharacteristics)
-                    throws RemoteException, ExecutionException {
-        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        mBinder.asBinder().linkToDeath(promise, 0);
-        try {
-            int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-
-            error = result.getKeystoreResponse().getErrorCode();
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristics characteristics = result.getKeyCharacteristics();
-            if (characteristics == null) return SYSTEM_ERROR;
-            outCharacteristics.shallowCopyFrom(characteristics);
-            return NO_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
-            int uid, int flags, KeyCharacteristics outCharacteristics) {
-        try {
-            int error = importKeyInternal(alias, args, format, keyData, uid, flags,
-                    outCharacteristics);
-            if (error == KEY_ALREADY_EXISTS) {
-                mBinder.del(alias, uid);
-                error = importKeyInternal(alias, args, format, keyData, uid, flags,
-                        outCharacteristics);
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "ImportKey completed with exception", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
-            int flags, KeyCharacteristics outCharacteristics) {
-        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
-    }
-
-    private String getAlgorithmFromPKCS8(byte[] keyData) {
-        try {
-            final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
-            final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
-            final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
-            return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
-        } catch (IOException e) {
-            Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
-            Log.e(TAG, Log.getStackTraceString(e));
-            return null;
-        }
-    }
-
-    private KeymasterArguments makeLegacyArguments(String algorithm) {
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
-                KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
-            args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
-            args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
-            args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
-            args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
-        }
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
-        args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
-        args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
-        args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
-        return args;
-    }
-
-    public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
-        String algorithm = getAlgorithmFromPKCS8(keyData);
-        if (algorithm == null) return false;
-        KeymasterArguments args = makeLegacyArguments(algorithm);
-        KeyCharacteristics out = new KeyCharacteristics();
-        int result =  importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
-                                flags, out);
-        if (result != NO_ERROR) {
-            Log.e(TAG, Log.getStackTraceString(
-                    new KeyStoreException(result, "legacy key import failed")));
-            return false;
-        }
         return true;
     }
 
-    private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
-            String wrappingKeyAlias,
-            byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
-            KeyCharacteristics outCharacteristics)
-                    throws RemoteException, ExecutionException {
-        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        mBinder.asBinder().linkToDeath(promise, 0);
-        try {
-            int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
-                    wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-
-            error = result.getKeystoreResponse().getErrorCode();
-            if (error != NO_ERROR) return error;
-
-            KeyCharacteristics characteristics = result.getKeyCharacteristics();
-            if (characteristics == null) return SYSTEM_ERROR;
-            outCharacteristics.shallowCopyFrom(characteristics);
-            return NO_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
-            String wrappingKeyAlias,
-            byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
-            KeyCharacteristics outCharacteristics) {
-        // TODO b/119217337 uid parameter gets silently ignored.
-        try {
-            int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
-                    maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
-            if (error == KEY_ALREADY_EXISTS) {
-                mBinder.del(wrappedKeyAlias, UID_SELF);
-                error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
-                        maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "ImportWrappedKey completed with exception", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    private class ExportKeyPromise
-            extends android.security.keystore.IKeystoreExportKeyCallback.Stub
-            implements IBinder.DeathRecipient {
-        final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
-        @Override
-        public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
-            future.complete(exportKeyResult);
-        }
-        public final CompletableFuture<ExportResult> getFuture() {
-            return future;
-        }
-        @Override
-        public void binderDied() {
-            future.completeExceptionally(new RemoteException("Keystore died"));
-        }
-    };
-
-    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
-            KeymasterBlob appId, int uid) {
-        ExportKeyPromise promise = new ExportKeyPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
-            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
-            int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
-            if (error == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture());
-            } else {
-                return new ExportResult(error);
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "ExportKey completed with exception", e);
-            return null;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
-            KeymasterBlob appId) {
-        return exportKey(alias, format, clientId, appId, UID_SELF);
-    }
-
-    private class OperationPromise
-            extends android.security.keystore.IKeystoreOperationResultCallback.Stub
-            implements IBinder.DeathRecipient {
-        final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
-        @Override
-        public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
-            future.complete(operationResult);
-        }
-        public final CompletableFuture<OperationResult> getFuture() {
-            return future;
-        }
-        @Override
-        public void binderDied() {
-            future.completeExceptionally(new RemoteException("Keystore died"));
-        }
-    };
-
-    public OperationResult begin(String alias, int purpose, boolean pruneable,
-            KeymasterArguments args, byte[] entropy, int uid) {
-        OperationPromise promise = new OperationPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            args = args != null ? args : new KeymasterArguments();
-            entropy = entropy != null ? entropy : new byte[0];
-            int errorCode =  mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
-                                           entropy, uid);
-            if (errorCode == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture());
-            } else {
-                return new OperationResult(errorCode);
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "Begin completed with exception", e);
-            return null;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    public OperationResult begin(String alias, int purpose, boolean pruneable,
-            KeymasterArguments args, byte[] entropy) {
-        entropy = entropy != null ? entropy : new byte[0];
-        args = args != null ? args : new KeymasterArguments();
-        return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
-    }
-
-    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
-        OperationPromise promise = new OperationPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            arguments = arguments != null ? arguments : new KeymasterArguments();
-            input = input != null ? input : new byte[0];
-            int errorCode =  mBinder.update(promise, token, arguments, input);
-            if (errorCode == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture());
-            } else {
-                return new OperationResult(errorCode);
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "Update completed with exception", e);
-            return null;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
     /**
-     * Android KeyStore finish operation.
-     *
-     * @param token Authentication token.
-     * @param arguments Keymaster arguments
-     * @param input Optional additional input data.
-     * @param signature Optional signature to be verified.
-     * @param entropy Optional additional entropy
-     * @return OperationResult that will indicate success or error of the operation.
+     * Forwards the request to clear a UID to Keystore 2.0.
+     * @hide
      */
-    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
-            byte[] signature, byte[] entropy) {
-        OperationPromise promise = new OperationPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            arguments = arguments != null ? arguments : new KeymasterArguments();
-            entropy = entropy != null ? entropy : new byte[0];
-            input = input != null ? input : new byte[0];
-            signature = signature != null ? signature : new byte[0];
-            int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
-            if (errorCode == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture());
-            } else {
-                return new OperationResult(errorCode);
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "Finish completed with exception", e);
-            return null;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
+    public boolean clearUid(int uid) {
+        return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
     }
 
-    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
-        return finish(token, arguments, null, signature, null);
-    }
-
-    private class KeystoreResultPromise
-            extends android.security.keystore.IKeystoreResponseCallback.Stub
-            implements IBinder.DeathRecipient {
-        final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
-        @Override
-        public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
-            future.complete(keystoreResponse);
-        }
-        public final CompletableFuture<KeystoreResponse> getFuture() {
-            return future;
-        }
-        @Override
-        public void binderDied() {
-            future.completeExceptionally(new RemoteException("Keystore died"));
-        }
-    };
-
-    public int abort(IBinder token) {
-        KeystoreResultPromise promise = new KeystoreResultPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            int errorCode = mBinder.abort(promise, token);
-            if (errorCode == NO_ERROR) {
-                return interruptedPreservingGet(promise.getFuture()).getErrorCode();
-            } else {
-                return errorCode;
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "Abort completed with exception", e);
-            return SYSTEM_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
 
     /**
      * Add an authentication record to the keystore authorization table.
@@ -1013,191 +136,7 @@
      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
      */
     public int addAuthToken(byte[] authToken) {
-        try {
-            Authorization.addAuthToken(authToken);
-            return mBinder.addAuthToken(authToken);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    /**
-     * Notify keystore that a user's password has changed.
-     *
-     * @param userId the user whose password changed.
-     * @param newPassword the new password or "" if the password was removed.
-     */
-    public boolean onUserPasswordChanged(int userId, String newPassword) {
-        // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
-        // explicit here.
-        if (newPassword == null) {
-            newPassword = "";
-        }
-        try {
-            return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
-    /**
-     * Notify keystore that a user was added.
-     *
-     * @param userId the new user.
-     * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
-     * specified then the new user's keystore will be intialized with the same secure lockscreen
-     * password as the parent.
-     */
-    public void onUserAdded(int userId, int parentId) {
-        try {
-            mBinder.onUserAdded(userId, parentId);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-        }
-    }
-
-    /**
-     * Notify keystore that a user was added.
-     *
-     * @param userId the new user.
-     */
-    public void onUserAdded(int userId) {
-        onUserAdded(userId, -1);
-    }
-
-    /**
-     * Notify keystore that a user was removed.
-     *
-     * @param userId the removed user.
-     */
-    public void onUserRemoved(int userId) {
-        try {
-            mBinder.onUserRemoved(userId);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-        }
-    }
-
-    public boolean onUserPasswordChanged(String newPassword) {
-        return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
-    }
-
-    /**
-     * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
-     */
-    public void onUserLockedStateChanged(int userHandle, boolean locked) {
-        try {
-            mBinder.onKeyguardVisibilityChanged(locked, userHandle);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to update user locked state " + userHandle, e);
-        }
-    }
-
-    private class KeyAttestationCallbackResult {
-        private KeystoreResponse keystoreResponse;
-        private KeymasterCertificateChain certificateChain;
-
-        public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
-                KeymasterCertificateChain certificateChain) {
-            this.keystoreResponse = keystoreResponse;
-            this.certificateChain = certificateChain;
-        }
-
-        public KeystoreResponse getKeystoreResponse() {
-            return keystoreResponse;
-        }
-
-        public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
-            this.keystoreResponse = keystoreResponse;
-        }
-
-        public KeymasterCertificateChain getCertificateChain() {
-            return certificateChain;
-        }
-
-        public void setCertificateChain(KeymasterCertificateChain certificateChain) {
-            this.certificateChain = certificateChain;
-        }
-    }
-
-    private class CertificateChainPromise
-            extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
-            implements IBinder.DeathRecipient {
-        final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
-        @Override
-        public void onFinished(KeystoreResponse keystoreResponse,
-                KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
-            future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
-        }
-        public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
-            return future;
-        }
-        @Override
-        public void binderDied() {
-            future.completeExceptionally(new RemoteException("Keystore died"));
-        }
-    };
-
-
-    public int attestKey(
-            String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
-        CertificateChainPromise promise = new CertificateChainPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            if (params == null) {
-                params = new KeymasterArguments();
-            }
-            if (outChain == null) {
-                outChain = new KeymasterCertificateChain();
-            }
-            int error = mBinder.attestKey(promise, alias, params);
-            if (error != NO_ERROR) return error;
-            KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
-            error = result.getKeystoreResponse().getErrorCode();
-            if (error == NO_ERROR) {
-                outChain.shallowCopyFrom(result.getCertificateChain());
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "AttestKey completed with exception", e);
-            return SYSTEM_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
-    }
-
-    public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
-        CertificateChainPromise promise = new CertificateChainPromise();
-        try {
-            mBinder.asBinder().linkToDeath(promise, 0);
-            if (params == null) {
-                params = new KeymasterArguments();
-            }
-            if (outChain == null) {
-                outChain = new KeymasterCertificateChain();
-            }
-            int error = mBinder.attestDeviceIds(promise, params);
-            if (error != NO_ERROR) return error;
-            KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
-            error = result.getKeystoreResponse().getErrorCode();
-            if (error == NO_ERROR) {
-                outChain.shallowCopyFrom(result.getCertificateChain());
-            }
-            return error;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return SYSTEM_ERROR;
-        } catch (ExecutionException e) {
-            Log.e(TAG, "AttestDevicdeIds completed with exception", e);
-            return SYSTEM_ERROR;
-        } finally {
-            mBinder.asBinder().unlinkToDeath(promise, 0);
-        }
+        return Authorization.addAuthToken(authToken);
     }
 
     /**
@@ -1205,77 +144,6 @@
      */
     public void onDeviceOffBody() {
         AndroidKeyStoreMaintenance.onDeviceOffBody();
-        try {
-            mBinder.onDeviceOffBody();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-        }
-    }
-
-    // Keep in sync with confirmationui/1.0/types.hal.
-    public static final int CONFIRMATIONUI_OK = 0;
-    public static final int CONFIRMATIONUI_CANCELED = 1;
-    public static final int CONFIRMATIONUI_ABORTED = 2;
-    public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
-    public static final int CONFIRMATIONUI_IGNORED = 4;
-    public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
-    public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
-    public static final int CONFIRMATIONUI_UNEXPECTED = 7;
-    public static final int CONFIRMATIONUI_UIERROR = 0x10000;
-    public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
-    public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
-    public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
-
-    /**
-     * Requests keystore call into the confirmationui HAL to display a prompt.
-     *
-     * @param listener the binder to use for callbacks.
-     * @param promptText the prompt to display.
-     * @param extraData extra data / nonce from application.
-     * @param locale the locale as a BCP 47 langauge tag.
-     * @param uiOptionsAsFlags the UI options to use, as flags.
-     * @return one of the {@code CONFIRMATIONUI_*} constants, for
-     * example {@code KeyStore.CONFIRMATIONUI_OK}.
-     */
-    public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
-                                         String locale, int uiOptionsAsFlags) {
-        try {
-            return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
-                                                     uiOptionsAsFlags);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return CONFIRMATIONUI_SYSTEM_ERROR;
-        }
-    }
-
-    /**
-     * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
-     *
-     * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
-     * @return one of the {@code CONFIRMATIONUI_*} constants, for
-     * example {@code KeyStore.CONFIRMATIONUI_OK}.
-     */
-    public int cancelConfirmationPrompt(IBinder listener) {
-        try {
-            return mBinder.cancelConfirmationPrompt(listener);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return CONFIRMATIONUI_SYSTEM_ERROR;
-        }
-    }
-
-    /**
-     * Requests keystore to check if the confirmationui HAL is available.
-     *
-     * @return whether the confirmationUI HAL is available.
-     */
-    public boolean isConfirmationPromptSupported() {
-        try {
-            return mBinder.isConfirmationPromptSupported();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
     }
 
     /**
@@ -1284,143 +152,6 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static KeyStoreException getKeyStoreException(int errorCode) {
-        if (errorCode > 0) {
-            // KeyStore layer error
-            switch (errorCode) {
-                case NO_ERROR:
-                    return new KeyStoreException(errorCode, "OK");
-                case LOCKED:
-                    return new KeyStoreException(errorCode, "User authentication required");
-                case UNINITIALIZED:
-                    return new KeyStoreException(errorCode, "Keystore not initialized");
-                case SYSTEM_ERROR:
-                    return new KeyStoreException(errorCode, "System error");
-                case PERMISSION_DENIED:
-                    return new KeyStoreException(errorCode, "Permission denied");
-                case KEY_NOT_FOUND:
-                    return new KeyStoreException(errorCode, "Key not found");
-                case VALUE_CORRUPTED:
-                    return new KeyStoreException(errorCode, "Key blob corrupted");
-                case OP_AUTH_NEEDED:
-                    return new KeyStoreException(errorCode, "Operation requires authorization");
-                case 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));
-            }
-        }
-    }
-
-    /**
-     * Returns an {@link InvalidKeyException} corresponding to the provided
-     * {@link KeyStoreException}.
-     */
-    public InvalidKeyException getInvalidKeyException(
-            String keystoreKeyAlias, int uid, KeyStoreException e) {
-        switch (e.getErrorCode()) {
-            case LOCKED:
-                return new UserNotAuthenticatedException();
-            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
-                return new KeyExpiredException();
-            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
-                return new KeyNotYetValidException();
-            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
-            case OP_AUTH_NEEDED:
-            {
-                // We now need to determine whether the key/operation can become usable if user
-                // authentication is performed, or whether it can never become usable again.
-                // User authentication requirements are contained in the key's characteristics. We
-                // need to check whether these requirements can be be satisfied by asking the user
-                // to authenticate.
-                KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-                int getKeyCharacteristicsErrorCode =
-                        getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
-                                keyCharacteristics);
-                if (getKeyCharacteristicsErrorCode != NO_ERROR) {
-                    return new InvalidKeyException(
-                            "Failed to obtained key characteristics",
-                            getKeyStoreException(getKeyCharacteristicsErrorCode));
-                }
-                List<BigInteger> keySids =
-                        keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
-                if (keySids.isEmpty()) {
-                    // Key is not bound to any SIDs -- no amount of authentication will help here.
-                    return new KeyPermanentlyInvalidatedException();
-                }
-                long rootSid = GateKeeper.getSecureUserId();
-                if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
-                    // One of the key's SIDs is the current root SID -- user can be authenticated
-                    // against that SID.
-                    return new UserNotAuthenticatedException();
-                }
-
-                final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
-                long[] biometricSids = bm.getAuthenticatorIds();
-
-                // The key must contain every biometric SID. This is because the current API surface
-                // treats all biometrics (capable of keystore integration) equally. e.g. if the
-                // device has multiple keystore-capable sensors, and one of the sensor's SIDs
-                // changed, 1) there is no way for a developer to specify authentication with a
-                // specific sensor (the one that hasn't changed), and 2) currently the only
-                // signal to developers is the UserNotAuthenticatedException, which doesn't
-                // indicate a specific sensor.
-                boolean canUnlockViaBiometrics = true;
-                for (long sid : biometricSids) {
-                    if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
-                        canUnlockViaBiometrics = false;
-                        break;
-                    }
-                }
-
-                if (canUnlockViaBiometrics) {
-                    // All of the biometric SIDs are contained in the key's SIDs.
-                    return new UserNotAuthenticatedException();
-                }
-
-                // None of the key's SIDs can ever be authenticated
-                return new KeyPermanentlyInvalidatedException();
-            }
-            case UNINITIALIZED:
-                return new KeyPermanentlyInvalidatedException();
-            default:
-                return new InvalidKeyException("Keystore operation failed", e);
-        }
-    }
-
-    /**
-     * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
-     * code.
-     */
-    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
-            int errorCode) {
-        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
-    }
-
-    private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
-            throws ExecutionException {
-        boolean wasInterrupted = false;
-        while (true) {
-            try {
-                R result = future.get();
-                if (wasInterrupted) {
-                    Thread.currentThread().interrupt();
-                }
-                return result;
-            } catch (InterruptedException e) {
-                wasInterrupted = true;
-            }
-        }
+        return new KeyStoreException(-10000, "Should not be called.");
     }
 }
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 75e248e..df579bb 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -125,6 +125,8 @@
         }
     }
 
+    private static final String KEYSTORE2_SERVICE_NAME =
+            "android.system.keystore2.IKeystoreService/default";
 
     private KeyStore2() {
         mBinder = null;
@@ -137,7 +139,7 @@
     private synchronized IKeystoreService getService(boolean retryLookup) {
         if (mBinder == null || retryLookup) {
             mBinder = IKeystoreService.Stub.asInterface(ServiceManager
-                    .getService("android.system.keystore2"));
+                    .getService(KEYSTORE2_SERVICE_NAME));
         }
         return mBinder;
     }
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java
index 41cfb27..1d2738e 100644
--- a/keystore/java/android/security/LegacyVpnProfileStore.java
+++ b/keystore/java/android/security/LegacyVpnProfileStore.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.vpnprofilestore.IVpnProfileStore;
 import android.util.Log;
 
@@ -53,13 +52,8 @@
      */
     public static boolean put(@NonNull String alias, @NonNull byte[] profile) {
         try {
-            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-                getService().put(alias, profile);
-                return true;
-            } else {
-                return KeyStore.getInstance().put(
-                        alias, profile, KeyStore.UID_SELF, 0);
-            }
+            getService().put(alias, profile);
+            return true;
         } catch (Exception e) {
             Log.e(TAG, "Failed to put vpn profile.", e);
             return false;
@@ -77,11 +71,7 @@
      */
     public static byte[] get(@NonNull String alias) {
         try {
-            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-                return getService().get(alias);
-            } else {
-                return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */);
-            }
+            return getService().get(alias);
         } catch (ServiceSpecificException e) {
             if (e.errorCode != PROFILE_NOT_FOUND) {
                 Log.e(TAG, "Failed to get vpn profile.", e);
@@ -100,12 +90,8 @@
      */
     public static boolean remove(@NonNull String alias) {
         try {
-            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-                getService().remove(alias);
-                return true;
-            } else {
-                return KeyStore.getInstance().delete(alias);
-            }
+            getService().remove(alias);
+            return true;
         } catch (ServiceSpecificException e) {
             if (e.errorCode != PROFILE_NOT_FOUND) {
                 Log.e(TAG, "Failed to remove vpn profile.", e);
@@ -124,16 +110,11 @@
      */
     public static @NonNull String[] list(@NonNull String prefix) {
         try {
-            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
-                final String[] aliases = getService().list(prefix);
-                for (int i = 0; i < aliases.length; ++i) {
-                    aliases[i] = aliases[i].substring(prefix.length());
-                }
-                return aliases;
-            } else {
-                final String[] result = KeyStore.getInstance().list(prefix);
-                return result != null ? result : new String[0];
+            final String[] aliases = getService().list(prefix);
+            for (int i = 0; i < aliases.length; ++i) {
+                aliases[i] = aliases[i].substring(prefix.length());
             }
+            return aliases;
         } catch (Exception e) {
             Log.e(TAG, "Failed to list vpn profiles.", e);
         }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
deleted file mode 100644
index 01fd062..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore 3DES {@link CipherSpi} implementations.
- *
- * @hide
- */
-public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
-    private static final int BLOCK_SIZE_BYTES = 8;
-
-    private final int mKeymasterBlockMode;
-    private final int mKeymasterPadding;
-    /** Whether this transformation requires an IV. */
-    private final boolean mIvRequired;
-
-    private byte[] mIv;
-
-    /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
-    private boolean mIvHasBeenUsed;
-
-    AndroidKeyStore3DESCipherSpi(
-            int keymasterBlockMode,
-            int keymasterPadding,
-            boolean ivRequired) {
-        mKeymasterBlockMode = keymasterBlockMode;
-        mKeymasterPadding = keymasterPadding;
-        mIvRequired = ivRequired;
-    }
-
-    abstract static class ECB extends AndroidKeyStore3DESCipherSpi {
-        protected ECB(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
-        }
-
-        public static class NoPadding extends ECB {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-        }
-
-        public static class PKCS7Padding extends ECB {
-            public PKCS7Padding() {
-                super(KeymasterDefs.KM_PAD_PKCS7);
-            }
-        }
-    }
-
-    abstract static class CBC extends AndroidKeyStore3DESCipherSpi {
-        protected CBC(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
-        }
-
-        public static class NoPadding extends CBC {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-        }
-
-        public static class PKCS7Padding extends CBC {
-            public PKCS7Padding() {
-                super(KeymasterDefs.KM_PAD_PKCS7);
-            }
-        }
-    }
-
-    @Override
-    protected void initKey(int i, Key key) throws InvalidKeyException {
-        if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeyException(
-                    "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
-        }
-        if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException(
-                    "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
-                            KeyProperties.KEY_ALGORITHM_3DES + " supported");
-        }
-        setKey((AndroidKeyStoreSecretKey) key);
-    }
-
-    @Override
-    protected int engineGetBlockSize() {
-        return BLOCK_SIZE_BYTES;
-    }
-
-    @Override
-    protected int engineGetOutputSize(int inputLen) {
-        return inputLen + 3 * BLOCK_SIZE_BYTES;
-    }
-
-    @Override
-    protected final byte[] engineGetIV() {
-        return ArrayUtils.cloneIfNotEmpty(mIv);
-    }
-
-    @Override
-    protected AlgorithmParameters engineGetParameters() {
-        if (!mIvRequired) {
-            return null;
-        }
-        if ((mIv != null) && (mIv.length > 0)) {
-            try {
-                AlgorithmParameters params = AlgorithmParameters.getInstance("DESede");
-                params.init(new IvParameterSpec(mIv));
-                return params;
-            } catch (NoSuchAlgorithmException e) {
-                throw new ProviderException(
-                        "Failed to obtain 3DES AlgorithmParameters", e);
-            } catch (InvalidParameterSpecException e) {
-                throw new ProviderException(
-                        "Failed to initialize 3DES AlgorithmParameters with an IV",
-                        e);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
-        if (!mIvRequired) {
-            return;
-        }
-
-        // IV is used
-        if (!isEncrypting()) {
-            throw new InvalidKeyException("IV required when decrypting"
-                    + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
-        }
-    }
-
-    @Override
-    protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
-            throws InvalidAlgorithmParameterException {
-        if (!mIvRequired) {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
-            }
-            return;
-        }
-
-        // IV is used
-        if (params == null) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException(
-                        "IvParameterSpec must be provided when decrypting");
-            }
-            return;
-        }
-        if (!(params instanceof IvParameterSpec)) {
-            throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
-        }
-        mIv = ((IvParameterSpec) params).getIV();
-        if (mIv == null) {
-            throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
-        }
-    }
-
-    @Override
-    protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
-            throws InvalidAlgorithmParameterException {
-        if (!mIvRequired) {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
-            }
-            return;
-        }
-
-        // IV is used
-        if (params == null) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException("IV required when decrypting"
-                        + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
-            }
-            return;
-        }
-
-        if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) {
-            throw new InvalidAlgorithmParameterException(
-                    "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
-                            + ". Supported: DESede");
-        }
-
-        IvParameterSpec ivSpec;
-        try {
-            ivSpec = params.getParameterSpec(IvParameterSpec.class);
-        } catch (InvalidParameterSpecException e) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException("IV required when decrypting"
-                        + ", but not found in parameters: " + params, e);
-            }
-            mIv = null;
-            return;
-        }
-        mIv = ivSpec.getIV();
-        if (mIv == null) {
-            throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
-        }
-    }
-
-    @Override
-    protected final int getAdditionalEntropyAmountForBegin() {
-        if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
-            // IV will need to be generated
-            return BLOCK_SIZE_BYTES;
-        }
-
-        return 0;
-    }
-
-    @Override
-    protected int getAdditionalEntropyAmountForFinish() {
-        return 0;
-    }
-
-    @Override
-    protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) {
-        if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
-            // IV is being reused for encryption: this violates security best practices.
-            throw new IllegalStateException(
-                    "IV has already been used. Reusing IV in encryption mode violates security best"
-                            + " practices.");
-        }
-
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
-        if ((mIvRequired) && (mIv != null)) {
-            keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
-        }
-    }
-
-    @Override
-    protected void loadAlgorithmSpecificParametersFromBeginResult(
-            KeymasterArguments keymasterArgs) {
-        mIvHasBeenUsed = true;
-
-        // NOTE: Keymaster doesn't always return an IV, even if it's used.
-        byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
-        if ((returnedIv != null) && (returnedIv.length == 0)) {
-            returnedIv = null;
-        }
-
-        if (mIvRequired) {
-            if (mIv == null) {
-                mIv = returnedIv;
-            } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
-                throw new ProviderException("IV in use differs from provided IV");
-            }
-        } else {
-            if (returnedIv != null) {
-                throw new ProviderException(
-                        "IV in use despite IV not being used by this transformation");
-            }
-        }
-    }
-
-    @Override
-    protected final void resetAll() {
-        mIv = null;
-        mIvHasBeenUsed = false;
-        super.resetAll();
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
deleted file mode 100644
index feb6101..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,449 +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.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.Stream;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.GCMParameterSpec;
-
-/**
- * Base class for Android Keystore authenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
-    abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
-        static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
-        private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
-        private static final int DEFAULT_TAG_LENGTH_BITS = 128;
-        private static final int IV_LENGTH_BYTES = 12;
-
-        private int mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
-
-        GCM(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_GCM, keymasterPadding);
-        }
-
-        @Override
-        protected final void resetAll() {
-            mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
-            super.resetAll();
-        }
-
-        @Override
-        protected final void resetWhilePreservingInitState() {
-            super.resetWhilePreservingInitState();
-        }
-
-        @Override
-        protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
-            if (!isEncrypting()) {
-                throw new InvalidKeyException("IV required when decrypting"
-                        + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
-            }
-        }
-
-        @Override
-        protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
-                throws InvalidAlgorithmParameterException {
-            // IV is used
-            if (params == null) {
-                if (!isEncrypting()) {
-                    // IV must be provided by the caller
-                    throw new InvalidAlgorithmParameterException(
-                            "GCMParameterSpec must be provided when decrypting");
-                }
-                return;
-            }
-            if (!(params instanceof GCMParameterSpec)) {
-                throw new InvalidAlgorithmParameterException("Only GCMParameterSpec supported");
-            }
-            GCMParameterSpec spec = (GCMParameterSpec) params;
-            byte[] iv = spec.getIV();
-            if (iv == null) {
-                throw new InvalidAlgorithmParameterException("Null IV in GCMParameterSpec");
-            } else if (iv.length != IV_LENGTH_BYTES) {
-                throw new InvalidAlgorithmParameterException("Unsupported IV length: "
-                        + iv.length + " bytes. Only " + IV_LENGTH_BYTES
-                        + " bytes long IV supported");
-            }
-            int tagLengthBits = spec.getTLen();
-            if ((tagLengthBits < MIN_SUPPORTED_TAG_LENGTH_BITS)
-                    || (tagLengthBits > MAX_SUPPORTED_TAG_LENGTH_BITS)
-                    || ((tagLengthBits % 8) != 0)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported tag length: " + tagLengthBits + " bits"
-                        + ". Supported lengths: 96, 104, 112, 120, 128");
-            }
-            setIv(iv);
-            mTagLengthBits = tagLengthBits;
-        }
-
-        @Override
-        protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
-                throws InvalidAlgorithmParameterException {
-            if (params == null) {
-                if (!isEncrypting()) {
-                    // IV must be provided by the caller
-                    throw new InvalidAlgorithmParameterException("IV required when decrypting"
-                            + ". Use GCMParameterSpec or GCM AlgorithmParameters to provide it.");
-                }
-                return;
-            }
-
-            if (!"GCM".equalsIgnoreCase(params.getAlgorithm())) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
-                        + ". Supported: GCM");
-            }
-
-            GCMParameterSpec spec;
-            try {
-                spec = params.getParameterSpec(GCMParameterSpec.class);
-            } catch (InvalidParameterSpecException e) {
-                if (!isEncrypting()) {
-                    // IV must be provided by the caller
-                    throw new InvalidAlgorithmParameterException("IV and tag length required when"
-                            + " decrypting, but not found in parameters: " + params, e);
-                }
-                setIv(null);
-                return;
-            }
-            initAlgorithmSpecificParameters(spec);
-        }
-
-        @Nullable
-        @Override
-        protected final AlgorithmParameters engineGetParameters() {
-            byte[] iv = getIv();
-            if ((iv != null) && (iv.length > 0)) {
-                try {
-                    AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
-                    params.init(new GCMParameterSpec(mTagLengthBits, iv));
-                    return params;
-                } catch (NoSuchAlgorithmException e) {
-                    throw new ProviderException(
-                            "Failed to obtain GCM AlgorithmParameters", e);
-                } catch (InvalidParameterSpecException e) {
-                    throw new ProviderException(
-                            "Failed to initialize GCM AlgorithmParameters", e);
-                }
-            }
-            return null;
-        }
-
-        @NonNull
-        @Override
-        protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
-                KeyStore keyStore, IBinder operationToken) {
-            KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer(
-                    new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                            keyStore, operationToken), 0);
-            if (isEncrypting()) {
-                return streamer;
-            } else {
-                // When decrypting, to avoid leaking unauthenticated plaintext, do not return any
-                // plaintext before ciphertext is authenticated by KeyStore.finish.
-                return new BufferAllOutputUntilDoFinalStreamer(streamer);
-            }
-        }
-
-        @NonNull
-        @Override
-        protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
-                KeyStore keyStore, IBinder operationToken) {
-            return new KeyStoreCryptoOperationChunkedStreamer(
-                    new AdditionalAuthenticationDataStream(keyStore, operationToken), 0);
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForBegin() {
-            if ((getIv() == null) && (isEncrypting())) {
-                // IV will need to be generated
-                return IV_LENGTH_BYTES;
-            }
-
-            return 0;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForFinish() {
-            return 0;
-        }
-
-        @Override
-        protected final void addAlgorithmSpecificParametersToBegin(
-                @NonNull KeymasterArguments keymasterArgs) {
-            super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
-            keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits);
-        }
-
-        protected final int getTagLengthBits() {
-            return mTagLengthBits;
-        }
-
-        public static final class NoPadding extends GCM {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-
-            @Override
-            protected final int engineGetOutputSize(int inputLen) {
-                int tagLengthBytes = (getTagLengthBits() + 7) / 8;
-                long result;
-                if (isEncrypting()) {
-                    result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
-                            + tagLengthBytes;
-                } else {
-                    result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
-                            - tagLengthBytes;
-                }
-                if (result < 0) {
-                    return 0;
-                } else if (result > Integer.MAX_VALUE) {
-                    return Integer.MAX_VALUE;
-                }
-                return (int) result;
-            }
-        }
-    }
-
-    private static final int BLOCK_SIZE_BYTES = 16;
-
-    private final int mKeymasterBlockMode;
-    private final int mKeymasterPadding;
-
-    private byte[] mIv;
-
-    /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
-    private boolean mIvHasBeenUsed;
-
-    AndroidKeyStoreAuthenticatedAESCipherSpi(
-            int keymasterBlockMode,
-            int keymasterPadding) {
-        mKeymasterBlockMode = keymasterBlockMode;
-        mKeymasterPadding = keymasterPadding;
-    }
-
-    @Override
-    protected void resetAll() {
-        mIv = null;
-        mIvHasBeenUsed = false;
-        super.resetAll();
-    }
-
-    @Override
-    protected final void initKey(int opmode, Key key) throws InvalidKeyException {
-        if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeyException(
-                    "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
-        }
-        if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException(
-                    "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
-                    KeyProperties.KEY_ALGORITHM_AES + " supported");
-        }
-        setKey((AndroidKeyStoreSecretKey) key);
-    }
-
-    @Override
-    protected void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs) {
-        if ((isEncrypting()) && (mIvHasBeenUsed)) {
-            // IV is being reused for encryption: this violates security best practices.
-            throw new IllegalStateException(
-                    "IV has already been used. Reusing IV in encryption mode violates security best"
-                    + " practices.");
-        }
-
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
-        if (mIv != null) {
-            keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
-        }
-    }
-
-    @Override
-    protected final void loadAlgorithmSpecificParametersFromBeginResult(
-            @NonNull KeymasterArguments keymasterArgs) {
-        mIvHasBeenUsed = true;
-
-        // NOTE: Keymaster doesn't always return an IV, even if it's used.
-        byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
-        if ((returnedIv != null) && (returnedIv.length == 0)) {
-            returnedIv = null;
-        }
-
-        if (mIv == null) {
-            mIv = returnedIv;
-        } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
-            throw new ProviderException("IV in use differs from provided IV");
-        }
-    }
-
-    @Override
-    protected final int engineGetBlockSize() {
-        return BLOCK_SIZE_BYTES;
-    }
-
-    @Override
-    protected final byte[] engineGetIV() {
-        return ArrayUtils.cloneIfNotEmpty(mIv);
-    }
-
-    protected void setIv(byte[] iv) {
-        mIv = iv;
-    }
-
-    protected byte[] getIv() {
-        return mIv;
-    }
-
-    /**
-     * {@link KeyStoreCryptoOperationStreamer} which buffers all output until {@code doFinal} from
-     * which it returns all output in one go, provided {@code doFinal} succeeds.
-     */
-    private static class BufferAllOutputUntilDoFinalStreamer
-        implements KeyStoreCryptoOperationStreamer {
-
-        private final KeyStoreCryptoOperationStreamer mDelegate;
-        private ByteArrayOutputStream mBufferedOutput = new ByteArrayOutputStream();
-        private long mProducedOutputSizeBytes;
-
-        private BufferAllOutputUntilDoFinalStreamer(KeyStoreCryptoOperationStreamer delegate) {
-            mDelegate = delegate;
-        }
-
-        @Override
-        public byte[] update(byte[] input, int inputOffset, int inputLength)
-                throws KeyStoreException {
-            byte[] output = mDelegate.update(input, inputOffset, inputLength);
-            if (output != null) {
-                try {
-                    mBufferedOutput.write(output);
-                } catch (IOException e) {
-                    throw new ProviderException("Failed to buffer output", e);
-                }
-            }
-            return EmptyArray.BYTE;
-        }
-
-        @Override
-        public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-                byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
-            byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature,
-                    additionalEntropy);
-            if (output != null) {
-                try {
-                    mBufferedOutput.write(output);
-                } catch (IOException e) {
-                    throw new ProviderException("Failed to buffer output", e);
-                }
-            }
-            byte[] result = mBufferedOutput.toByteArray();
-            mBufferedOutput.reset();
-            mProducedOutputSizeBytes += result.length;
-            return result;
-        }
-
-        @Override
-        public long getConsumedInputSizeBytes() {
-            return mDelegate.getConsumedInputSizeBytes();
-        }
-
-        @Override
-        public long getProducedOutputSizeBytes() {
-            return mProducedOutputSizeBytes;
-        }
-    }
-
-    /**
-     * Additional Authentication Data (AAD) stream via a KeyStore streaming operation. This stream
-     * sends AAD into the KeyStore.
-     */
-    private static class AdditionalAuthenticationDataStream implements Stream {
-
-        private final KeyStore mKeyStore;
-        private final IBinder mOperationToken;
-
-        private AdditionalAuthenticationDataStream(KeyStore keyStore, IBinder operationToken) {
-            mKeyStore = keyStore;
-            mOperationToken = operationToken;
-        }
-
-        @Override
-        public OperationResult update(byte[] input) {
-            KeymasterArguments keymasterArgs = new KeymasterArguments();
-            keymasterArgs.addBytes(KeymasterDefs.KM_TAG_ASSOCIATED_DATA, input);
-
-            // KeyStore does not reflect AAD in inputConsumed, but users of Stream rely on this
-            // field. We fix this discrepancy here. KeyStore.update contract is that all of AAD
-            // has been consumed if the method succeeds.
-            OperationResult result = mKeyStore.update(mOperationToken, keymasterArgs, null);
-            if (result.resultCode == KeyStore.NO_ERROR) {
-                result = new OperationResult(
-                        result.resultCode,
-                        result.token,
-                        result.operationHandle,
-                        input.length, // inputConsumed
-                        result.output,
-                        result.outParams);
-            }
-            return result;
-        }
-
-        @Override
-        public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
-            if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
-                throw new ProviderException("AAD stream does not support additional entropy");
-            }
-            return new OperationResult(
-                    KeyStore.NO_ERROR,
-                    mOperationToken,
-                    0, // operation handle -- nobody cares about this being returned from finish
-                    0, // inputConsumed
-                    EmptyArray.BYTE, // output
-                    new KeymasterArguments() // additional params returned by finish
-                    );
-        }
-    }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
deleted file mode 100644
index 5730234..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ /dev/null
@@ -1,279 +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.security.keystore;
-
-import java.security.Provider;
-
-/**
- * {@link Provider} of JCA crypto operations operating on Android KeyStore keys.
- *
- * <p>This provider was separated out of {@link AndroidKeyStoreProvider} to work around the issue
- * that Bouncy Castle provider incorrectly declares that it accepts arbitrary keys (incl. Android
- * KeyStore ones). This causes JCA to select the Bouncy Castle's implementation of JCA crypto
- * operations for Android KeyStore keys unless Android KeyStore's own implementations are installed
- * as higher-priority than Bouncy Castle ones. The purpose of this provider is to do just that: to
- * offer crypto operations operating on Android KeyStore keys and to be installed at higher priority
- * than the Bouncy Castle provider.
- *
- * <p>Once Bouncy Castle provider is fixed, this provider can be merged into the
- * {@code AndroidKeyStoreProvider}.
- *
- * @hide
- */
-public class AndroidKeyStoreBCWorkaroundProvider extends Provider {
-
-    // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
-    // classes when this provider is instantiated and installed early on during each app's
-    // initialization process.
-
-    private static final String PACKAGE_NAME = "android.security.keystore";
-    private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
-            PACKAGE_NAME + ".AndroidKeyStoreSecretKey";
-    private static final String KEYSTORE_PRIVATE_KEY_CLASS_NAME =
-            PACKAGE_NAME + ".AndroidKeyStorePrivateKey";
-    private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
-            PACKAGE_NAME + ".AndroidKeyStorePublicKey";
-
-    private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede";
-
-    /** @hide */
-    public AndroidKeyStoreBCWorkaroundProvider() {
-        this("AndroidKeyStoreBCWorkaround");
-    }
-
-    /** @hide **/
-    public AndroidKeyStoreBCWorkaroundProvider(String providerName) {
-        super(providerName,
-                1.0,
-                "Android KeyStore security provider to work around Bouncy Castle");
-
-        // --------------------- javax.crypto.Mac
-        putMacImpl("HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA1");
-        put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1");
-        put("Alg.Alias.Mac.HMAC-SHA1", "HmacSHA1");
-        put("Alg.Alias.Mac.HMAC/SHA1", "HmacSHA1");
-
-        putMacImpl("HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA224");
-        put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA224");
-        put("Alg.Alias.Mac.HMAC-SHA224", "HmacSHA224");
-        put("Alg.Alias.Mac.HMAC/SHA224", "HmacSHA224");
-
-        putMacImpl("HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA256");
-        put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256");
-        put("Alg.Alias.Mac.HMAC-SHA256", "HmacSHA256");
-        put("Alg.Alias.Mac.HMAC/SHA256", "HmacSHA256");
-
-        putMacImpl("HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA384");
-        put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384");
-        put("Alg.Alias.Mac.HMAC-SHA384", "HmacSHA384");
-        put("Alg.Alias.Mac.HMAC/SHA384", "HmacSHA384");
-
-        putMacImpl("HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA512");
-        put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
-        put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512");
-        put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512");
-
-        // --------------------- javax.crypto.Cipher
-        putSymmetricCipherImpl("AES/ECB/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$NoPadding");
-        putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$PKCS7Padding");
-
-        putSymmetricCipherImpl("AES/CBC/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$NoPadding");
-        putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$PKCS7Padding");
-
-        putSymmetricCipherImpl("AES/CTR/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
-
-        if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) {
-            putSymmetricCipherImpl("DESede/CBC/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
-            putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
-                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding");
-
-            putSymmetricCipherImpl("DESede/ECB/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding");
-            putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
-                PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding");
-        }
-
-        putSymmetricCipherImpl("AES/GCM/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding");
-
-        putAsymmetricCipherImpl("RSA/ECB/NoPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$NoPadding");
-        put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
-        putAsymmetricCipherImpl("RSA/ECB/PKCS1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$PKCS1Padding");
-        put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPPadding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPPadding", "RSA/ECB/OAEPPadding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-1AndMGF1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-1AndMGF1Padding",
-                "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-224AndMGF1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA224AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-224AndMGF1Padding",
-                "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA256AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-256AndMGF1Padding",
-                "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-384AndMGF1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA384AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-384AndMGF1Padding",
-                "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
-        putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-512AndMGF1Padding",
-                PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA512AndMGF1Padding");
-        put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-512AndMGF1Padding",
-                "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
-
-        // --------------------- java.security.Signature
-        putSignatureImpl("NONEwithRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$NONEWithPKCS1Padding");
-
-        putSignatureImpl("MD5withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$MD5WithPKCS1Padding");
-        put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5withRSA");
-        put("Alg.Alias.Signature.MD5/RSA", "MD5withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5withRSA");
-
-        putSignatureImpl("SHA1withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPKCS1Padding");
-        put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1withRSA");
-        put("Alg.Alias.Signature.SHA1/RSA", "SHA1withRSA");
-        put("Alg.Alias.Signature.SHA-1/RSA", "SHA1withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1withRSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1withRSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
-
-        putSignatureImpl("SHA224withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPKCS1Padding");
-        put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1",
-                "SHA224withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.11",
-                "SHA224withRSA");
-
-        putSignatureImpl("SHA256withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPKCS1Padding");
-        put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1",
-                "SHA256withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11",
-                "SHA256withRSA");
-
-        putSignatureImpl("SHA384withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPKCS1Padding");
-        put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1",
-                "SHA384withRSA");
-
-        putSignatureImpl("SHA512withRSA",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPKCS1Padding");
-        put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512withRSA");
-        put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1",
-                "SHA512withRSA");
-
-        putSignatureImpl("SHA1withRSA/PSS",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPSSPadding");
-        putSignatureImpl("SHA224withRSA/PSS",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPSSPadding");
-        putSignatureImpl("SHA256withRSA/PSS",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPSSPadding");
-        putSignatureImpl("SHA384withRSA/PSS",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPSSPadding");
-        putSignatureImpl("SHA512withRSA/PSS",
-                PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPSSPadding");
-
-        putSignatureImpl("NONEwithECDSA",
-                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
-
-        putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
-        put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
-        put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
-        // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
-        put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
-
-        // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
-        putSignatureImpl("SHA224withECDSA",
-                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA224");
-        // ecdsa-with-SHA224(1)
-        put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.10045.2.1", "SHA224withECDSA");
-
-        // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
-        putSignatureImpl("SHA256withECDSA",
-                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA256");
-        // ecdsa-with-SHA256(2)
-        put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.10045.2.1", "SHA256withECDSA");
-
-        putSignatureImpl("SHA384withECDSA",
-                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA384");
-        // ecdsa-with-SHA384(3)
-        put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.10045.2.1", "SHA384withECDSA");
-
-        putSignatureImpl("SHA512withECDSA",
-                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA512");
-        // ecdsa-with-SHA512(4)
-        put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
-        put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.10045.2.1", "SHA512withECDSA");
-    }
-
-    private void putMacImpl(String algorithm, String implClass) {
-        put("Mac." + algorithm, implClass);
-        put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
-    }
-
-    private void putSymmetricCipherImpl(String transformation, String implClass) {
-        put("Cipher." + transformation, implClass);
-        put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
-    }
-
-    private void putAsymmetricCipherImpl(String transformation, String implClass) {
-        put("Cipher." + transformation, implClass);
-        put("Cipher." + transformation + " SupportedKeyClasses",
-                KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
-    }
-
-    private void putSignatureImpl(String algorithm, String implClass) {
-        put("Signature." + algorithm, implClass);
-        put("Signature." + algorithm + " SupportedKeyClasses",
-                KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
-    }
-
-    public static String[] getSupportedEcdsaSignatureDigests() {
-        return new String[] {"NONE", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
-    }
-
-    public static String[] getSupportedRsaSignatureWithPkcs1PaddingDigests() {
-        return new String[] {"NONE", "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
deleted file mode 100644
index ccc3153..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ /dev/null
@@ -1,920 +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.security.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * Base class for {@link CipherSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation {
-    private final KeyStore mKeyStore;
-
-    // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
-    // doFinal finishes.
-    private boolean mEncrypting;
-    private int mKeymasterPurposeOverride = -1;
-    private AndroidKeyStoreKey mKey;
-    private SecureRandom mRng;
-
-    /**
-     * Token referencing this operation inside keystore service. It is initialized by
-     * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and on some error
-     * conditions in between.
-     */
-    private IBinder mOperationToken;
-    private long mOperationHandle;
-    private KeyStoreCryptoOperationStreamer mMainDataStreamer;
-    private KeyStoreCryptoOperationStreamer mAdditionalAuthenticationDataStreamer;
-    private boolean mAdditionalAuthenticationDataStreamerClosed;
-
-    /**
-     * Encountered exception which could not be immediately thrown because it was encountered inside
-     * a method that does not throw checked exception. This exception will be thrown from
-     * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and
-     * {@code engineDoFinal} start ignoring input data.
-     */
-    private Exception mCachedException;
-
-    AndroidKeyStoreCipherSpiBase() {
-        mKeyStore = KeyStore.getInstance();
-    }
-
-    @Override
-    protected final void engineInit(int opmode, Key key, SecureRandom random)
-            throws InvalidKeyException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            init(opmode, key, random);
-            initAlgorithmSpecificParameters();
-            try {
-                ensureKeystoreOperationInitialized();
-            } catch (InvalidAlgorithmParameterException e) {
-                throw new InvalidKeyException(e);
-            }
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    @Override
-    protected final void engineInit(int opmode, Key key, AlgorithmParameters params,
-            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            init(opmode, key, random);
-            initAlgorithmSpecificParameters(params);
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    @Override
-    protected final void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
-            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            init(opmode, key, random);
-            initAlgorithmSpecificParameters(params);
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
-        switch (opmode) {
-            case Cipher.ENCRYPT_MODE:
-            case Cipher.WRAP_MODE:
-                mEncrypting = true;
-                break;
-            case Cipher.DECRYPT_MODE:
-            case Cipher.UNWRAP_MODE:
-                mEncrypting = false;
-                break;
-            default:
-                throw new InvalidParameterException("Unsupported opmode: " + opmode);
-        }
-        initKey(opmode, key);
-        if (mKey == null) {
-            throw new ProviderException("initKey did not initialize the key");
-        }
-        mRng = random;
-    }
-
-    /**
-     * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
-     * cipher instance.
-     *
-     * <p>Subclasses storing additional state should override this method, reset the additional
-     * state, and then chain to superclass.
-     */
-    @CallSuper
-    protected void resetAll() {
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mKeyStore.abort(operationToken);
-        }
-        mEncrypting = false;
-        mKeymasterPurposeOverride = -1;
-        mKey = null;
-        mRng = null;
-        mOperationToken = null;
-        mOperationHandle = 0;
-        mMainDataStreamer = null;
-        mAdditionalAuthenticationDataStreamer = null;
-        mAdditionalAuthenticationDataStreamerClosed = false;
-        mCachedException = null;
-    }
-
-    /**
-     * Resets this cipher while preserving the initialized state. This must be equivalent to
-     * rolling back the cipher's state to just after the most recent {@code engineInit} completed
-     * successfully.
-     *
-     * <p>Subclasses storing additional post-init state should override this method, reset the
-     * additional state, and then chain to superclass.
-     */
-    @CallSuper
-    protected void resetWhilePreservingInitState() {
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mKeyStore.abort(operationToken);
-        }
-        mOperationToken = null;
-        mOperationHandle = 0;
-        mMainDataStreamer = null;
-        mAdditionalAuthenticationDataStreamer = null;
-        mAdditionalAuthenticationDataStreamerClosed = false;
-        mCachedException = null;
-    }
-
-    private void ensureKeystoreOperationInitialized() throws InvalidKeyException,
-            InvalidAlgorithmParameterException {
-        if (mMainDataStreamer != null) {
-            return;
-        }
-        if (mCachedException != null) {
-            return;
-        }
-        if (mKey == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-
-        KeymasterArguments keymasterInputArgs = new KeymasterArguments();
-        addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
-        byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
-                mRng, getAdditionalEntropyAmountForBegin());
-
-        int purpose;
-        if (mKeymasterPurposeOverride != -1) {
-            purpose = mKeymasterPurposeOverride;
-        } else {
-            purpose = mEncrypting
-                    ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT;
-        }
-        OperationResult opResult = mKeyStore.begin(
-                mKey.getAlias(),
-                purpose,
-                true, // permit aborting this operation if keystore runs out of resources
-                keymasterInputArgs,
-                additionalEntropy,
-                mKey.getUid());
-        if (opResult == null) {
-            throw new KeyStoreConnectException();
-        }
-
-        // Store operation token and handle regardless of the error code returned by KeyStore to
-        // ensure that the operation gets aborted immediately if the code below throws an exception.
-        mOperationToken = opResult.token;
-        mOperationHandle = opResult.operationHandle;
-
-        // If necessary, throw an exception due to KeyStore operation having failed.
-        GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
-                mKeyStore, mKey, opResult.resultCode);
-        if (e != null) {
-            if (e instanceof InvalidKeyException) {
-                throw (InvalidKeyException) e;
-            } else if (e instanceof InvalidAlgorithmParameterException) {
-                throw (InvalidAlgorithmParameterException) e;
-            } else {
-                throw new ProviderException("Unexpected exception type", e);
-            }
-        }
-
-        if (mOperationToken == null) {
-            throw new ProviderException("Keystore returned null operation token");
-        }
-        if (mOperationHandle == 0) {
-            throw new ProviderException("Keystore returned invalid operation handle");
-        }
-
-        loadAlgorithmSpecificParametersFromBeginResult(opResult.outParams);
-        mMainDataStreamer = createMainDataStreamer(mKeyStore, opResult.token);
-        mAdditionalAuthenticationDataStreamer =
-                createAdditionalAuthenticationDataStreamer(mKeyStore, opResult.token);
-        mAdditionalAuthenticationDataStreamerClosed = false;
-    }
-
-    /**
-     * Creates a streamer which sends plaintext/ciphertext into the provided KeyStore and receives
-     * the corresponding ciphertext/plaintext from the KeyStore.
-     *
-     * <p>This implementation returns a working streamer.
-     */
-    @NonNull
-    protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
-            KeyStore keyStore, IBinder operationToken) {
-        return new KeyStoreCryptoOperationChunkedStreamer(
-                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                        keyStore, operationToken), 0);
-    }
-
-    /**
-     * Creates a streamer which sends Additional Authentication Data (AAD) into the KeyStore.
-     *
-     * <p>This implementation returns {@code null}.
-     *
-     * @return stream or {@code null} if AAD is not supported by this cipher.
-     */
-    @Nullable
-    protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
-            @SuppressWarnings("unused") KeyStore keyStore,
-            @SuppressWarnings("unused") IBinder operationToken) {
-        return null;
-    }
-
-    @Override
-    protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
-        if (mCachedException != null) {
-            return null;
-        }
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
-            mCachedException = e;
-            return null;
-        }
-
-        if (inputLen == 0) {
-            return null;
-        }
-
-        byte[] output;
-        try {
-            flushAAD();
-            output = mMainDataStreamer.update(input, inputOffset, inputLen);
-        } catch (KeyStoreException e) {
-            mCachedException = e;
-            return null;
-        }
-
-        if (output.length == 0) {
-            return null;
-        }
-
-        return output;
-    }
-
-    private void flushAAD() throws KeyStoreException {
-        if ((mAdditionalAuthenticationDataStreamer != null)
-                && (!mAdditionalAuthenticationDataStreamerClosed)) {
-            byte[] output;
-            try {
-                output = mAdditionalAuthenticationDataStreamer.doFinal(
-                        EmptyArray.BYTE, 0, 0,
-                        null, // no signature
-                        null // no additional entropy needed flushing AAD
-                        );
-            } finally {
-                mAdditionalAuthenticationDataStreamerClosed = true;
-            }
-            if ((output != null) && (output.length > 0)) {
-                throw new ProviderException(
-                        "AAD update unexpectedly returned data: " + output.length + " bytes");
-            }
-        }
-    }
-
-    @Override
-    protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
-            int outputOffset) throws ShortBufferException {
-        byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
-        if (outputCopy == null) {
-            return 0;
-        }
-        int outputAvailable = output.length - outputOffset;
-        if (outputCopy.length > outputAvailable) {
-            throw new ShortBufferException("Output buffer too short. Produced: "
-                    + outputCopy.length + ", available: " + outputAvailable);
-        }
-        System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
-        return outputCopy.length;
-    }
-
-    @Override
-    protected final int engineUpdate(ByteBuffer input, ByteBuffer output)
-            throws ShortBufferException {
-        if (input == null) {
-            throw new NullPointerException("input == null");
-        }
-        if (output == null) {
-            throw new NullPointerException("output == null");
-        }
-
-        int inputSize = input.remaining();
-        byte[] outputArray;
-        if (input.hasArray()) {
-            outputArray =
-                    engineUpdate(
-                            input.array(), input.arrayOffset() + input.position(), inputSize);
-            input.position(input.position() + inputSize);
-        } else {
-            byte[] inputArray = new byte[inputSize];
-            input.get(inputArray);
-            outputArray = engineUpdate(inputArray, 0, inputSize);
-        }
-
-        int outputSize = (outputArray != null) ? outputArray.length : 0;
-        if (outputSize > 0) {
-            int outputBufferAvailable = output.remaining();
-            try {
-                output.put(outputArray);
-            } catch (BufferOverflowException e) {
-                throw new ShortBufferException(
-                        "Output buffer too small. Produced: " + outputSize + ", available: "
-                                + outputBufferAvailable);
-            }
-        }
-        return outputSize;
-    }
-
-    @Override
-    protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
-        if (mCachedException != null) {
-            return;
-        }
-
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
-            mCachedException = e;
-            return;
-        }
-
-        if (mAdditionalAuthenticationDataStreamerClosed) {
-            throw new IllegalStateException(
-                    "AAD can only be provided before Cipher.update is invoked");
-        }
-
-        if (mAdditionalAuthenticationDataStreamer == null) {
-            throw new IllegalStateException("This cipher does not support AAD");
-        }
-
-        byte[] output;
-        try {
-            output = mAdditionalAuthenticationDataStreamer.update(input, inputOffset, inputLen);
-        } catch (KeyStoreException e) {
-            mCachedException = e;
-            return;
-        }
-
-        if ((output != null) && (output.length > 0)) {
-            throw new ProviderException("AAD update unexpectedly produced output: "
-                    + output.length + " bytes");
-        }
-    }
-
-    @Override
-    protected final void engineUpdateAAD(ByteBuffer src) {
-        if (src == null) {
-            throw new IllegalArgumentException("src == null");
-        }
-        if (!src.hasRemaining()) {
-            return;
-        }
-
-        byte[] input;
-        int inputOffset;
-        int inputLen;
-        if (src.hasArray()) {
-            input = src.array();
-            inputOffset = src.arrayOffset() + src.position();
-            inputLen = src.remaining();
-            src.position(src.limit());
-        } else {
-            input = new byte[src.remaining()];
-            inputOffset = 0;
-            inputLen = input.length;
-            src.get(input);
-        }
-        engineUpdateAAD(input, inputOffset, inputLen);
-    }
-
-    @Override
-    protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
-            throws IllegalBlockSizeException, BadPaddingException {
-        if (mCachedException != null) {
-            throw (IllegalBlockSizeException)
-                    new IllegalBlockSizeException().initCause(mCachedException);
-        }
-
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
-            throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
-        }
-
-        byte[] output;
-        try {
-            flushAAD();
-            byte[] additionalEntropy =
-                    KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
-                            mRng, getAdditionalEntropyAmountForFinish());
-            output = mMainDataStreamer.doFinal(
-                    input, inputOffset, inputLen,
-                    null, // no signature involved
-                    additionalEntropy);
-        } catch (KeyStoreException e) {
-            switch (e.getErrorCode()) {
-                case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
-                    throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
-                case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
-                    throw (BadPaddingException) new BadPaddingException().initCause(e);
-                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
-                    throw (AEADBadTagException) new AEADBadTagException().initCause(e);
-                default:
-                    throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
-            }
-        }
-
-        resetWhilePreservingInitState();
-        return output;
-    }
-
-    @Override
-    protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
-            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
-            BadPaddingException {
-        byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
-        if (outputCopy == null) {
-            return 0;
-        }
-        int outputAvailable = output.length - outputOffset;
-        if (outputCopy.length > outputAvailable) {
-            throw new ShortBufferException("Output buffer too short. Produced: "
-                    + outputCopy.length + ", available: " + outputAvailable);
-        }
-        System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
-        return outputCopy.length;
-    }
-
-    @Override
-    protected final int engineDoFinal(ByteBuffer input, ByteBuffer output)
-            throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
-        if (input == null) {
-            throw new NullPointerException("input == null");
-        }
-        if (output == null) {
-            throw new NullPointerException("output == null");
-        }
-
-        int inputSize = input.remaining();
-        byte[] outputArray;
-        if (input.hasArray()) {
-            outputArray =
-                    engineDoFinal(
-                            input.array(), input.arrayOffset() + input.position(), inputSize);
-            input.position(input.position() + inputSize);
-        } else {
-            byte[] inputArray = new byte[inputSize];
-            input.get(inputArray);
-            outputArray = engineDoFinal(inputArray, 0, inputSize);
-        }
-
-        int outputSize = (outputArray != null) ? outputArray.length : 0;
-        if (outputSize > 0) {
-            int outputBufferAvailable = output.remaining();
-            try {
-                output.put(outputArray);
-            } catch (BufferOverflowException e) {
-                throw new ShortBufferException(
-                        "Output buffer too small. Produced: " + outputSize + ", available: "
-                                + outputBufferAvailable);
-            }
-        }
-        return outputSize;
-    }
-
-    @Override
-    protected final byte[] engineWrap(Key key)
-            throws IllegalBlockSizeException, InvalidKeyException {
-        if (mKey == null) {
-            throw new IllegalStateException("Not initilized");
-        }
-
-        if (!isEncrypting()) {
-            throw new IllegalStateException(
-                    "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
-        }
-
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-        byte[] encoded = null;
-        if (key instanceof SecretKey) {
-            if ("RAW".equalsIgnoreCase(key.getFormat())) {
-                encoded = key.getEncoded();
-            }
-            if (encoded == null) {
-                try {
-                    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(key.getAlgorithm());
-                    SecretKeySpec spec =
-                            (SecretKeySpec) keyFactory.getKeySpec(
-                                    (SecretKey) key, SecretKeySpec.class);
-                    encoded = spec.getEncoded();
-                } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-                    throw new InvalidKeyException(
-                            "Failed to wrap key because it does not export its key material",
-                            e);
-                }
-            }
-        } else if (key instanceof PrivateKey) {
-            if ("PKCS8".equalsIgnoreCase(key.getFormat())) {
-                encoded = key.getEncoded();
-            }
-            if (encoded == null) {
-                try {
-                    KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
-                    PKCS8EncodedKeySpec spec =
-                            keyFactory.getKeySpec(key, PKCS8EncodedKeySpec.class);
-                    encoded = spec.getEncoded();
-                } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-                    throw new InvalidKeyException(
-                            "Failed to wrap key because it does not export its key material",
-                            e);
-                }
-            }
-        } else if (key instanceof PublicKey) {
-            if ("X.509".equalsIgnoreCase(key.getFormat())) {
-                encoded = key.getEncoded();
-            }
-            if (encoded == null) {
-                try {
-                    KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
-                    X509EncodedKeySpec spec =
-                            keyFactory.getKeySpec(key, X509EncodedKeySpec.class);
-                    encoded = spec.getEncoded();
-                } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-                    throw new InvalidKeyException(
-                            "Failed to wrap key because it does not export its key material",
-                            e);
-                }
-            }
-        } else {
-            throw new InvalidKeyException("Unsupported key type: " + key.getClass().getName());
-        }
-
-        if (encoded == null) {
-            throw new InvalidKeyException(
-                    "Failed to wrap key because it does not export its key material");
-        }
-
-        try {
-            return engineDoFinal(encoded, 0, encoded.length);
-        } catch (BadPaddingException e) {
-            throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
-        }
-    }
-
-    @Override
-    protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
-            int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
-        if (mKey == null) {
-            throw new IllegalStateException("Not initilized");
-        }
-
-        if (isEncrypting()) {
-            throw new IllegalStateException(
-                    "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
-        }
-
-        if (wrappedKey == null) {
-            throw new NullPointerException("wrappedKey == null");
-        }
-
-        byte[] encoded;
-        try {
-            encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
-        } catch (IllegalBlockSizeException | BadPaddingException e) {
-            throw new InvalidKeyException("Failed to unwrap key", e);
-        }
-
-        switch (wrappedKeyType) {
-            case Cipher.SECRET_KEY:
-            {
-                return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
-                // break;
-            }
-            case Cipher.PRIVATE_KEY:
-            {
-                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
-                try {
-                    return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
-                } catch (InvalidKeySpecException e) {
-                    throw new InvalidKeyException(
-                            "Failed to create private key from its PKCS#8 encoded form", e);
-                }
-                // break;
-            }
-            case Cipher.PUBLIC_KEY:
-            {
-                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
-                try {
-                    return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
-                } catch (InvalidKeySpecException e) {
-                    throw new InvalidKeyException(
-                            "Failed to create public key from its X.509 encoded form", e);
-                }
-                // break;
-            }
-            default:
-                throw new InvalidParameterException(
-                        "Unsupported wrappedKeyType: " + wrappedKeyType);
-        }
-    }
-
-    @Override
-    protected final void engineSetMode(String mode) throws NoSuchAlgorithmException {
-        // This should never be invoked because all algorithms registered with the AndroidKeyStore
-        // provide explicitly specify block mode.
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected final void engineSetPadding(String arg0) throws NoSuchPaddingException {
-        // This should never be invoked because all algorithms registered with the AndroidKeyStore
-        // provide explicitly specify padding mode.
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected final int engineGetKeySize(Key key) throws InvalidKeyException {
-        throw new UnsupportedOperationException();
-    }
-
-    @CallSuper
-    @Override
-    public void finalize() throws Throwable {
-        try {
-            IBinder operationToken = mOperationToken;
-            if (operationToken != null) {
-                mKeyStore.abort(operationToken);
-            }
-        } finally {
-            super.finalize();
-        }
-    }
-
-    @Override
-    public final long getOperationHandle() {
-        return mOperationHandle;
-    }
-
-    protected final void setKey(@NonNull AndroidKeyStoreKey key) {
-        mKey = key;
-    }
-
-    /**
-     * Overrides the default purpose/type of the crypto operation.
-     */
-    protected final void setKeymasterPurposeOverride(int keymasterPurpose) {
-        mKeymasterPurposeOverride = keymasterPurpose;
-    }
-
-    protected final int getKeymasterPurposeOverride() {
-        return mKeymasterPurposeOverride;
-    }
-
-    /**
-     * Returns {@code true} if this cipher is initialized for encryption, {@code false} if this
-     * cipher is initialized for decryption.
-     */
-    protected final boolean isEncrypting() {
-        return mEncrypting;
-    }
-
-    @NonNull
-    protected final KeyStore getKeyStore() {
-        return mKeyStore;
-    }
-
-    protected final long getConsumedInputSizeBytes() {
-        if (mMainDataStreamer == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-        return mMainDataStreamer.getConsumedInputSizeBytes();
-    }
-
-    protected final long getProducedOutputSizeBytes() {
-        if (mMainDataStreamer == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-        return mMainDataStreamer.getProducedOutputSizeBytes();
-    }
-
-    static String opmodeToString(int opmode) {
-        switch (opmode) {
-            case Cipher.ENCRYPT_MODE:
-                return "ENCRYPT_MODE";
-            case Cipher.DECRYPT_MODE:
-                return "DECRYPT_MODE";
-            case Cipher.WRAP_MODE:
-                return "WRAP_MODE";
-            case Cipher.UNWRAP_MODE:
-                return "UNWRAP_MODE";
-            default:
-                return String.valueOf(opmode);
-        }
-    }
-
-    // The methods below need to be implemented by subclasses.
-
-    /**
-     * Initializes this cipher with the provided key.
-     *
-     * @throws InvalidKeyException if the {@code key} is not suitable for this cipher in the
-     *         specified {@code opmode}.
-     *
-     * @see #setKey(AndroidKeyStoreKey)
-     */
-    protected abstract void initKey(int opmode, @Nullable Key key) throws InvalidKeyException;
-
-    /**
-     * Returns algorithm-specific parameters used by this cipher or {@code null} if no
-     * algorithm-specific parameters are used.
-     */
-    @Nullable
-    @Override
-    protected abstract AlgorithmParameters engineGetParameters();
-
-    /**
-     * Invoked by {@code engineInit} to initialize algorithm-specific parameters when no additional
-     * initialization parameters were provided.
-     *
-     * @throws InvalidKeyException if this cipher cannot be configured based purely on the provided
-     *         key and needs additional parameters to be provided to {@code Cipher.init}.
-     */
-    protected abstract void initAlgorithmSpecificParameters() throws InvalidKeyException;
-
-    /**
-     * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
-     * parameters were provided.
-     *
-     * @param params additional algorithm parameters or {@code null} if not specified.
-     *
-     * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
-     *         this cipher or if the provided parameters are not suitable for this cipher.
-     */
-    protected abstract void initAlgorithmSpecificParameters(
-            @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException;
-
-    /**
-     * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
-     * parameters were provided.
-     *
-     * @param params additional algorithm parameters or {@code null} if not specified.
-     *
-     * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
-     *         this cipher or if the provided parameters are not suitable for this cipher.
-     */
-    protected abstract void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
-            throws InvalidAlgorithmParameterException;
-
-    /**
-     * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
-     * {@code begin} operation. This amount of entropy is typically what's consumed to generate
-     * random parameters, such as IV.
-     *
-     * <p>For decryption, the return value should be {@code 0} because decryption should not be
-     * consuming any entropy. For encryption, the value combined with
-     * {@link #getAdditionalEntropyAmountForFinish()} should match (or exceed) the amount of Shannon
-     * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
-     * explicitly provided parameters to {@code Cipher.init} are known. For example, for AES CBC
-     * encryption with an explicitly provided IV the return value should be {@code 0}, whereas for
-     * the case where IV is generated by the KeyStore's {@code begin} operation it should be
-     * {@code 16}.
-     */
-    protected abstract int getAdditionalEntropyAmountForBegin();
-
-    /**
-     * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
-     * {@code finish} operation. This amount of entropy is typically what's consumed by encryption
-     * padding scheme.
-     *
-     * <p>For decryption, the return value should be {@code 0} because decryption should not be
-     * consuming any entropy. For encryption, the value combined with
-     * {@link #getAdditionalEntropyAmountForBegin()} should match (or exceed) the amount of Shannon
-     * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
-     * explicitly provided parameters to {@code Cipher.init} are known. For example, for RSA with
-     * OAEP the return value should be the size of the OAEP hash output. For RSA with PKCS#1 padding
-     * the return value should be the size of the padding string or could be raised (for simplicity)
-     * to the size of the modulus.
-     */
-    protected abstract int getAdditionalEntropyAmountForFinish();
-
-    /**
-     * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
-     *
-     * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
-     *        parameters.
-     */
-    protected abstract void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs);
-
-    /**
-     * Invoked to obtain algorithm-specific parameters from the result of the KeyStore's
-     * {@code begin} operation.
-     *
-     * <p>Some parameters, such as IV, are not required to be provided to {@code Cipher.init}. Such
-     * parameters, if not provided, must be generated by KeyStore and returned to the user of
-     * {@code Cipher} and potentially reused after {@code doFinal}.
-     *
-     * @param keymasterArgs keystore/keymaster arguments returned by KeyStore {@code begin}
-     *        operation.
-     */
-    protected abstract void loadAlgorithmSpecificParametersFromBeginResult(
-            @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
deleted file mode 100644
index 45f2110..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ /dev/null
@@ -1,202 +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.security.keystore;
-
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
-    public final static class NONE extends AndroidKeyStoreECDSASignatureSpi {
-        public NONE() {
-            super(KeymasterDefs.KM_DIGEST_NONE);
-        }
-
-        @Override
-        protected KeyStoreCryptoOperationStreamer createMainDataStreamer(KeyStore keyStore,
-                IBinder operationToken) {
-            return new TruncateToFieldSizeMessageStreamer(
-                    super.createMainDataStreamer(keyStore, operationToken),
-                    getGroupSizeBits());
-        }
-
-        /**
-         * Streamer which buffers all input, then truncates it to field size, and then sends it into
-         * KeyStore via the provided delegate streamer.
-         */
-        private static class TruncateToFieldSizeMessageStreamer
-                implements KeyStoreCryptoOperationStreamer {
-
-            private final KeyStoreCryptoOperationStreamer mDelegate;
-            private final int mGroupSizeBits;
-            private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
-            private long mConsumedInputSizeBytes;
-
-            private TruncateToFieldSizeMessageStreamer(
-                    KeyStoreCryptoOperationStreamer delegate,
-                    int groupSizeBits) {
-                mDelegate = delegate;
-                mGroupSizeBits = groupSizeBits;
-            }
-
-            @Override
-            public byte[] update(byte[] input, int inputOffset, int inputLength)
-                    throws KeyStoreException {
-                if (inputLength > 0) {
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                    mConsumedInputSizeBytes += inputLength;
-                }
-                return EmptyArray.BYTE;
-            }
-
-            @Override
-            public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
-                    byte[] additionalEntropy) throws KeyStoreException {
-                if (inputLength > 0) {
-                    mConsumedInputSizeBytes += inputLength;
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                }
-
-                byte[] bufferedInput = mInputBuffer.toByteArray();
-                mInputBuffer.reset();
-                // Truncate input at field size (bytes)
-                return mDelegate.doFinal(bufferedInput,
-                        0,
-                        Math.min(bufferedInput.length, ((mGroupSizeBits + 7) / 8)),
-                        signature, additionalEntropy);
-            }
-
-            @Override
-            public long getConsumedInputSizeBytes() {
-                return mConsumedInputSizeBytes;
-            }
-
-            @Override
-            public long getProducedOutputSizeBytes() {
-                return mDelegate.getProducedOutputSizeBytes();
-            }
-        }
-    }
-
-    public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
-        public SHA1() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public final static class SHA224 extends AndroidKeyStoreECDSASignatureSpi {
-        public SHA224() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public final static class SHA256 extends AndroidKeyStoreECDSASignatureSpi {
-        public SHA256() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public final static class SHA384 extends AndroidKeyStoreECDSASignatureSpi {
-        public SHA384() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public final static class SHA512 extends AndroidKeyStoreECDSASignatureSpi {
-        public SHA512() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    private final int mKeymasterDigest;
-
-    private int mGroupSizeBits = -1;
-
-    AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
-        mKeymasterDigest = keymasterDigest;
-    }
-
-    @Override
-    protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
-        if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
-                    + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
-        }
-
-        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode = getKeyStore().getKeyCharacteristics(
-                key.getAlias(), null, null, key.getUid(), keyCharacteristics);
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
-        }
-        long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
-        if (keySizeBits == -1) {
-            throw new InvalidKeyException("Size of key not known");
-        } else if (keySizeBits > Integer.MAX_VALUE) {
-            throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
-        }
-        mGroupSizeBits = (int) keySizeBits;
-
-        super.initKey(key);
-    }
-
-    @Override
-    protected final void resetAll() {
-        mGroupSizeBits = -1;
-        super.resetAll();
-    }
-
-    @Override
-    protected final void resetWhilePreservingInitState() {
-        super.resetWhilePreservingInitState();
-    }
-
-    @Override
-    protected final void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs) {
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-    }
-
-    @Override
-    protected final int getAdditionalEntropyAmountForSign() {
-        return (mGroupSizeBits + 7) / 8;
-    }
-
-    protected final int getGroupSizeBits() {
-        if (mGroupSizeBits == -1) {
-            throw new IllegalStateException("Not initialized");
-        }
-        return mGroupSizeBits;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
deleted file mode 100644
index aa7bdff..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
+++ /dev/null
@@ -1,40 +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.security.keystore;
-
-import java.security.PrivateKey;
-import java.security.interfaces.ECKey;
-import java.security.spec.ECParameterSpec;
-
-/**
- * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
-    private final ECParameterSpec mParams;
-
-    public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
-        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
-        mParams = params;
-    }
-
-    @Override
-    public ECParameterSpec getParams() {
-        return mParams;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
deleted file mode 100644
index 2efaeb6..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
+++ /dev/null
@@ -1,57 +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.security.keystore;
-
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-
-/**
- * {@link ECPublicKey} backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey implements ECPublicKey {
-
-    private final ECParameterSpec mParams;
-    private final ECPoint mW;
-
-    public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
-            ECPoint w) {
-        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
-        mParams = params;
-        mW = w;
-    }
-
-    public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
-        this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
-        if (!"X.509".equalsIgnoreCase(info.getFormat())) {
-            throw new IllegalArgumentException(
-                    "Unsupported key export format: " + info.getFormat());
-        }
-    }
-
-    @Override
-    public ECParameterSpec getParams() {
-        return mParams;
-    }
-
-    @Override
-    public ECPoint getW() {
-        return mW;
-    }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
deleted file mode 100644
index 2e8ac32..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ /dev/null
@@ -1,265 +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.security.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-
-import javax.crypto.MacSpi;
-
-/**
- * {@link MacSpi} which provides HMAC implementations backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
-
-    public static class HmacSHA1 extends AndroidKeyStoreHmacSpi {
-        public HmacSHA1() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public static class HmacSHA224 extends AndroidKeyStoreHmacSpi {
-        public HmacSHA224() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public static class HmacSHA256 extends AndroidKeyStoreHmacSpi {
-        public HmacSHA256() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public static class HmacSHA384 extends AndroidKeyStoreHmacSpi {
-        public HmacSHA384() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public static class HmacSHA512 extends AndroidKeyStoreHmacSpi {
-        public HmacSHA512() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final int mKeymasterDigest;
-    private final int mMacSizeBits;
-
-    // Fields below are populated by engineInit and should be preserved after engineDoFinal.
-    private AndroidKeyStoreSecretKey mKey;
-
-    // Fields below are reset when engineDoFinal succeeds.
-    private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
-    private IBinder mOperationToken;
-    private long mOperationHandle;
-
-    protected AndroidKeyStoreHmacSpi(int keymasterDigest) {
-        mKeymasterDigest = keymasterDigest;
-        mMacSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
-    }
-
-    @Override
-    protected int engineGetMacLength() {
-        return (mMacSizeBits + 7) / 8;
-    }
-
-    @Override
-    protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
-            InvalidAlgorithmParameterException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            init(key, params);
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    private void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
-        InvalidAlgorithmParameterException {
-        if (key == null) {
-            throw new InvalidKeyException("key == null");
-        } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeyException(
-                    "Only Android KeyStore secret keys supported. Key: " + key);
-        }
-        mKey = (AndroidKeyStoreSecretKey) key;
-
-        if (params != null) {
-            throw new InvalidAlgorithmParameterException(
-                    "Unsupported algorithm parameters: " + params);
-        }
-
-    }
-
-    private void resetAll() {
-        mKey = null;
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mKeyStore.abort(operationToken);
-        }
-        mOperationToken = null;
-        mOperationHandle = 0;
-        mChunkedStreamer = null;
-    }
-
-    private void resetWhilePreservingInitState() {
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mKeyStore.abort(operationToken);
-        }
-        mOperationToken = null;
-        mOperationHandle = 0;
-        mChunkedStreamer = null;
-    }
-
-    @Override
-    protected void engineReset() {
-        resetWhilePreservingInitState();
-    }
-
-    private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
-        if (mChunkedStreamer != null) {
-            return;
-        }
-        if (mKey == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-
-        KeymasterArguments keymasterArgs = new KeymasterArguments();
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-        keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mMacSizeBits);
-
-        OperationResult opResult = mKeyStore.begin(
-                mKey.getAlias(),
-                KeymasterDefs.KM_PURPOSE_SIGN,
-                true,
-                keymasterArgs,
-                null, // no additional entropy needed for HMAC because it's deterministic
-                mKey.getUid());
-
-        if (opResult == null) {
-            throw new KeyStoreConnectException();
-        }
-
-        // Store operation token and handle regardless of the error code returned by KeyStore to
-        // ensure that the operation gets aborted immediately if the code below throws an exception.
-        mOperationToken = opResult.token;
-        mOperationHandle = opResult.operationHandle;
-
-        // If necessary, throw an exception due to KeyStore operation having failed.
-        InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
-                mKeyStore, mKey, opResult.resultCode);
-        if (e != null) {
-            throw e;
-        }
-
-        if (mOperationToken == null) {
-            throw new ProviderException("Keystore returned null operation token");
-        }
-        if (mOperationHandle == 0) {
-            throw new ProviderException("Keystore returned invalid operation handle");
-        }
-
-        mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
-                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                        mKeyStore, mOperationToken));
-    }
-
-    @Override
-    protected void engineUpdate(byte input) {
-        engineUpdate(new byte[] {input}, 0, 1);
-    }
-
-    @Override
-    protected void engineUpdate(byte[] input, int offset, int len) {
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException e) {
-            throw new ProviderException("Failed to reinitialize MAC", e);
-        }
-
-        byte[] output;
-        try {
-            output = mChunkedStreamer.update(input, offset, len);
-        } catch (KeyStoreException e) {
-            throw new ProviderException("Keystore operation failed", e);
-        }
-        if ((output != null) && (output.length != 0)) {
-            throw new ProviderException("Update operation unexpectedly produced output");
-        }
-    }
-
-    @Override
-    protected byte[] engineDoFinal() {
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException e) {
-            throw new ProviderException("Failed to reinitialize MAC", e);
-        }
-
-        byte[] result;
-        try {
-            result = mChunkedStreamer.doFinal(
-                    null, 0, 0,
-                    null, // no signature provided -- this invocation will generate one
-                    null // no additional entropy needed -- HMAC is deterministic
-                    );
-        } catch (KeyStoreException e) {
-            throw new ProviderException("Keystore operation failed", e);
-        }
-
-        resetWhilePreservingInitState();
-        return result;
-    }
-
-    @Override
-    public void finalize() throws Throwable {
-        try {
-            IBinder operationToken = mOperationToken;
-            if (operationToken != null) {
-                mKeyStore.abort(operationToken);
-            }
-        } finally {
-            super.finalize();
-        }
-    }
-
-    @Override
-    public long getOperationHandle() {
-        return mOperationHandle;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
deleted file mode 100644
index e8e6310..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ /dev/null
@@ -1,103 +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.security.keystore;
-
-import java.security.Key;
-
-/**
- * {@link Key} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreKey implements Key {
-    private final String mAlias;
-    private final int mUid;
-    private final String mAlgorithm;
-
-    public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
-        mAlias = alias;
-        mUid = uid;
-        mAlgorithm = algorithm;
-    }
-
-    String getAlias() {
-        return mAlias;
-    }
-
-    int getUid() {
-        return mUid;
-    }
-
-    @Override
-    public String getAlgorithm() {
-        return mAlgorithm;
-    }
-
-    @Override
-    public String getFormat() {
-        // This key does not export its key material
-        return null;
-    }
-
-    @Override
-    public byte[] getEncoded() {
-        // This key does not export its key material
-        return null;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
-        result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
-        result = prime * result + mUid;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
-        if (mAlgorithm == null) {
-            if (other.mAlgorithm != null) {
-                return false;
-            }
-        } else if (!mAlgorithm.equals(other.mAlgorithm)) {
-            return false;
-        }
-        if (mAlias == null) {
-            if (other.mAlias != null) {
-                return false;
-            }
-        } else if (!mAlias.equals(other.mAlias)) {
-            return false;
-        }
-        if (mUid != other.mUid) {
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
deleted file mode 100644
index 303b0f2..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ /dev/null
@@ -1,151 +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.security.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyFactorySpi;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-/**
- * {@link KeyFactorySpi} backed by Android KeyStore.
- *
- * @hide
- */
-public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
-
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-
-    @Override
-    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass)
-            throws InvalidKeySpecException {
-        if (key == null) {
-            throw new InvalidKeySpecException("key == null");
-        } else if ((!(key instanceof AndroidKeyStorePrivateKey))
-            && (!(key instanceof AndroidKeyStorePublicKey))) {
-            throw new InvalidKeySpecException(
-                    "Unsupported key type: " + key.getClass().getName()
-                    + ". This KeyFactory supports only Android Keystore asymmetric keys");
-        }
-
-        // key is an Android Keystore private or public key
-
-        if (keySpecClass == null) {
-            throw new InvalidKeySpecException("keySpecClass == null");
-        } else if (KeyInfo.class.equals(keySpecClass)) {
-            if (!(key instanceof AndroidKeyStorePrivateKey)) {
-                throw new InvalidKeySpecException(
-                        "Unsupported key type: " + key.getClass().getName()
-                        + ". KeyInfo can be obtained only for Android Keystore private keys");
-            }
-            AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
-            String keyAliasInKeystore = keystorePrivateKey.getAlias();
-            String entryAlias;
-            if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
-                entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
-            } else {
-                throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
-            }
-            @SuppressWarnings("unchecked")
-            T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
-                    mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
-            return result;
-        } else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
-            if (!(key instanceof AndroidKeyStorePublicKey)) {
-                throw new InvalidKeySpecException(
-                        "Unsupported key type: " + key.getClass().getName()
-                        + ". X509EncodedKeySpec can be obtained only for Android Keystore public"
-                        + " keys");
-            }
-            @SuppressWarnings("unchecked")
-            T result = (T) new X509EncodedKeySpec(((AndroidKeyStorePublicKey) key).getEncoded());
-            return result;
-        } else if (PKCS8EncodedKeySpec.class.equals(keySpecClass)) {
-            if (key instanceof AndroidKeyStorePrivateKey) {
-                throw new InvalidKeySpecException(
-                        "Key material export of Android Keystore private keys is not supported");
-            } else {
-                throw new InvalidKeySpecException(
-                        "Cannot export key material of public key in PKCS#8 format."
-                        + " Only X.509 format (X509EncodedKeySpec) supported for public keys.");
-            }
-        } else if (RSAPublicKeySpec.class.equals(keySpecClass)) {
-            if (key instanceof AndroidKeyStoreRSAPublicKey) {
-                AndroidKeyStoreRSAPublicKey rsaKey = (AndroidKeyStoreRSAPublicKey) key;
-                @SuppressWarnings("unchecked")
-                T result =
-                        (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
-                return result;
-            } else {
-                throw new InvalidKeySpecException(
-                        "Obtaining RSAPublicKeySpec not supported for " + key.getAlgorithm() + " "
-                        + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
-                        + " key");
-            }
-        } else if (ECPublicKeySpec.class.equals(keySpecClass)) {
-            if (key instanceof AndroidKeyStoreECPublicKey) {
-                AndroidKeyStoreECPublicKey ecKey = (AndroidKeyStoreECPublicKey) key;
-                @SuppressWarnings("unchecked")
-                T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
-                return result;
-            } else {
-                throw new InvalidKeySpecException(
-                        "Obtaining ECPublicKeySpec not supported for " + key.getAlgorithm() + " "
-                        + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
-                        + " key");
-            }
-        } else {
-            throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
-        }
-    }
-
-    @Override
-    protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
-        throw new InvalidKeySpecException(
-                "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
-                + " " + KeyGenParameterSpec.class.getName());
-    }
-
-    @Override
-    protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
-        throw new InvalidKeySpecException(
-                "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
-                + " " + KeyGenParameterSpec.class.getName());
-    }
-
-    @Override
-    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
-        if (key == null) {
-            throw new InvalidKeyException("key == null");
-        } else if ((!(key instanceof AndroidKeyStorePrivateKey))
-                && (!(key instanceof AndroidKeyStorePublicKey))) {
-            throw new InvalidKeyException(
-                    "To import a key into Android Keystore, use KeyStore.setEntry");
-        }
-        return key;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
deleted file mode 100644
index fedde42..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ /dev/null
@@ -1,352 +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.security.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
-import libcore.util.EmptyArray;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.ProviderException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.KeyGeneratorSpi;
-import javax.crypto.SecretKey;
-
-/**
- * {@link KeyGeneratorSpi} backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
-
-    public static class AES extends AndroidKeyStoreKeyGeneratorSpi {
-        public AES() {
-            super(KeymasterDefs.KM_ALGORITHM_AES, 128);
-        }
-
-        @Override
-        protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
-                throws InvalidAlgorithmParameterException {
-            super.engineInit(params, random);
-            if ((mKeySizeBits != 128) && (mKeySizeBits != 192) && (mKeySizeBits != 256)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported key size: " + mKeySizeBits
-                        + ". Supported: 128, 192, 256.");
-            }
-        }
-    }
-
-    public static class DESede extends AndroidKeyStoreKeyGeneratorSpi {
-        public DESede() {
-            super(KeymasterDefs.KM_ALGORITHM_3DES, 168);
-        }
-    }
-
-    protected static abstract class HmacBase extends AndroidKeyStoreKeyGeneratorSpi {
-        protected HmacBase(int keymasterDigest) {
-            super(KeymasterDefs.KM_ALGORITHM_HMAC,
-                    keymasterDigest,
-                    KeymasterUtils.getDigestOutputSizeBits(keymasterDigest));
-        }
-    }
-
-    public static class HmacSHA1 extends HmacBase {
-        public HmacSHA1() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public static class HmacSHA224 extends HmacBase {
-        public HmacSHA224() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public static class HmacSHA256 extends HmacBase {
-        public HmacSHA256() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public static class HmacSHA384 extends HmacBase {
-        public HmacSHA384() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public static class HmacSHA512 extends HmacBase {
-        public HmacSHA512() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final int mKeymasterAlgorithm;
-    private final int mKeymasterDigest;
-    private final int mDefaultKeySizeBits;
-
-    private KeyGenParameterSpec mSpec;
-    private SecureRandom mRng;
-
-    protected int mKeySizeBits;
-    private int[] mKeymasterPurposes;
-    private int[] mKeymasterBlockModes;
-    private int[] mKeymasterPaddings;
-    private int[] mKeymasterDigests;
-
-    protected AndroidKeyStoreKeyGeneratorSpi(
-            int keymasterAlgorithm,
-            int defaultKeySizeBits) {
-        this(keymasterAlgorithm, -1, defaultKeySizeBits);
-    }
-
-    protected AndroidKeyStoreKeyGeneratorSpi(
-            int keymasterAlgorithm,
-            int keymasterDigest,
-            int defaultKeySizeBits) {
-        mKeymasterAlgorithm = keymasterAlgorithm;
-        mKeymasterDigest = keymasterDigest;
-        mDefaultKeySizeBits = defaultKeySizeBits;
-        if (mDefaultKeySizeBits <= 0) {
-            throw new IllegalArgumentException("Default key size must be positive");
-        }
-
-        if ((mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) && (mKeymasterDigest == -1)) {
-            throw new IllegalArgumentException(
-                    "Digest algorithm must be specified for HMAC key");
-        }
-    }
-
-    @Override
-    protected void engineInit(SecureRandom random) {
-        throw new UnsupportedOperationException("Cannot initialize without a "
-                + KeyGenParameterSpec.class.getName() + " parameter");
-    }
-
-    @Override
-    protected void engineInit(int keySize, SecureRandom random) {
-        throw new UnsupportedOperationException("Cannot initialize without a "
-                + KeyGenParameterSpec.class.getName() + " parameter");
-    }
-
-    @Override
-    protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
-            throws InvalidAlgorithmParameterException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            if ((params == null) || (!(params instanceof KeyGenParameterSpec))) {
-                throw new InvalidAlgorithmParameterException("Cannot initialize without a "
-                        + KeyGenParameterSpec.class.getName() + " parameter");
-            }
-            KeyGenParameterSpec spec = (KeyGenParameterSpec) params;
-            if (spec.getKeystoreAlias() == null) {
-                throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
-            }
-
-            mRng = random;
-            mSpec = spec;
-
-            mKeySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
-            if (mKeySizeBits <= 0) {
-                throw new InvalidAlgorithmParameterException(
-                        "Key size must be positive: " + mKeySizeBits);
-            } else if ((mKeySizeBits % 8) != 0) {
-                throw new InvalidAlgorithmParameterException(
-                        "Key size must be a multiple of 8: " + mKeySizeBits);
-            }
-
-            try {
-                mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
-                mKeymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
-                        spec.getEncryptionPaddings());
-                if (spec.getSignaturePaddings().length > 0) {
-                    throw new InvalidAlgorithmParameterException(
-                            "Signature paddings not supported for symmetric key algorithms");
-                }
-                mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
-                if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                        && (spec.isRandomizedEncryptionRequired())) {
-                    for (int keymasterBlockMode : mKeymasterBlockModes) {
-                        if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
-                                keymasterBlockMode)) {
-                            throw new InvalidAlgorithmParameterException(
-                                    "Randomized encryption (IND-CPA) required but may be violated"
-                                    + " by block mode: "
-                                    + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
-                                    + ". See " + KeyGenParameterSpec.class.getName()
-                                    + " documentation.");
-                        }
-                    }
-                }
-                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
-                    if (mKeySizeBits != 168) {
-                        throw new InvalidAlgorithmParameterException(
-                            "3DES key size must be 168 bits.");
-                    }
-                }
-                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
-                    if (mKeySizeBits < 64 || mKeySizeBits > 512) {
-                        throw new InvalidAlgorithmParameterException(
-                            "HMAC key sizes must be within 64-512 bits, inclusive.");
-                    }
-
-                    // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
-                    // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
-                    // one digest, we don't let algorithm parameter spec override the digest implied
-                    // by the key. If the spec specifies digests at all, it must specify only one
-                    // digest, the only implied by key algorithm.
-                    mKeymasterDigests = new int[] {mKeymasterDigest};
-                    if (spec.isDigestsSpecified()) {
-                        // Digest(s) explicitly specified in the spec. Check that the list
-                        // consists of exactly one digest, the one implied by key algorithm.
-                        int[] keymasterDigestsFromSpec =
-                                KeyProperties.Digest.allToKeymaster(spec.getDigests());
-                        if ((keymasterDigestsFromSpec.length != 1)
-                                || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
-                            throw new InvalidAlgorithmParameterException(
-                                    "Unsupported digests specification: "
-                                    + Arrays.asList(spec.getDigests()) + ". Only "
-                                    + KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
-                                    + " supported for this HMAC key algorithm");
-                        }
-                    }
-                } else {
-                    // Key algorithm does not imply a digest.
-                    if (spec.isDigestsSpecified()) {
-                        mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
-                    } else {
-                        mKeymasterDigests = EmptyArray.INT;
-                    }
-                }
-
-                // Check that user authentication related parameters are acceptable. This method
-                // will throw an IllegalStateException if there are issues (e.g., secure lock screen
-                // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
-            } catch (IllegalStateException | IllegalArgumentException e) {
-                throw new InvalidAlgorithmParameterException(e);
-            }
-
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    private void resetAll() {
-        mSpec = null;
-        mRng = null;
-        mKeySizeBits = -1;
-        mKeymasterPurposes = null;
-        mKeymasterPaddings = null;
-        mKeymasterBlockModes = null;
-    }
-
-    @Override
-    protected SecretKey engineGenerateKey() {
-        KeyGenParameterSpec spec = mSpec;
-        if (spec == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-
-        KeymasterArguments args = new KeymasterArguments();
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
-        args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
-        args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
-        args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
-        args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-        KeymasterUtils.addUserAuthArgs(args, spec);
-        KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
-                args,
-                mKeymasterAlgorithm,
-                mKeymasterBlockModes,
-                mKeymasterDigests);
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                spec.getKeyValidityForOriginationEnd());
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                spec.getKeyValidityForConsumptionEnd());
-
-        if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                && (!spec.isRandomizedEncryptionRequired())) {
-            // Permit caller-provided IV when encrypting with this key
-            args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
-        }
-
-        byte[] additionalEntropy =
-                KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
-                        mRng, (mKeySizeBits + 7) / 8);
-        int flags = 0;
-        if (spec.isStrongBoxBacked()) {
-            flags |= KeyStore.FLAG_STRONGBOX;
-        }
-        if (spec.isCriticalToDeviceEncryption()) {
-            flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
-        }
-        String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
-        KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
-        boolean success = false;
-        try {
-            Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
-            int errorCode = mKeyStore.generateKey(
-                    keyAliasInKeystore,
-                    args,
-                    additionalEntropy,
-                    spec.getUid(),
-                    flags,
-                    resultingKeyCharacteristics);
-            if (errorCode != KeyStore.NO_ERROR) {
-                if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
-                    throw new StrongBoxUnavailableException("Failed to generate key");
-                } else {
-                    throw new ProviderException(
-                            "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
-                }
-            }
-            @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
-            try {
-                keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
-                        mKeymasterAlgorithm, mKeymasterDigest);
-            } catch (IllegalArgumentException e) {
-                throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
-            }
-            SecretKey result = new AndroidKeyStoreSecretKey(
-                    keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
-            success = true;
-            return result;
-        } finally {
-            if (!success) {
-                Credentials.deleteAllTypesForAlias(
-                        mKeyStore, spec.getKeystoreAlias(), spec.getUid());
-            }
-        }
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
deleted file mode 100644
index 988838b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * Copyright (C) 2012 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.keystore;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
-import android.security.Credentials;
-import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.telephony.TelephonyManager;
-import android.util.ArraySet;
-
-import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
-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;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyPairGeneratorSpi;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Provides a way to create instances of a KeyPair which will be placed in the
- * Android keystore service usable only by the application that called it. This
- * can be used in conjunction with
- * {@link java.security.KeyStore#getInstance(String)} using the
- * {@code "AndroidKeyStore"} type.
- * <p>
- * This class can not be directly instantiated and must instead be used via the
- * {@link KeyPairGenerator#getInstance(String)
- * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
-
-    public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
-        public RSA() {
-            super(KeymasterDefs.KM_ALGORITHM_RSA);
-        }
-    }
-
-    public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
-        public EC() {
-            super(KeymasterDefs.KM_ALGORITHM_EC);
-        }
-    }
-
-    /*
-     * These must be kept in sync with system/security/keystore/defaults.h
-     */
-
-    /* EC */
-    private static final int EC_DEFAULT_KEY_SIZE = 256;
-
-    /* RSA */
-    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
-    private static final int RSA_MIN_KEY_SIZE = 512;
-    private static final int RSA_MAX_KEY_SIZE = 8192;
-
-    private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
-            new HashMap<String, Integer>();
-    private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
-    private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
-    static {
-        // Aliases for NIST P-224
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
-
-
-        // Aliases for NIST P-256
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
-
-        // Aliases for NIST P-384
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
-
-        // Aliases for NIST P-521
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
-        SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
-
-        SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
-        Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
-
-        SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
-                new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
-        Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
-    }
-
-    private final int mOriginalKeymasterAlgorithm;
-
-    private KeyStore mKeyStore;
-
-    private KeyGenParameterSpec mSpec;
-
-    private String mEntryAlias;
-    private int mEntryUid;
-    private boolean mEncryptionAtRestRequired;
-    private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
-    private int mKeymasterAlgorithm = -1;
-    private int mKeySizeBits;
-    private SecureRandom mRng;
-
-    private int[] mKeymasterPurposes;
-    private int[] mKeymasterBlockModes;
-    private int[] mKeymasterEncryptionPaddings;
-    private int[] mKeymasterSignaturePaddings;
-    private int[] mKeymasterDigests;
-
-    private BigInteger mRSAPublicExponent;
-
-    protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
-        mOriginalKeymasterAlgorithm = keymasterAlgorithm;
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public void initialize(int keysize, SecureRandom random) {
-        throw new IllegalArgumentException(
-                KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
-                + " required to initialize this KeyPairGenerator");
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
-            throws InvalidAlgorithmParameterException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            if (params == null) {
-                throw new InvalidAlgorithmParameterException(
-                        "Must supply params of type " + KeyGenParameterSpec.class.getName()
-                        + " or " + KeyPairGeneratorSpec.class.getName());
-            }
-
-            KeyGenParameterSpec spec;
-            boolean encryptionAtRestRequired = false;
-            int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
-            if (params instanceof KeyGenParameterSpec) {
-                spec = (KeyGenParameterSpec) params;
-            } else if (params instanceof KeyPairGeneratorSpec) {
-                // Legacy/deprecated spec
-                KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
-                try {
-                    KeyGenParameterSpec.Builder specBuilder;
-                    String specKeyAlgorithm = legacySpec.getKeyType();
-                    if (specKeyAlgorithm != null) {
-                        // Spec overrides the generator's default key algorithm
-                        try {
-                            keymasterAlgorithm =
-                                    KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
-                                            specKeyAlgorithm);
-                        } catch (IllegalArgumentException e) {
-                            throw new InvalidAlgorithmParameterException(
-                                    "Invalid key type in parameters", e);
-                        }
-                    }
-                    switch (keymasterAlgorithm) {
-                        case KeymasterDefs.KM_ALGORITHM_EC:
-                            specBuilder = new KeyGenParameterSpec.Builder(
-                                    legacySpec.getKeystoreAlias(),
-                                    KeyProperties.PURPOSE_SIGN
-                                    | KeyProperties.PURPOSE_VERIFY);
-                            // Authorized to be used with any digest (including no digest).
-                            // MD5 was never offered for Android Keystore for ECDSA.
-                            specBuilder.setDigests(
-                                    KeyProperties.DIGEST_NONE,
-                                    KeyProperties.DIGEST_SHA1,
-                                    KeyProperties.DIGEST_SHA224,
-                                    KeyProperties.DIGEST_SHA256,
-                                    KeyProperties.DIGEST_SHA384,
-                                    KeyProperties.DIGEST_SHA512);
-                            break;
-                        case KeymasterDefs.KM_ALGORITHM_RSA:
-                            specBuilder = new KeyGenParameterSpec.Builder(
-                                    legacySpec.getKeystoreAlias(),
-                                    KeyProperties.PURPOSE_ENCRYPT
-                                    | KeyProperties.PURPOSE_DECRYPT
-                                    | KeyProperties.PURPOSE_SIGN
-                                    | KeyProperties.PURPOSE_VERIFY);
-                            // Authorized to be used with any digest (including no digest).
-                            specBuilder.setDigests(
-                                    KeyProperties.DIGEST_NONE,
-                                    KeyProperties.DIGEST_MD5,
-                                    KeyProperties.DIGEST_SHA1,
-                                    KeyProperties.DIGEST_SHA224,
-                                    KeyProperties.DIGEST_SHA256,
-                                    KeyProperties.DIGEST_SHA384,
-                                    KeyProperties.DIGEST_SHA512);
-                            // Authorized to be used with any encryption and signature padding
-                            // schemes (including no padding).
-                            specBuilder.setEncryptionPaddings(
-                                    KeyProperties.ENCRYPTION_PADDING_NONE,
-                                    KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
-                                    KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
-                            specBuilder.setSignaturePaddings(
-                                    KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
-                                    KeyProperties.SIGNATURE_PADDING_RSA_PSS);
-                            // Disable randomized encryption requirement to support encryption
-                            // padding NONE above.
-                            specBuilder.setRandomizedEncryptionRequired(false);
-                            break;
-                        default:
-                            throw new ProviderException(
-                                    "Unsupported algorithm: " + mKeymasterAlgorithm);
-                    }
-
-                    if (legacySpec.getKeySize() != -1) {
-                        specBuilder.setKeySize(legacySpec.getKeySize());
-                    }
-                    if (legacySpec.getAlgorithmParameterSpec() != null) {
-                        specBuilder.setAlgorithmParameterSpec(
-                                legacySpec.getAlgorithmParameterSpec());
-                    }
-                    specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
-                    specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
-                    specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
-                    specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
-                    encryptionAtRestRequired = legacySpec.isEncryptionRequired();
-                    specBuilder.setUserAuthenticationRequired(false);
-
-                    spec = specBuilder.build();
-                } catch (NullPointerException | IllegalArgumentException e) {
-                    throw new InvalidAlgorithmParameterException(e);
-                }
-            } else {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported params class: " + params.getClass().getName()
-                        + ". Supported: " + KeyGenParameterSpec.class.getName()
-                        + ", " + KeyPairGeneratorSpec.class.getName());
-            }
-
-            mEntryAlias = spec.getKeystoreAlias();
-            mEntryUid = spec.getUid();
-            mSpec = spec;
-            mKeymasterAlgorithm = keymasterAlgorithm;
-            mEncryptionAtRestRequired = encryptionAtRestRequired;
-            mKeySizeBits = spec.getKeySize();
-            initAlgorithmSpecificParameters();
-            if (mKeySizeBits == -1) {
-                mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
-            }
-            checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
-
-            if (spec.getKeystoreAlias() == null) {
-                throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
-            }
-
-            String jcaKeyAlgorithm;
-            try {
-                jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
-                        keymasterAlgorithm);
-                mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
-                mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
-                mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
-                        spec.getEncryptionPaddings());
-                if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                        && (spec.isRandomizedEncryptionRequired())) {
-                    for (int keymasterPadding : mKeymasterEncryptionPaddings) {
-                        if (!KeymasterUtils
-                                .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
-                                        keymasterPadding)) {
-                            throw new InvalidAlgorithmParameterException(
-                                    "Randomized encryption (IND-CPA) required but may be violated"
-                                    + " by padding scheme: "
-                                    + KeyProperties.EncryptionPadding.fromKeymaster(
-                                            keymasterPadding)
-                                    + ". See " + KeyGenParameterSpec.class.getName()
-                                    + " documentation.");
-                        }
-                    }
-                }
-                mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
-                        spec.getSignaturePaddings());
-                if (spec.isDigestsSpecified()) {
-                    mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
-                } else {
-                    mKeymasterDigests = EmptyArray.INT;
-                }
-
-                // Check that user authentication related parameters are acceptable. This method
-                // will throw an IllegalStateException if there are issues (e.g., secure lock screen
-                // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
-            } catch (IllegalArgumentException | IllegalStateException e) {
-                throw new InvalidAlgorithmParameterException(e);
-            }
-
-            mJcaKeyAlgorithm = jcaKeyAlgorithm;
-            mRng = random;
-            mKeyStore = KeyStore.getInstance();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    private void resetAll() {
-        mEntryAlias = null;
-        mEntryUid = KeyStore.UID_SELF;
-        mJcaKeyAlgorithm = null;
-        mKeymasterAlgorithm = -1;
-        mKeymasterPurposes = null;
-        mKeymasterBlockModes = null;
-        mKeymasterEncryptionPaddings = null;
-        mKeymasterSignaturePaddings = null;
-        mKeymasterDigests = null;
-        mKeySizeBits = 0;
-        mSpec = null;
-        mRSAPublicExponent = null;
-        mEncryptionAtRestRequired = false;
-        mRng = null;
-        mKeyStore = null;
-    }
-
-    private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
-        AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
-        switch (mKeymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-            {
-                BigInteger publicExponent = null;
-                if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
-                    RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
-                    if (mKeySizeBits == -1) {
-                        mKeySizeBits = rsaSpec.getKeysize();
-                    } else if (mKeySizeBits != rsaSpec.getKeysize()) {
-                        throw new InvalidAlgorithmParameterException("RSA key size must match "
-                                + " between " + mSpec + " and " + algSpecificSpec
-                                + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
-                    }
-                    publicExponent = rsaSpec.getPublicExponent();
-                } else if (algSpecificSpec != null) {
-                    throw new InvalidAlgorithmParameterException(
-                        "RSA may only use RSAKeyGenParameterSpec");
-                }
-                if (publicExponent == null) {
-                    publicExponent = RSAKeyGenParameterSpec.F4;
-                }
-                if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
-                    throw new InvalidAlgorithmParameterException(
-                            "RSA public exponent must be positive: " + publicExponent);
-                }
-                if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
-                    throw new InvalidAlgorithmParameterException(
-                            "Unsupported RSA public exponent: " + publicExponent
-                            + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
-                }
-                mRSAPublicExponent = publicExponent;
-                break;
-            }
-            case KeymasterDefs.KM_ALGORITHM_EC:
-                if (algSpecificSpec instanceof ECGenParameterSpec) {
-                    ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
-                    String curveName = ecSpec.getName();
-                    Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
-                            curveName.toLowerCase(Locale.US));
-                    if (ecSpecKeySizeBits == null) {
-                        throw new InvalidAlgorithmParameterException(
-                                "Unsupported EC curve name: " + curveName
-                                + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
-                    }
-                    if (mKeySizeBits == -1) {
-                        mKeySizeBits = ecSpecKeySizeBits;
-                    } else if (mKeySizeBits != ecSpecKeySizeBits) {
-                        throw new InvalidAlgorithmParameterException("EC key size must match "
-                                + " between " + mSpec + " and " + algSpecificSpec
-                                + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
-                    }
-                } else if (algSpecificSpec != null) {
-                    throw new InvalidAlgorithmParameterException(
-                        "EC may only use ECGenParameterSpec");
-                }
-                break;
-            default:
-                throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
-        }
-    }
-
-    @Override
-    public KeyPair generateKeyPair() {
-        if (mKeyStore == null || mSpec == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-
-        int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
-        if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
-                && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
-            throw new IllegalStateException(
-                    "Encryption at rest using secure lock screen credential requested for key pair"
-                    + ", but the user has not yet entered the credential");
-        }
-
-        if (mSpec.isStrongBoxBacked()) {
-            flags |= KeyStore.FLAG_STRONGBOX;
-        }
-        if (mSpec.isCriticalToDeviceEncryption()) {
-            flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
-        }
-
-        byte[] additionalEntropy =
-                KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
-                        mRng, (mKeySizeBits + 7) / 8);
-
-        Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
-        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
-        boolean success = false;
-        try {
-            generateKeystoreKeyPair(
-                    privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
-            KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
-
-            storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
-
-            success = true;
-            return keyPair;
-        } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
-          if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
-              throw new SecureKeyImportUnavailableException(e);
-          } else {
-                throw new ProviderException(e);
-          }
-        } finally {
-            if (!success) {
-                Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
-            }
-        }
-    }
-
-    private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
-            throws ProviderException, DeviceIdAttestationException {
-        byte[] challenge = mSpec.getAttestationChallenge();
-        if (challenge != null) {
-            KeymasterArguments args = new KeymasterArguments();
-            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
-
-            if (mSpec.isDevicePropertiesAttestationIncluded()) {
-                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
-                        Build.BRAND.getBytes(StandardCharsets.UTF_8));
-                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
-                        Build.DEVICE.getBytes(StandardCharsets.UTF_8));
-                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
-                        Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
-                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
-                        Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
-                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
-                        Build.MODEL.getBytes(StandardCharsets.UTF_8));
-            }
-
-            int[] idTypes = mSpec.getAttestationIds();
-            if (idTypes != null) {
-                final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
-                for (int idType : idTypes) {
-                    idTypesSet.add(idType);
-                }
-                TelephonyManager telephonyService = null;
-                if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
-                        || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
-                    telephonyService =
-                            (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
-                                    Context.TELEPHONY_SERVICE);
-                    if (telephonyService == null) {
-                        throw new DeviceIdAttestationException(
-                                "Unable to access telephony service");
-                    }
-                }
-                for (final Integer idType : idTypesSet) {
-                    switch (idType) {
-                        case AttestationUtils.ID_TYPE_SERIAL:
-                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
-                                    Build.getSerial().getBytes(StandardCharsets.UTF_8)
-                            );
-                            break;
-                        case AttestationUtils.ID_TYPE_IMEI: {
-                            final String imei = telephonyService.getImei(0);
-                            if (imei == null) {
-                                throw new DeviceIdAttestationException("Unable to retrieve IMEI");
-                            }
-                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
-                                    imei.getBytes(StandardCharsets.UTF_8)
-                            );
-                            break;
-                        }
-                        case AttestationUtils.ID_TYPE_MEID: {
-                            final String meid = telephonyService.getMeid(0);
-                            if (meid == null) {
-                                throw new DeviceIdAttestationException("Unable to retrieve MEID");
-                            }
-                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
-                                    meid.getBytes(StandardCharsets.UTF_8)
-                            );
-                            break;
-                        }
-                        case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
-                            args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
-                            break;
-                        }
-                        default:
-                            throw new IllegalArgumentException("Unknown device ID type " + idType);
-                    }
-                }
-            }
-
-            return getAttestationChain(privateKeyAlias, keyPair, args);
-        }
-
-        // Very short certificate chain in the non-attestation case.
-        return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
-    }
-
-    private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
-            byte[] additionalEntropy, final int flags) throws ProviderException {
-        KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
-        int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
-                mEntryUid, flags, resultingKeyCharacteristics);
-        if (errorCode != KeyStore.NO_ERROR) {
-            if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
-                throw new StrongBoxUnavailableException("Failed to generate key pair");
-            } else {
-                throw new ProviderException(
-                        "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
-            }
-        }
-    }
-
-    private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
-        try {
-            KeyPair result  = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                    mKeyStore, privateKeyAlias, mEntryUid);
-            if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
-                throw new ProviderException(
-                        "Generated key pair algorithm does not match requested algorithm: "
-                                + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
-            }
-            return result;
-        } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
-            throw new ProviderException("Failed to load generated key pair from keystore", e);
-        }
-    }
-
-    private KeymasterArguments constructKeyGenerationArguments()
-            throws IllegalArgumentException, DeviceIdAttestationException {
-        KeymasterArguments args = new KeymasterArguments();
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
-        args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
-        args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
-        args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
-        args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
-        args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-
-        KeymasterUtils.addUserAuthArgs(args, mSpec);
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                mSpec.getKeyValidityForOriginationEnd());
-        args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                mSpec.getKeyValidityForConsumptionEnd());
-        addAlgorithmSpecificParameters(args);
-
-        if (mSpec.isUniqueIdIncluded()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
-        }
-        return args;
-    }
-
-    private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
-            throws ProviderException {
-        Iterator<byte[]> iter = iterable.iterator();
-        storeCertificate(
-                Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
-
-        if (!iter.hasNext()) {
-            return;
-        }
-
-        ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
-        while (iter.hasNext()) {
-            byte[] data = iter.next();
-            certificateConcatenationStream.write(data, 0, data.length);
-        }
-
-        storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
-                flags, "Failed to store attestation CA certificate");
-    }
-
-    private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
-            String failureMessage) throws ProviderException {
-        int insertErrorCode = mKeyStore.insert(
-                prefix + mEntryAlias,
-                certificateBytes,
-                mEntryUid,
-                flags);
-        if (insertErrorCode != KeyStore.NO_ERROR) {
-            throw new ProviderException(failureMessage,
-                    KeyStore.getKeyStoreException(insertErrorCode));
-        }
-    }
-
-    private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
-        try {
-            return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
-                    .getEncoded();
-        } catch (IOException | CertificateParsingException e) {
-            throw new ProviderException("Failed to generate self-signed certificate", e);
-        } catch (CertificateEncodingException e) {
-            throw new ProviderException(
-                    "Failed to obtain encoded form of self-signed certificate", e);
-        }
-    }
-
-    private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
-            KeyPair keyPair, KeymasterArguments args)
-                    throws ProviderException {
-        final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
-        final int errorCode;
-        if (mSpec.isDevicePropertiesAttestationIncluded()
-                && mSpec.getAttestationChallenge() == null) {
-            throw new ProviderException("An attestation challenge must be provided when requesting "
-                    + "device properties attestation.");
-        }
-        errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw new ProviderException("Failed to generate attestation certificate chain",
-                    KeyStore.getKeyStoreException(errorCode));
-        }
-        Collection<byte[]> chain = outChain.getCertificates();
-        if (chain.size() < 2) {
-            throw new ProviderException("Attestation certificate chain contained "
-                    + chain.size() + " entries. At least two are required.");
-        }
-        return chain;
-    }
-
-    private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
-        switch (mKeymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-                keymasterArgs.addUnsignedLong(
-                        KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
-                break;
-            case KeymasterDefs.KM_ALGORITHM_EC:
-                break;
-            default:
-                throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
-        }
-    }
-
-    private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
-            PublicKey publicKey) throws CertificateParsingException, IOException {
-        String signatureAlgorithm =
-                getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
-        if (signatureAlgorithm == null) {
-            // Key cannot be used to sign a certificate
-            return generateSelfSignedCertificateWithFakeSignature(publicKey);
-        } else {
-            // Key can be used to sign a certificate
-            try {
-                return generateSelfSignedCertificateWithValidSignature(
-                        privateKey, publicKey, signatureAlgorithm);
-            } catch (Exception e) {
-                // Failed to generate the self-signed certificate with valid signature. Fall back
-                // to generating a self-signed certificate with a fake signature. This is done for
-                // all exception types because we prefer key pair generation to succeed and end up
-                // producing a self-signed certificate with an invalid signature to key pair
-                // generation failing.
-                return generateSelfSignedCertificateWithFakeSignature(publicKey);
-            }
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private X509Certificate generateSelfSignedCertificateWithValidSignature(
-            PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
-        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
-        certGen.setPublicKey(publicKey);
-        certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
-        certGen.setSubjectDN(mSpec.getCertificateSubject());
-        certGen.setIssuerDN(mSpec.getCertificateSubject());
-        certGen.setNotBefore(mSpec.getCertificateNotBefore());
-        certGen.setNotAfter(mSpec.getCertificateNotAfter());
-        certGen.setSignatureAlgorithm(signatureAlgorithm);
-        return certGen.generate(privateKey);
-    }
-
-    @SuppressWarnings("deprecation")
-    private X509Certificate generateSelfSignedCertificateWithFakeSignature(
-            PublicKey publicKey) throws IOException, CertificateParsingException {
-        V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
-        ASN1ObjectIdentifier sigAlgOid;
-        AlgorithmIdentifier sigAlgId;
-        byte[] signature;
-        switch (mKeymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_EC:
-                sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
-                sigAlgId = new AlgorithmIdentifier(sigAlgOid);
-                ASN1EncodableVector v = new ASN1EncodableVector();
-                v.add(new ASN1Integer(BigInteger.valueOf(0)));
-                v.add(new ASN1Integer(BigInteger.valueOf(0)));
-                signature = new DERSequence().getEncoded();
-                break;
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-                sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
-                sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
-                signature = new byte[1];
-                break;
-            default:
-                throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
-        }
-
-        try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
-            tbsGenerator.setSubjectPublicKeyInfo(
-                    SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
-        }
-        tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
-        X509Principal subject =
-                new X509Principal(mSpec.getCertificateSubject().getEncoded());
-        tbsGenerator.setSubject(subject);
-        tbsGenerator.setIssuer(subject);
-        tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
-        tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
-        tbsGenerator.setSignature(sigAlgId);
-        TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
-
-        ASN1EncodableVector result = new ASN1EncodableVector();
-        result.add(tbsCertificate);
-        result.add(sigAlgId);
-        result.add(new DERBitString(signature));
-        return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
-    }
-
-    private static int getDefaultKeySize(int keymasterAlgorithm) {
-        switch (keymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_EC:
-                return EC_DEFAULT_KEY_SIZE;
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-                return RSA_DEFAULT_KEY_SIZE;
-            default:
-                throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
-        }
-    }
-
-    private static void checkValidKeySize(
-            int keymasterAlgorithm,
-            int keySize,
-            boolean isStrongBoxBacked)
-            throws InvalidAlgorithmParameterException {
-        switch (keymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_EC:
-                if (isStrongBoxBacked && keySize != 256) {
-                    throw new InvalidAlgorithmParameterException(
-                            "Unsupported StrongBox EC key size: "
-                            + keySize + " bits. Supported: 256");
-                }
-                if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
-                    throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
-                            + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
-                }
-                break;
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-                if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
-                    throw new InvalidAlgorithmParameterException("RSA key size must be >= "
-                            + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
-                }
-                break;
-            default:
-                throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
-        }
-    }
-
-    /**
-     * Returns the {@code Signature} algorithm to be used for signing a certificate using the
-     * specified key or {@code null} if the key cannot be used for signing a certificate.
-     */
-    @Nullable
-    private static String getCertificateSignatureAlgorithm(
-            int keymasterAlgorithm,
-            int keySizeBits,
-            KeyGenParameterSpec spec) {
-        // Constraints:
-        // 1. Key must be authorized for signing without user authentication.
-        // 2. Signature digest must be one of key's authorized digests.
-        // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
-        //    of RSA PKCS#1 signature padding scheme (about 30 bytes).
-        // 4. For EC keys, the there is no point in using a digest whose output size is longer than
-        //    key/field size because the digest will be truncated to that size.
-
-        if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
-            // Key not authorized for signing
-            return null;
-        }
-        if (spec.isUserAuthenticationRequired()) {
-            // Key not authorized for use without user authentication
-            return null;
-        }
-        if (!spec.isDigestsSpecified()) {
-            // Key not authorized for any digests -- can't sign
-            return null;
-        }
-        switch (keymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_EC:
-            {
-                Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
-                        spec.getDigests(),
-                        AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
-                int bestKeymasterDigest = -1;
-                int bestDigestOutputSizeBits = -1;
-                for (int keymasterDigest : availableKeymasterDigests) {
-                    int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
-                    if (outputSizeBits == keySizeBits) {
-                        // Perfect match -- use this digest
-                        bestKeymasterDigest = keymasterDigest;
-                        bestDigestOutputSizeBits = outputSizeBits;
-                        break;
-                    }
-                    // Not a perfect match -- check against the best digest so far
-                    if (bestKeymasterDigest == -1) {
-                        // First digest tested -- definitely the best so far
-                        bestKeymasterDigest = keymasterDigest;
-                        bestDigestOutputSizeBits = outputSizeBits;
-                    } else {
-                        // Prefer output size to be as close to key size as possible, with output
-                        // sizes larger than key size preferred to those smaller than key size.
-                        if (bestDigestOutputSizeBits < keySizeBits) {
-                            // Output size of the best digest so far is smaller than key size.
-                            // Anything larger is a win.
-                            if (outputSizeBits > bestDigestOutputSizeBits) {
-                                bestKeymasterDigest = keymasterDigest;
-                                bestDigestOutputSizeBits = outputSizeBits;
-                            }
-                        } else {
-                            // Output size of the best digest so far is larger than key size.
-                            // Anything smaller is a win, as long as it's not smaller than key size.
-                            if ((outputSizeBits < bestDigestOutputSizeBits)
-                                    && (outputSizeBits >= keySizeBits)) {
-                                bestKeymasterDigest = keymasterDigest;
-                                bestDigestOutputSizeBits = outputSizeBits;
-                            }
-                        }
-                    }
-                }
-                if (bestKeymasterDigest == -1) {
-                    return null;
-                }
-                return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
-                        bestKeymasterDigest) + "WithECDSA";
-            }
-            case KeymasterDefs.KM_ALGORITHM_RSA:
-            {
-                // Check whether this key is authorized for PKCS#1 signature padding.
-                // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
-                // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
-                // to be authorized for PKCS#1 padding or padding NONE which means any padding.
-                boolean pkcs1SignaturePaddingSupported =
-                        com.android.internal.util.ArrayUtils.contains(
-                                KeyProperties.SignaturePadding.allToKeymaster(
-                                        spec.getSignaturePaddings()),
-                                KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
-                if (!pkcs1SignaturePaddingSupported) {
-                    // Key not authorized for PKCS#1 signature padding -- can't sign
-                    return null;
-                }
-
-                Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
-                        spec.getDigests(),
-                        AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
-                // The amount of space available for the digest is less than modulus size by about
-                // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
-                // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
-                // overhead (depending the on chosen digest) for encoding digest OID and digest
-                // value in DER.
-                int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
-                int bestKeymasterDigest = -1;
-                int bestDigestOutputSizeBits = -1;
-                for (int keymasterDigest : availableKeymasterDigests) {
-                    int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
-                    if (outputSizeBits > maxDigestOutputSizeBits) {
-                        // Digest too long (signature generation will fail) -- skip
-                        continue;
-                    }
-                    if (bestKeymasterDigest == -1) {
-                        // First digest tested -- definitely the best so far
-                        bestKeymasterDigest = keymasterDigest;
-                        bestDigestOutputSizeBits = outputSizeBits;
-                    } else {
-                        // The longer the better
-                        if (outputSizeBits > bestDigestOutputSizeBits) {
-                            bestKeymasterDigest = keymasterDigest;
-                            bestDigestOutputSizeBits = outputSizeBits;
-                        }
-                    }
-                }
-                if (bestKeymasterDigest == -1) {
-                    return null;
-                }
-                return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
-                        bestKeymasterDigest) + "WithRSA";
-            }
-            default:
-                throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
-        }
-    }
-
-    private static Set<Integer> getAvailableKeymasterSignatureDigests(
-            @KeyProperties.DigestEnum String[] authorizedKeyDigests,
-            @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
-        Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
-        for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
-            authorizedKeymasterKeyDigests.add(keymasterDigest);
-        }
-        Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
-        for (int keymasterDigest
-                : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
-            supportedKeymasterSignatureDigests.add(keymasterDigest);
-        }
-        Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
-        result.retainAll(authorizedKeymasterKeyDigests);
-        return result;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
deleted file mode 100644
index 45d579e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
+++ /dev/null
@@ -1,38 +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.security.keystore;
-
-import java.security.KeyStore;
-import java.security.KeyStore.ProtectionParameter;
-
-class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
-
-    private final int mUid;
-
-    AndroidKeyStoreLoadStoreParameter(int uid) {
-        mUid = uid;
-    }
-
-    @Override
-    public ProtectionParameter getProtectionParameter() {
-        return null;
-    }
-
-    int getUid() {
-        return mUid;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
deleted file mode 100644
index 06e4c88..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
+++ /dev/null
@@ -1,31 +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.security.keystore;
-
-import java.security.PrivateKey;
-
-/**
- * {@link PrivateKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {
-
-    public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
-        super(alias, uid, algorithm);
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 0871517..ecb082e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -20,30 +20,13 @@
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
 
 import java.io.IOException;
-import java.security.KeyFactory;
-import java.security.KeyPair;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.Provider;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.Signature;
-import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.List;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -57,117 +40,10 @@
 public class AndroidKeyStoreProvider extends Provider {
     private static final String PROVIDER_NAME = "AndroidKeyStore";
 
-    // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
-    // classes when this provider is instantiated and installed early on during each app's
-    // initialization process.
-    //
-    // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider.
-    // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
-    // for details.
-
-    private static final String PACKAGE_NAME = "android.security.keystore";
-
-    private static final String DESEDE_SYSTEM_PROPERTY =
-            "ro.hardware.keystore_desede";
-
     /** @hide */
-    public AndroidKeyStoreProvider() {
-        this(PROVIDER_NAME);
-    }
-
-    /** @hide **/
-    public AndroidKeyStoreProvider(String providerName) {
-        super(providerName, 1.0, "Android KeyStore security provider");
-
-        boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
-
-        // java.security.KeyStore
-        put("KeyStore." + providerName, PACKAGE_NAME + ".AndroidKeyStoreSpi");
-
-        // java.security.KeyPairGenerator
-        put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
-        put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
-
-        // java.security.KeyFactory
-        putKeyFactoryImpl("EC");
-        putKeyFactoryImpl("RSA");
-
-        // javax.crypto.KeyGenerator
-        put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
-        put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
-        put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224");
-        put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256");
-        put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384");
-        put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512");
-
-        if (supports3DES) {
-            put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
-        }
-
-        // java.security.SecretKeyFactory
-        putSecretKeyFactoryImpl("AES");
-        if (supports3DES) {
-            putSecretKeyFactoryImpl("DESede");
-        }
-        putSecretKeyFactoryImpl("HmacSHA1");
-        putSecretKeyFactoryImpl("HmacSHA224");
-        putSecretKeyFactoryImpl("HmacSHA256");
-        putSecretKeyFactoryImpl("HmacSHA384");
-        putSecretKeyFactoryImpl("HmacSHA512");
-    }
-
-    /**
-     * 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,
-     * the platform property that indicates that Keystore 2.0 is enabled is not readable
-     * by applications. So we set this value when {@code install()} is called because it
-     * is called by zygote, which can access Keystore2Properties.
-     *
-     * This function can be removed once the transition to Keystore 2.0 is complete.
-     * b/171305684
-     *
-     * @return true if Keystore 2.0 is enabled.
-     * @hide
-     */
-    public static boolean isKeystore2Enabled() {
-        return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
-    }
-
-    /**
-     * Installs a new instance of this provider (and the
-     * {@link AndroidKeyStoreBCWorkaroundProvider}).
-     * @hide
-     */
-    public static void install() {
-        Provider[] providers = Security.getProviders();
-        int bcProviderIndex = -1;
-        for (int i = 0; i < providers.length; i++) {
-            Provider provider = providers[i];
-            if ("BC".equals(provider.getName())) {
-                bcProviderIndex = i;
-                break;
-            }
-        }
-
-        Security.addProvider(new AndroidKeyStoreProvider());
-        Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
-        if (bcProviderIndex != -1) {
-            // Bouncy Castle provider found -- install the workaround provider above it.
-            // insertProviderAt uses 1-based positions.
-            Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
-        } else {
-            // Bouncy Castle provider not found -- install the workaround provider at lowest
-            // priority.
-            Security.addProvider(workaroundProvider);
-        }
-    }
-
-    private void putSecretKeyFactoryImpl(String algorithm) {
-        put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreSecretKeyFactorySpi");
-    }
-
-    private void putKeyFactoryImpl(String algorithm) {
-        put("KeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreKeyFactorySpi");
+    public AndroidKeyStoreProvider(@NonNull String name) {
+        super(name, 1.0, "Android KeyStore security provider");
+        throw new IllegalStateException("Should not be instantiated.");
     }
 
     /**
@@ -189,229 +65,7 @@
         if (cryptoPrimitive == null) {
             throw new NullPointerException();
         }
-        Object spi;
-        if (cryptoPrimitive instanceof Signature) {
-            spi = ((Signature) cryptoPrimitive).getCurrentSpi();
-        } else if (cryptoPrimitive instanceof Mac) {
-            spi = ((Mac) cryptoPrimitive).getCurrentSpi();
-        } else if (cryptoPrimitive instanceof Cipher) {
-            spi = ((Cipher) cryptoPrimitive).getCurrentSpi();
-        } else {
-            throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive
-                    + ". Supported: Signature, Mac, Cipher");
-        }
-        if (spi == null) {
-            throw new IllegalStateException("Crypto primitive not initialized");
-        } else if (!(spi instanceof KeyStoreCryptoOperation)) {
-            throw new IllegalArgumentException(
-                    "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive
-                    + ", spi: " + spi);
-        }
-        return ((KeyStoreCryptoOperation) spi).getOperationHandle();
-    }
-
-    /** @hide **/
-    @NonNull
-    public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
-            @NonNull String alias,
-            int uid,
-            @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
-            @NonNull byte[] x509EncodedForm) {
-        PublicKey publicKey;
-        try {
-            KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
-            publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
-        } catch (NoSuchAlgorithmException e) {
-            throw new ProviderException(
-                    "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
-        } catch (InvalidKeySpecException e) {
-            throw new ProviderException("Invalid X.509 encoding of public key", e);
-        }
-        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
-        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
-        } else {
-            throw new ProviderException("Unsupported Android Keystore public key algorithm: "
-                    + keyAlgorithm);
-        }
-    }
-
-    @NonNull
-    private static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
-            @NonNull AndroidKeyStorePublicKey publicKey) {
-        String keyAlgorithm = publicKey.getAlgorithm();
-        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreECPrivateKey(
-                    publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
-        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreRSAPrivateKey(
-                    publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
-        } else {
-            throw new ProviderException("Unsupported Android Keystore public key algorithm: "
-                    + keyAlgorithm);
-        }
-    }
-
-    @NonNull
-    private static KeyCharacteristics getKeyCharacteristics(@NonNull KeyStore keyStore,
-            @NonNull String alias, int uid)
-            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode = keyStore.getKeyCharacteristics(
-                alias, null, null, uid, keyCharacteristics);
-        if (errorCode == KeyStore.KEY_PERMANENTLY_INVALIDATED) {
-            throw (KeyPermanentlyInvalidatedException)
-                new KeyPermanentlyInvalidatedException(
-                            "User changed or deleted their auth credentials",
-                            KeyStore.getKeyStoreException(errorCode));
-        }
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw (UnrecoverableKeyException)
-                    new UnrecoverableKeyException("Failed to obtain information about key")
-                            .initCause(KeyStore.getKeyStoreException(errorCode));
-        }
-        return keyCharacteristics;
-    }
-
-    @NonNull
-    private static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
-            KeyCharacteristics keyCharacteristics)
-            throws UnrecoverableKeyException {
-        ExportResult exportResult = keyStore.exportKey(
-                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
-        if (exportResult.resultCode != KeyStore.NO_ERROR) {
-            throw (UnrecoverableKeyException)
-                    new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
-                    .initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
-        }
-        final byte[] x509EncodedPublicKey = exportResult.exportData;
-
-        Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
-        if (keymasterAlgorithm == null) {
-            throw new UnrecoverableKeyException("Key algorithm unknown");
-        }
-
-        String jcaKeyAlgorithm;
-        try {
-            jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
-                    keymasterAlgorithm);
-        } catch (IllegalArgumentException e) {
-            throw (UnrecoverableKeyException)
-                    new UnrecoverableKeyException("Failed to load private key")
-                    .initCause(e);
-        }
-
-        return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
-    }
-
-    /** @hide **/
-    @NonNull
-    public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        return loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
-                getKeyCharacteristics(keyStore, privateKeyAlias, uid));
-    }
-
-    @NonNull
-    private static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
-            @NonNull KeyCharacteristics keyCharacteristics)
-            throws UnrecoverableKeyException {
-        AndroidKeyStorePublicKey publicKey =
-                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
-                        keyCharacteristics);
-        AndroidKeyStorePrivateKey privateKey =
-                AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
-        return new KeyPair(publicKey, privateKey);
-    }
-
-    /** @hide **/
-    @NonNull
-    public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        return loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
-                getKeyCharacteristics(keyStore, privateKeyAlias, uid));
-    }
-
-    @NonNull
-    private static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
-            @NonNull KeyCharacteristics keyCharacteristics)
-            throws UnrecoverableKeyException {
-        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
-                keyCharacteristics);
-        return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
-    }
-
-    /** @hide **/
-    @NonNull
-    public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
-            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, privateKeyAlias, uid,
-                getKeyCharacteristics(keyStore, privateKeyAlias, uid));
-    }
-
-    @NonNull
-    private static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
-            @NonNull String secretKeyAlias, int uid, @NonNull KeyCharacteristics keyCharacteristics)
-            throws UnrecoverableKeyException {
-        Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
-        if (keymasterAlgorithm == null) {
-            throw new UnrecoverableKeyException("Key algorithm unknown");
-        }
-
-        List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
-        int keymasterDigest;
-        if (keymasterDigests.isEmpty()) {
-            keymasterDigest = -1;
-        } else {
-            // More than one digest can be permitted for this key. Use the first one to form the
-            // JCA key algorithm name.
-            keymasterDigest = keymasterDigests.get(0);
-        }
-
-        @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
-        try {
-            keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
-                    keymasterAlgorithm, keymasterDigest);
-        } catch (IllegalArgumentException e) {
-            throw (UnrecoverableKeyException)
-                    new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
-        }
-
-        return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
-    }
-
-    /** @hide **/
-    @NonNull
-    public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
-            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException  {
-        KeyCharacteristics keyCharacteristics = getKeyCharacteristics(keyStore, userKeyAlias, uid);
-
-        Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
-        if (keymasterAlgorithm == null) {
-            throw new UnrecoverableKeyException("Key algorithm unknown");
-        }
-
-        if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC ||
-                keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES ||
-                keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
-            return loadAndroidKeyStoreSecretKeyFromKeystore(userKeyAlias, uid,
-                    keyCharacteristics);
-        } else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA ||
-                keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
-            return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, userKeyAlias, uid,
-                    keyCharacteristics);
-        } else {
-            throw new UnrecoverableKeyException("Key algorithm unknown");
-        }
+        return 0;
     }
 
     /**
@@ -434,13 +88,9 @@
     @NonNull
     public static java.security.KeyStore getKeyStoreForUid(int uid)
             throws KeyStoreException, NoSuchProviderException {
-        final java.security.KeyStore.LoadStoreParameter loadParameter;
-        if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
-            loadParameter = new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
-                    KeyProperties.legacyUidToNamespace(uid));
-        } else {
-            loadParameter = new AndroidKeyStoreLoadStoreParameter(uid);
-        }
+        final java.security.KeyStore.LoadStoreParameter loadParameter =
+                new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
+                        KeyProperties.legacyUidToNamespace(uid));
         java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
         try {
             result.load(loadParameter);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
deleted file mode 100644
index 4194780..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ /dev/null
@@ -1,71 +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.security.keystore;
-
-import java.security.PublicKey;
-import java.util.Arrays;
-
-/**
- * {@link PublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
-
-    private final byte[] mEncoded;
-
-    public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
-        super(alias, uid, algorithm);
-        mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
-    }
-
-    @Override
-    public String getFormat() {
-        return "X.509";
-    }
-
-    @Override
-    public byte[] getEncoded() {
-        return ArrayUtils.cloneIfNotEmpty(mEncoded);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + Arrays.hashCode(mEncoded);
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!super.equals(obj)) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
-        if (!Arrays.equals(mEncoded, other.mEncoded)) {
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
deleted file mode 100644
index 2ae68fa..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ /dev/null
@@ -1,515 +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.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.security.spec.MGF1ParameterSpec;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PSource;
-
-/**
- * Base class for {@link CipherSpi} providing Android KeyStore backed RSA encryption/decryption.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase {
-
-    /**
-     * Raw RSA cipher without any padding.
-     */
-    public static final class NoPadding extends AndroidKeyStoreRSACipherSpi {
-        public NoPadding() {
-            super(KeymasterDefs.KM_PAD_NONE);
-        }
-
-        @Override
-        protected boolean adjustConfigForEncryptingWithPrivateKey() {
-            // RSA encryption with no padding using private key is a way to implement raw RSA
-            // signatures which JCA does not expose via Signature. We thus have to support this.
-            setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
-            return true;
-        }
-
-        @Override
-        protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
-        @Override
-        protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
-                throws InvalidAlgorithmParameterException {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unexpected parameters: " + params + ". No parameters supported");
-            }
-        }
-
-        @Override
-        protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
-                throws InvalidAlgorithmParameterException {
-
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unexpected parameters: " + params + ". No parameters supported");
-            }
-        }
-
-        @Override
-        protected AlgorithmParameters engineGetParameters() {
-            return null;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForBegin() {
-            return 0;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForFinish() {
-            return 0;
-        }
-    }
-
-    /**
-     * RSA cipher with PKCS#1 v1.5 encryption padding.
-     */
-    public static final class PKCS1Padding extends AndroidKeyStoreRSACipherSpi {
-        public PKCS1Padding() {
-            super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
-        }
-
-        @Override
-        protected boolean adjustConfigForEncryptingWithPrivateKey() {
-            // RSA encryption with PCKS#1 padding using private key is a way to implement RSA
-            // signatures with PKCS#1 padding. We have to support this for legacy reasons.
-            setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
-            setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
-            return true;
-        }
-
-        @Override
-        protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
-        @Override
-        protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
-                throws InvalidAlgorithmParameterException {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unexpected parameters: " + params + ". No parameters supported");
-            }
-        }
-
-        @Override
-        protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
-                throws InvalidAlgorithmParameterException {
-
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unexpected parameters: " + params + ". No parameters supported");
-            }
-        }
-
-        @Override
-        protected AlgorithmParameters engineGetParameters() {
-            return null;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForBegin() {
-            return 0;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForFinish() {
-            return (isEncrypting()) ? getModulusSizeBytes() : 0;
-        }
-    }
-
-    /**
-     * RSA cipher with OAEP encryption padding. Only SHA-1 based MGF1 is supported as MGF.
-     */
-    abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
-
-        private static final String MGF_ALGORITGM_MGF1 = "MGF1";
-
-        private int mKeymasterDigest = -1;
-        private int mDigestOutputSizeBytes;
-
-        OAEPWithMGF1Padding(int keymasterDigest) {
-            super(KeymasterDefs.KM_PAD_RSA_OAEP);
-            mKeymasterDigest = keymasterDigest;
-            mDigestOutputSizeBytes =
-                    (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
-        }
-
-        @Override
-        protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
-        @Override
-        protected final void initAlgorithmSpecificParameters(
-                @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException {
-            if (params == null) {
-                return;
-            }
-
-            if (!(params instanceof OAEPParameterSpec)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported parameter spec: " + params
-                        + ". Only OAEPParameterSpec supported");
-            }
-            OAEPParameterSpec spec = (OAEPParameterSpec) params;
-            if (!MGF_ALGORITGM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported MGF: " + spec.getMGFAlgorithm()
-                        + ". Only " + MGF_ALGORITGM_MGF1 + " supported");
-            }
-            String jcaDigest = spec.getDigestAlgorithm();
-            int keymasterDigest;
-            try {
-                keymasterDigest = KeyProperties.Digest.toKeymaster(jcaDigest);
-            } catch (IllegalArgumentException e) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported digest: " + jcaDigest, e);
-            }
-            switch (keymasterDigest) {
-                case KeymasterDefs.KM_DIGEST_SHA1:
-                case KeymasterDefs.KM_DIGEST_SHA_2_224:
-                case KeymasterDefs.KM_DIGEST_SHA_2_256:
-                case KeymasterDefs.KM_DIGEST_SHA_2_384:
-                case KeymasterDefs.KM_DIGEST_SHA_2_512:
-                    // Permitted.
-                    break;
-                default:
-                    throw new InvalidAlgorithmParameterException(
-                            "Unsupported digest: " + jcaDigest);
-            }
-            AlgorithmParameterSpec mgfParams = spec.getMGFParameters();
-            if (mgfParams == null) {
-                throw new InvalidAlgorithmParameterException("MGF parameters must be provided");
-            }
-            // Check whether MGF parameters match the OAEPParameterSpec
-            if (!(mgfParams instanceof MGF1ParameterSpec)) {
-                throw new InvalidAlgorithmParameterException("Unsupported MGF parameters"
-                        + ": " + mgfParams + ". Only MGF1ParameterSpec supported");
-            }
-            MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) mgfParams;
-            String mgf1JcaDigest = mgfSpec.getDigestAlgorithm();
-            if (!KeyProperties.DIGEST_SHA1.equalsIgnoreCase(mgf1JcaDigest)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported MGF1 digest: " + mgf1JcaDigest
-                        + ". Only " + KeyProperties.DIGEST_SHA1 + " supported");
-            }
-            PSource pSource = spec.getPSource();
-            if (!(pSource instanceof PSource.PSpecified)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported source of encoding input P: " + pSource
-                        + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
-            }
-            PSource.PSpecified pSourceSpecified = (PSource.PSpecified) pSource;
-            byte[] pSourceValue = pSourceSpecified.getValue();
-            if ((pSourceValue != null) && (pSourceValue.length > 0)) {
-                throw new InvalidAlgorithmParameterException(
-                        "Unsupported source of encoding input P: " + pSource
-                        + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
-            }
-            mKeymasterDigest = keymasterDigest;
-            mDigestOutputSizeBytes =
-                    (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
-        }
-
-        @Override
-        protected final void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
-                throws InvalidAlgorithmParameterException {
-            if (params == null) {
-                return;
-            }
-
-            OAEPParameterSpec spec;
-            try {
-                spec = params.getParameterSpec(OAEPParameterSpec.class);
-            } catch (InvalidParameterSpecException e) {
-                throw new InvalidAlgorithmParameterException("OAEP parameters required"
-                        + ", but not found in parameters: " + params, e);
-            }
-            if (spec == null) {
-                throw new InvalidAlgorithmParameterException("OAEP parameters required"
-                        + ", but not provided in parameters: " + params);
-            }
-            initAlgorithmSpecificParameters(spec);
-        }
-
-        @Override
-        protected final AlgorithmParameters engineGetParameters() {
-            OAEPParameterSpec spec =
-                    new OAEPParameterSpec(
-                            KeyProperties.Digest.fromKeymaster(mKeymasterDigest),
-                            MGF_ALGORITGM_MGF1,
-                            MGF1ParameterSpec.SHA1,
-                            PSource.PSpecified.DEFAULT);
-            try {
-                AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
-                params.init(spec);
-                return params;
-            } catch (NoSuchAlgorithmException e) {
-                throw new ProviderException(
-                        "Failed to obtain OAEP AlgorithmParameters", e);
-            } catch (InvalidParameterSpecException e) {
-                throw new ProviderException(
-                        "Failed to initialize OAEP AlgorithmParameters with an IV",
-                        e);
-            }
-        }
-
-        @Override
-        protected final void addAlgorithmSpecificParametersToBegin(
-                KeymasterArguments keymasterArgs) {
-            super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
-            keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-        }
-
-        @Override
-        protected final void loadAlgorithmSpecificParametersFromBeginResult(
-                @NonNull KeymasterArguments keymasterArgs) {
-            super.loadAlgorithmSpecificParametersFromBeginResult(keymasterArgs);
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForBegin() {
-            return 0;
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForFinish() {
-            return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
-        }
-    }
-
-    public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding {
-        public OAEPWithSHA1AndMGF1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public static class OAEPWithSHA224AndMGF1Padding extends OAEPWithMGF1Padding {
-        public OAEPWithSHA224AndMGF1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public static class OAEPWithSHA256AndMGF1Padding extends OAEPWithMGF1Padding {
-        public OAEPWithSHA256AndMGF1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public static class OAEPWithSHA384AndMGF1Padding extends OAEPWithMGF1Padding {
-        public OAEPWithSHA384AndMGF1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public static class OAEPWithSHA512AndMGF1Padding extends OAEPWithMGF1Padding {
-        public OAEPWithSHA512AndMGF1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    private final int mKeymasterPadding;
-    private int mKeymasterPaddingOverride;
-
-    private int mModulusSizeBytes = -1;
-
-    AndroidKeyStoreRSACipherSpi(int keymasterPadding) {
-        mKeymasterPadding = keymasterPadding;
-    }
-
-    @Override
-    protected final void initKey(int opmode, Key key) throws InvalidKeyException {
-        if (key == null) {
-            throw new InvalidKeyException("Unsupported key: null");
-        }
-        if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
-                    + ". Only " + KeyProperties.KEY_ALGORITHM_RSA + " supported");
-        }
-        AndroidKeyStoreKey keystoreKey;
-        if (key instanceof AndroidKeyStorePrivateKey) {
-            keystoreKey = (AndroidKeyStoreKey) key;
-        } else if (key instanceof AndroidKeyStorePublicKey) {
-            keystoreKey = (AndroidKeyStoreKey) key;
-        } else {
-            throw new InvalidKeyException("Unsupported key type: " + key);
-        }
-
-        if (keystoreKey instanceof PrivateKey) {
-            // Private key
-            switch (opmode) {
-                case Cipher.DECRYPT_MODE:
-                case Cipher.UNWRAP_MODE:
-                    // Permitted
-                    break;
-                case Cipher.ENCRYPT_MODE:
-                case Cipher.WRAP_MODE:
-                    if (!adjustConfigForEncryptingWithPrivateKey()) {
-                        throw new InvalidKeyException(
-                                "RSA private keys cannot be used with " + opmodeToString(opmode)
-                                + " and padding "
-                                + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
-                                + ". Only RSA public keys supported for this mode");
-                    }
-                    break;
-                default:
-                    throw new InvalidKeyException(
-                            "RSA private keys cannot be used with opmode: " + opmode);
-            }
-        } else {
-            // Public key
-            switch (opmode) {
-                case Cipher.ENCRYPT_MODE:
-                case Cipher.WRAP_MODE:
-                    // Permitted
-                    break;
-                case Cipher.DECRYPT_MODE:
-                case Cipher.UNWRAP_MODE:
-                    throw new InvalidKeyException(
-                            "RSA public keys cannot be used with " + opmodeToString(opmode)
-                            + " and padding "
-                            + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
-                            + ". Only RSA private keys supported for this opmode.");
-                    // break;
-                default:
-                    throw new InvalidKeyException(
-                            "RSA public keys cannot be used with " + opmodeToString(opmode));
-            }
-        }
-
-        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode = getKeyStore().getKeyCharacteristics(
-                keystoreKey.getAlias(), null, null, keystoreKey.getUid(), keyCharacteristics);
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(
-                    keystoreKey.getAlias(), keystoreKey.getUid(), errorCode);
-        }
-        long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
-        if (keySizeBits == -1) {
-            throw new InvalidKeyException("Size of key not known");
-        } else if (keySizeBits > Integer.MAX_VALUE) {
-            throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
-        }
-        mModulusSizeBytes = (int) ((keySizeBits + 7) / 8);
-
-        setKey(keystoreKey);
-    }
-
-    /**
-     * Adjusts the configuration of this cipher for encrypting using the private key.
-     *
-     * <p>The default implementation does nothing and refuses to adjust the configuration.
-     *
-     * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
-     *         using private key is not permitted for this cipher.
-     */
-    protected boolean adjustConfigForEncryptingWithPrivateKey() {
-        return false;
-    }
-
-    @Override
-    protected final void resetAll() {
-        mModulusSizeBytes = -1;
-        mKeymasterPaddingOverride = -1;
-        super.resetAll();
-    }
-
-    @Override
-    protected final void resetWhilePreservingInitState() {
-        super.resetWhilePreservingInitState();
-    }
-
-    @Override
-    protected void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs) {
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        int keymasterPadding = getKeymasterPaddingOverride();
-        if (keymasterPadding == -1) {
-            keymasterPadding = mKeymasterPadding;
-        }
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
-        int purposeOverride = getKeymasterPurposeOverride();
-        if ((purposeOverride != -1)
-                && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
-                || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) {
-            // Keymaster sign/verify requires digest to be specified. For raw sign/verify it's NONE.
-            keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
-        }
-    }
-
-    @Override
-    protected void loadAlgorithmSpecificParametersFromBeginResult(
-            @NonNull KeymasterArguments keymasterArgs) {
-    }
-
-    @Override
-    protected final int engineGetBlockSize() {
-        // Not a block cipher, according to the RI
-        return 0;
-    }
-
-    @Override
-    protected final byte[] engineGetIV() {
-        // IV never used
-        return null;
-    }
-
-    @Override
-    protected final int engineGetOutputSize(int inputLen) {
-        return getModulusSizeBytes();
-    }
-
-    protected final int getModulusSizeBytes() {
-        if (mModulusSizeBytes == -1) {
-            throw new IllegalStateException("Not initialized");
-        }
-        return mModulusSizeBytes;
-    }
-
-    /**
-     * Overrides the default padding of the crypto operation.
-     */
-    protected final void setKeymasterPaddingOverride(int keymasterPadding) {
-        mKeymasterPaddingOverride = keymasterPadding;
-    }
-
-    protected final int getKeymasterPaddingOverride() {
-        return mKeymasterPaddingOverride;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
deleted file mode 100644
index adb3922..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ /dev/null
@@ -1,41 +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.security.keystore;
-
-import java.math.BigInteger;
-import java.security.PrivateKey;
-import java.security.interfaces.RSAKey;
-
-/**
- * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
-
-    private final BigInteger mModulus;
-
-    public AndroidKeyStoreRSAPrivateKey(String alias, int uid, BigInteger modulus) {
-        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA);
-        mModulus = modulus;
-    }
-
-    @Override
-    public BigInteger getModulus() {
-        return mModulus;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
deleted file mode 100644
index d85aace..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ /dev/null
@@ -1,55 +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.security.keystore;
-
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
-
-/**
- * {@link RSAPublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implements RSAPublicKey {
-    private final BigInteger mModulus;
-    private final BigInteger mPublicExponent;
-
-    public AndroidKeyStoreRSAPublicKey(String alias, int uid, byte[] x509EncodedForm, BigInteger modulus,
-            BigInteger publicExponent) {
-        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
-        mModulus = modulus;
-        mPublicExponent = publicExponent;
-    }
-
-    public AndroidKeyStoreRSAPublicKey(String alias, int uid, RSAPublicKey info) {
-        this(alias, uid, info.getEncoded(), info.getModulus(), info.getPublicExponent());
-        if (!"X.509".equalsIgnoreCase(info.getFormat())) {
-            throw new IllegalArgumentException(
-                    "Unsupported key export format: " + info.getFormat());
-        }
-    }
-
-    @Override
-    public BigInteger getModulus() {
-        return mModulus;
-    }
-
-    @Override
-    public BigInteger getPublicExponent() {
-        return mPublicExponent;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
deleted file mode 100644
index ecfc97e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
+++ /dev/null
@@ -1,164 +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.security.keystore;
-
-import android.annotation.NonNull;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed RSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
-    abstract static class PKCS1Padding extends AndroidKeyStoreRSASignatureSpi {
-        PKCS1Padding(int keymasterDigest) {
-            super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForSign() {
-            // No entropy required for this deterministic signature scheme.
-            return 0;
-        }
-    }
-
-    public static final class NONEWithPKCS1Padding extends PKCS1Padding {
-        public NONEWithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_NONE);
-        }
-    }
-
-    public static final class MD5WithPKCS1Padding extends PKCS1Padding {
-        public MD5WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_MD5);
-        }
-    }
-
-    public static final class SHA1WithPKCS1Padding extends PKCS1Padding {
-        public SHA1WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public static final class SHA224WithPKCS1Padding extends PKCS1Padding {
-        public SHA224WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public static final class SHA256WithPKCS1Padding extends PKCS1Padding {
-        public SHA256WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public static final class SHA384WithPKCS1Padding extends PKCS1Padding {
-        public SHA384WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public static final class SHA512WithPKCS1Padding extends PKCS1Padding {
-        public SHA512WithPKCS1Padding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    abstract static class PSSPadding extends AndroidKeyStoreRSASignatureSpi {
-        private static final int SALT_LENGTH_BYTES = 20;
-
-        PSSPadding(int keymasterDigest) {
-            super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PSS);
-        }
-
-        @Override
-        protected final int getAdditionalEntropyAmountForSign() {
-            return SALT_LENGTH_BYTES;
-        }
-    }
-
-    public static final class SHA1WithPSSPadding extends PSSPadding {
-        public SHA1WithPSSPadding() {
-            super(KeymasterDefs.KM_DIGEST_SHA1);
-        }
-    }
-
-    public static final class SHA224WithPSSPadding extends PSSPadding {
-        public SHA224WithPSSPadding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
-        }
-    }
-
-    public static final class SHA256WithPSSPadding extends PSSPadding {
-        public SHA256WithPSSPadding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
-        }
-    }
-
-    public static final class SHA384WithPSSPadding extends PSSPadding {
-        public SHA384WithPSSPadding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
-        }
-    }
-
-    public static final class SHA512WithPSSPadding extends PSSPadding {
-        public SHA512WithPSSPadding() {
-            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
-        }
-    }
-
-    private final int mKeymasterDigest;
-    private final int mKeymasterPadding;
-
-    AndroidKeyStoreRSASignatureSpi(int keymasterDigest, int keymasterPadding) {
-        mKeymasterDigest = keymasterDigest;
-        mKeymasterPadding = keymasterPadding;
-    }
-
-    @Override
-    protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
-        if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
-                    + ". Only" + KeyProperties.KEY_ALGORITHM_RSA + " supported");
-        }
-        super.initKey(key);
-    }
-
-    @Override
-    protected final void resetAll() {
-        super.resetAll();
-    }
-
-    @Override
-    protected final void resetWhilePreservingInitState() {
-        super.resetWhilePreservingInitState();
-    }
-
-    @Override
-    protected final void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs) {
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
deleted file mode 100644
index b8e6af7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ /dev/null
@@ -1,31 +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.security.keystore;
-
-import javax.crypto.SecretKey;
-
-/**
- * {@link SecretKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKey extends AndroidKeyStoreKey implements SecretKey {
-
-    public AndroidKeyStoreSecretKey(String alias, int uid, String algorithm) {
-        super(alias, uid, algorithm);
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
deleted file mode 100644
index d2678c7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ /dev/null
@@ -1,248 +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.security.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
-
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.ProviderException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactorySpi;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * {@link SecretKeyFactorySpi} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
-
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-
-    @Override
-    protected KeySpec engineGetKeySpec(SecretKey key,
-            @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
-        if (keySpecClass == null) {
-            throw new InvalidKeySpecException("keySpecClass == null");
-        }
-        if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
-                    ((key != null) ? key.getClass().getName() : "null"));
-        }
-        if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
-            throw new InvalidKeySpecException(
-                    "Key material export of Android KeyStore keys is not supported");
-        }
-        if (!KeyInfo.class.equals(keySpecClass)) {
-            throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
-        }
-        AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
-        String keyAliasInKeystore = keystoreKey.getAlias();
-        String entryAlias;
-        if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
-            entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
-        } else if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)){
-            // key has legacy prefix
-            entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
-        } else {
-            throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
-        }
-
-        return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
-    }
-
-    static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
-            int keyUid) {
-        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode = keyStore.getKeyCharacteristics(
-                keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw new ProviderException("Failed to obtain information about key."
-                    + " Keystore error: " + errorCode);
-        }
-
-        boolean insideSecureHardware;
-        @KeyProperties.OriginEnum int origin;
-        int keySize;
-        @KeyProperties.PurposeEnum int purposes;
-        String[] encryptionPaddings;
-        String[] signaturePaddings;
-        @KeyProperties.DigestEnum String[] digests;
-        @KeyProperties.BlockModeEnum String[] blockModes;
-        int keymasterSwEnforcedUserAuthenticators;
-        int keymasterHwEnforcedUserAuthenticators;
-        List<BigInteger> keymasterSecureUserIds;
-        try {
-            if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
-                insideSecureHardware = true;
-                origin = KeyProperties.Origin.fromKeymaster(
-                        keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
-            } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
-                insideSecureHardware = false;
-                origin = KeyProperties.Origin.fromKeymaster(
-                        keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
-            } else {
-                throw new ProviderException("Key origin not available");
-            }
-            long keySizeUnsigned =
-                    keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
-            if (keySizeUnsigned == -1) {
-                throw new ProviderException("Key size not available");
-            } else if (keySizeUnsigned > Integer.MAX_VALUE) {
-                throw new ProviderException("Key too large: " + keySizeUnsigned + " bits");
-            }
-            keySize = (int) keySizeUnsigned;
-            purposes = KeyProperties.Purpose.allFromKeymaster(
-                    keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE));
-
-            List<String> encryptionPaddingsList = new ArrayList<String>();
-            List<String> signaturePaddingsList = new ArrayList<String>();
-            // Keymaster stores both types of paddings in the same array -- we split it into two.
-            for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) {
-                try {
-                    @KeyProperties.EncryptionPaddingEnum String jcaPadding =
-                            KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
-                    encryptionPaddingsList.add(jcaPadding);
-                } catch (IllegalArgumentException e) {
-                    try {
-                        @KeyProperties.SignaturePaddingEnum String padding =
-                                KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
-                        signaturePaddingsList.add(padding);
-                    } catch (IllegalArgumentException e2) {
-                        throw new ProviderException(
-                                "Unsupported encryption padding: " + keymasterPadding);
-                    }
-                }
-
-            }
-            encryptionPaddings =
-                    encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
-            signaturePaddings =
-                    signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
-
-            digests = KeyProperties.Digest.allFromKeymaster(
-                    keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST));
-            blockModes = KeyProperties.BlockMode.allFromKeymaster(
-                    keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE));
-            keymasterSwEnforcedUserAuthenticators =
-                    keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            keymasterHwEnforcedUserAuthenticators =
-                    keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            keymasterSecureUserIds =
-                keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
-        } catch (IllegalArgumentException e) {
-            throw new ProviderException("Unsupported key characteristic", e);
-        }
-
-        Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
-        Date keyValidityForOriginationEnd =
-                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
-        Date keyValidityForConsumptionEnd =
-                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
-        boolean userAuthenticationRequired =
-                !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        long userAuthenticationValidityDurationSeconds =
-                keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, 0);
-        if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
-            throw new ProviderException("User authentication timeout validity too long: "
-                    + userAuthenticationValidityDurationSeconds + " seconds");
-        }
-        boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
-                && (keymasterHwEnforcedUserAuthenticators != 0)
-                && (keymasterSwEnforcedUserAuthenticators == 0);
-        boolean userAuthenticationValidWhileOnBody =
-                keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
-        boolean trustedUserPresenceRequired =
-                keyCharacteristics.hwEnforced.getBoolean(
-                    KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
-
-        boolean invalidatedByBiometricEnrollment = false;
-        if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC
-            || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) {
-            // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
-            invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
-                    && !keymasterSecureUserIds.isEmpty()
-                    && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
-        }
-
-        boolean userConfirmationRequired = keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
-
-        return new KeyInfo(entryAlias,
-                insideSecureHardware,
-                origin,
-                keySize,
-                keyValidityStart,
-                keyValidityForOriginationEnd,
-                keyValidityForConsumptionEnd,
-                purposes,
-                encryptionPaddings,
-                signaturePaddings,
-                digests,
-                blockModes,
-                userAuthenticationRequired,
-                (int) userAuthenticationValidityDurationSeconds,
-                keymasterHwEnforcedUserAuthenticators,
-                userAuthenticationRequirementEnforcedBySecureHardware,
-                userAuthenticationValidWhileOnBody,
-                trustedUserPresenceRequired,
-                invalidatedByBiometricEnrollment,
-                userConfirmationRequired,
-                // 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.UNRESTRICTED_USAGE_COUNT);
-    }
-
-    private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
-    	try {
-    		return BigInteger.valueOf(GateKeeper.getSecureUserId());
-    	} catch (IllegalStateException e) {
-    		throw new ProviderException("Failed to get GateKeeper secure user ID", e);
-    	}
-    }
-
-    @Override
-    protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
-        throw new InvalidKeySpecException(
-                "To generate secret key in Android Keystore, use KeyGenerator initialized with "
-                        + KeyGenParameterSpec.class.getName());
-    }
-
-    @Override
-    protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
-        if (key == null) {
-            throw new InvalidKeyException("key == null");
-        } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeyException(
-                    "To import a secret key into Android Keystore, use KeyStore.setEntry");
-        }
-
-        return key;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
deleted file mode 100644
index da47b6b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ /dev/null
@@ -1,431 +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.security.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.SignatureException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
-        implements KeyStoreCryptoOperation {
-    private final KeyStore mKeyStore;
-
-    // Fields below are populated by SignatureSpi.engineInitSign/engineInitVerify and KeyStore.begin
-    // and should be preserved after SignatureSpi.engineSign/engineVerify finishes.
-    private boolean mSigning;
-    private AndroidKeyStoreKey mKey;
-
-    /**
-     * Token referencing this operation inside keystore service. It is initialized by
-     * {@code engineInitSign}/{@code engineInitVerify} and is invalidated when
-     * {@code engineSign}/{@code engineVerify} succeeds and on some error conditions in between.
-     */
-    private IBinder mOperationToken;
-    private long mOperationHandle;
-    private KeyStoreCryptoOperationStreamer mMessageStreamer;
-
-    /**
-     * Encountered exception which could not be immediately thrown because it was encountered inside
-     * a method that does not throw checked exception. This exception will be thrown from
-     * {@code engineSign} or {@code engineVerify}. Once such an exception is encountered,
-     * {@code engineUpdate} starts ignoring input data.
-     */
-    private Exception mCachedException;
-
-    AndroidKeyStoreSignatureSpiBase() {
-        mKeyStore = KeyStore.getInstance();
-    }
-
-    @Override
-    protected final void engineInitSign(PrivateKey key) throws InvalidKeyException {
-        engineInitSign(key, null);
-    }
-
-    @Override
-    protected final void engineInitSign(PrivateKey privateKey, SecureRandom random)
-            throws InvalidKeyException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            if (privateKey == null) {
-                throw new InvalidKeyException("Unsupported key: null");
-            }
-            AndroidKeyStoreKey keystoreKey;
-            if (privateKey instanceof AndroidKeyStorePrivateKey) {
-                keystoreKey = (AndroidKeyStoreKey) privateKey;
-            } else {
-                throw new InvalidKeyException("Unsupported private key type: " + privateKey);
-            }
-            mSigning = true;
-            initKey(keystoreKey);
-            appRandom = random;
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    @Override
-    protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
-        resetAll();
-
-        boolean success = false;
-        try {
-            if (publicKey == null) {
-                throw new InvalidKeyException("Unsupported key: null");
-            }
-            AndroidKeyStoreKey keystoreKey;
-            if (publicKey instanceof AndroidKeyStorePublicKey) {
-                keystoreKey = (AndroidKeyStorePublicKey) publicKey;
-            } else {
-                throw new InvalidKeyException("Unsupported public key type: " + publicKey);
-            }
-            mSigning = false;
-            initKey(keystoreKey);
-            appRandom = null;
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
-        }
-    }
-
-    /**
-     * Configures this signature instance to use the provided key.
-     *
-     * @throws InvalidKeyException if the {@code key} is not suitable.
-     */
-    @CallSuper
-    protected void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
-        mKey = key;
-    }
-
-    /**
-     * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
-     * cipher instance.
-     *
-     * <p>Subclasses storing additional state should override this method, reset the additional
-     * state, and then chain to superclass.
-     */
-    @CallSuper
-    protected void resetAll() {
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mOperationToken = null;
-            mKeyStore.abort(operationToken);
-        }
-        mSigning = false;
-        mKey = null;
-        appRandom = null;
-        mOperationToken = null;
-        mOperationHandle = 0;
-        mMessageStreamer = null;
-        mCachedException = null;
-    }
-
-    /**
-     * Resets this cipher while preserving the initialized state. This must be equivalent to
-     * rolling back the cipher's state to just after the most recent {@code engineInit} completed
-     * successfully.
-     *
-     * <p>Subclasses storing additional post-init state should override this method, reset the
-     * additional state, and then chain to superclass.
-     */
-    @CallSuper
-    protected void resetWhilePreservingInitState() {
-        IBinder operationToken = mOperationToken;
-        if (operationToken != null) {
-            mOperationToken = null;
-            mKeyStore.abort(operationToken);
-        }
-        mOperationHandle = 0;
-        mMessageStreamer = null;
-        mCachedException = null;
-    }
-
-    private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
-        if (mMessageStreamer != null) {
-            return;
-        }
-        if (mCachedException != null) {
-            return;
-        }
-        if (mKey == null) {
-            throw new IllegalStateException("Not initialized");
-        }
-
-        KeymasterArguments keymasterInputArgs = new KeymasterArguments();
-        addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
-
-        OperationResult opResult = mKeyStore.begin(
-                mKey.getAlias(),
-                mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
-                true, // permit aborting this operation if keystore runs out of resources
-                keymasterInputArgs,
-                null, // no additional entropy for begin -- only finish might need some
-                mKey.getUid());
-        if (opResult == null) {
-            throw new KeyStoreConnectException();
-        }
-
-        // Store operation token and handle regardless of the error code returned by KeyStore to
-        // ensure that the operation gets aborted immediately if the code below throws an exception.
-        mOperationToken = opResult.token;
-        mOperationHandle = opResult.operationHandle;
-
-        // If necessary, throw an exception due to KeyStore operation having failed.
-        InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
-                mKeyStore, mKey, opResult.resultCode);
-        if (e != null) {
-            throw e;
-        }
-
-        if (mOperationToken == null) {
-            throw new ProviderException("Keystore returned null operation token");
-        }
-        if (mOperationHandle == 0) {
-            throw new ProviderException("Keystore returned invalid operation handle");
-        }
-
-        mMessageStreamer = createMainDataStreamer(mKeyStore, opResult.token);
-    }
-
-    /**
-     * Creates a streamer which sends the message to be signed/verified into the provided KeyStore
-     *
-     * <p>This implementation returns a working streamer.
-     */
-    @NonNull
-    protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
-            KeyStore keyStore, IBinder operationToken) {
-        return new KeyStoreCryptoOperationChunkedStreamer(
-                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                        keyStore, operationToken));
-    }
-
-    @Override
-    public final long getOperationHandle() {
-        return mOperationHandle;
-    }
-
-    @Override
-    protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
-        if (mCachedException != null) {
-            throw new SignatureException(mCachedException);
-        }
-
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException e) {
-            throw new SignatureException(e);
-        }
-
-        if (len == 0) {
-            return;
-        }
-
-        byte[] output;
-        try {
-            output = mMessageStreamer.update(b, off, len);
-        } catch (KeyStoreException e) {
-            throw new SignatureException(e);
-        }
-
-        if (output.length != 0) {
-            throw new ProviderException(
-                    "Update operation unexpectedly produced output: " + output.length + " bytes");
-        }
-    }
-
-    @Override
-    protected final void engineUpdate(byte b) throws SignatureException {
-        engineUpdate(new byte[] {b}, 0, 1);
-    }
-
-    @Override
-    protected final void engineUpdate(ByteBuffer input) {
-        byte[] b;
-        int off;
-        int len = input.remaining();
-        if (input.hasArray()) {
-            b = input.array();
-            off = input.arrayOffset() + input.position();
-            input.position(input.limit());
-        } else {
-            b = new byte[len];
-            off = 0;
-            input.get(b);
-        }
-
-        try {
-            engineUpdate(b, off, len);
-        } catch (SignatureException e) {
-            mCachedException = e;
-        }
-    }
-
-    @Override
-    protected final int engineSign(byte[] out, int outOffset, int outLen)
-            throws SignatureException {
-        return super.engineSign(out, outOffset, outLen);
-    }
-
-    @Override
-    protected final byte[] engineSign() throws SignatureException {
-        if (mCachedException != null) {
-            throw new SignatureException(mCachedException);
-        }
-
-        byte[] signature;
-        try {
-            ensureKeystoreOperationInitialized();
-
-            byte[] additionalEntropy =
-                    KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
-                            appRandom, getAdditionalEntropyAmountForSign());
-            signature = mMessageStreamer.doFinal(
-                    EmptyArray.BYTE, 0, 0,
-                    null, // no signature provided -- it'll be generated by this invocation
-                    additionalEntropy);
-        } catch (InvalidKeyException | KeyStoreException e) {
-            throw new SignatureException(e);
-        }
-
-        resetWhilePreservingInitState();
-        return signature;
-    }
-
-    @Override
-    protected final boolean engineVerify(byte[] signature) throws SignatureException {
-        if (mCachedException != null) {
-            throw new SignatureException(mCachedException);
-        }
-
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException e) {
-            throw new SignatureException(e);
-        }
-
-        boolean verified;
-        try {
-            byte[] output = mMessageStreamer.doFinal(
-                    EmptyArray.BYTE, 0, 0,
-                    signature,
-                    null // no additional entropy needed -- verification is deterministic
-                    );
-            if (output.length != 0) {
-                throw new ProviderException(
-                        "Signature verification unexpected produced output: " + output.length
-                        + " bytes");
-            }
-            verified = true;
-        } catch (KeyStoreException e) {
-            switch (e.getErrorCode()) {
-                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
-                    verified = false;
-                    break;
-                default:
-                    throw new SignatureException(e);
-            }
-        }
-
-        resetWhilePreservingInitState();
-        return verified;
-    }
-
-    @Override
-    protected final boolean engineVerify(byte[] sigBytes, int offset, int len)
-            throws SignatureException {
-        return engineVerify(ArrayUtils.subarray(sigBytes, offset, len));
-    }
-
-    @Deprecated
-    @Override
-    protected final Object engineGetParameter(String param) throws InvalidParameterException {
-        throw new InvalidParameterException();
-    }
-
-    @Deprecated
-    @Override
-    protected final void engineSetParameter(String param, Object value)
-            throws InvalidParameterException {
-        throw new InvalidParameterException();
-    }
-
-    protected final KeyStore getKeyStore() {
-        return mKeyStore;
-    }
-
-    /**
-     * Returns {@code true} if this signature is initialized for signing, {@code false} if this
-     * signature is initialized for verification.
-     */
-    protected final boolean isSigning() {
-        return mSigning;
-    }
-
-    // The methods below need to be implemented by subclasses.
-
-    /**
-     * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
-     * {@code finish} operation when generating a signature.
-     *
-     * <p>This value should match (or exceed) the amount of Shannon entropy of the produced
-     * signature assuming the key and the message are known. For example, for ECDSA signature this
-     * should be the size of {@code R}, whereas for the RSA signature with PKCS#1 padding this
-     * should be {@code 0}.
-     */
-    protected abstract int getAdditionalEntropyAmountForSign();
-
-    /**
-     * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
-     *
-     * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
-     *        parameters.
-     */
-    protected abstract void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
deleted file mode 100644
index 51c4252..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Copyright (C) 2012 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.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.KeyStoreParameter;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
-import android.security.keystore.SecureKeyImportUnavailableException;
-import android.security.keystore.WrappedKeyEntry;
-import android.util.Log;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.Key;
-import java.security.KeyStore.Entry;
-import java.security.KeyStore.LoadStoreParameter;
-import java.security.KeyStore.PrivateKeyEntry;
-import java.security.KeyStore.ProtectionParameter;
-import java.security.KeyStore.SecretKeyEntry;
-import java.security.KeyStoreException;
-import java.security.KeyStoreSpi;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.crypto.SecretKey;
-
-/**
- * A java.security.KeyStore interface for the Android KeyStore. An instance of
- * it can be created via the {@link java.security.KeyStore#getInstance(String)
- * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
- * java.security.KeyStore backed by this "AndroidKeyStore" implementation.
- * <p>
- * This is built on top of Android's keystore daemon. The convention of alias
- * use is:
- * <p>
- * PrivateKeyEntry will have a Credentials.USER_PRIVATE_KEY as the private key,
- * Credentials.USER_CERTIFICATE as the first certificate in the chain (the one
- * that corresponds to the private key), and then a Credentials.CA_CERTIFICATE
- * entry which will have the rest of the chain concatenated in BER format.
- * <p>
- * TrustedCertificateEntry will just have a Credentials.CA_CERTIFICATE entry
- * with a single certificate.
- *
- * @hide
- */
-public class AndroidKeyStoreSpi extends KeyStoreSpi {
-    public static final String NAME = "AndroidKeyStore";
-
-    private KeyStore mKeyStore;
-    private int mUid = KeyStore.UID_SELF;
-
-    @Override
-    public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
-            UnrecoverableKeyException {
-        String userKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-        AndroidKeyStoreKey key;
-        if (!mKeyStore.contains(userKeyAlias, mUid)) {
-            // try legacy prefix for backward compatibility
-            userKeyAlias = Credentials.USER_SECRET_KEY + alias;
-            if (!mKeyStore.contains(userKeyAlias, mUid)) return null;
-        }
-        try {
-            key = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore,
-                                                                             userKeyAlias,
-                                                                             mUid);
-        } catch (KeyPermanentlyInvalidatedException e) {
-            throw new UnrecoverableKeyException(e.getMessage());
-        }
-        return key;
-    }
-
-    @Override
-    public Certificate[] engineGetCertificateChain(String alias) {
-        if (alias == null) {
-            throw new NullPointerException("alias == null");
-        }
-
-        final X509Certificate leaf = (X509Certificate) engineGetCertificate(alias);
-        if (leaf == null) {
-            return null;
-        }
-
-        final Certificate[] caList;
-
-        // Suppress the key not found warning for this call. It seems that this error is exclusively
-        // being thrown when there is a self signed certificate chain, so when the keystore service
-        // attempts to query for the CA details, it obviously fails to find them and returns a
-        // key not found exception. This is WAI, and throwing a stack trace here can be very
-        // misleading since the trace is not clear.
-        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
-                                             mUid,
-                                             true /* suppressKeyNotFoundWarning */);
-        if (caBytes != null) {
-            final Collection<X509Certificate> caChain = toCertificates(caBytes);
-
-            caList = new Certificate[caChain.size() + 1];
-
-            final Iterator<X509Certificate> it = caChain.iterator();
-            int i = 1;
-            while (it.hasNext()) {
-                caList[i++] = it.next();
-            }
-        } else {
-            caList = new Certificate[1];
-        }
-
-        caList[0] = leaf;
-
-        return caList;
-    }
-
-    @Override
-    public Certificate engineGetCertificate(String alias) {
-        if (alias == null) {
-            throw new NullPointerException("alias == null");
-        }
-
-        byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
-        if (encodedCert != null) {
-            return getCertificateForPrivateKeyEntry(alias, encodedCert);
-        }
-
-        encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
-        if (encodedCert != null) {
-            return getCertificateForTrustedCertificateEntry(encodedCert);
-        }
-
-        // This entry/alias does not contain a certificate.
-        return null;
-    }
-
-    private Certificate getCertificateForTrustedCertificateEntry(byte[] encodedCert) {
-        // For this certificate there shouldn't be a private key in this KeyStore entry. Thus,
-        // there's no need to wrap this certificate as opposed to the certificate associated with
-        // a private key entry.
-        return toCertificate(encodedCert);
-    }
-
-    private Certificate getCertificateForPrivateKeyEntry(String alias, byte[] encodedCert) {
-        // All crypto algorithms offered by Android Keystore for its private keys must also
-        // be offered for the corresponding public keys stored in the Android Keystore. The
-        // complication is that the underlying keystore service operates only on full key pairs,
-        // rather than just public keys or private keys. As a result, Android Keystore-backed
-        // crypto can only be offered for public keys for which keystore contains the
-        // corresponding private key. This is not the case for certificate-only entries (e.g.,
-        // trusted certificates).
-        //
-        // getCertificate().getPublicKey() is the only way to obtain the public key
-        // corresponding to the private key stored in the KeyStore. Thus, we need to make sure
-        // that the returned public key points to the underlying key pair / private key
-        // when available.
-
-        X509Certificate cert = toCertificate(encodedCert);
-        if (cert == null) {
-            // Failed to parse the certificate.
-            return null;
-        }
-
-        String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-        if (mKeyStore.contains(privateKeyAlias, mUid)) {
-            // As expected, keystore contains the private key corresponding to this public key. Wrap
-            // the certificate so that its getPublicKey method returns an Android Keystore
-            // PublicKey. This key will delegate crypto operations involving this public key to
-            // Android Keystore when higher-priority providers do not offer these crypto
-            // operations for this key.
-            return wrapIntoKeyStoreCertificate(privateKeyAlias, mUid, cert);
-        } else {
-            // This KeyStore entry/alias is supposed to contain the private key corresponding to
-            // the public key in this certificate, but it does not for some reason. It's probably a
-            // bug. Let other providers handle crypto operations involving the public key returned
-            // by this certificate's getPublicKey.
-            return cert;
-        }
-    }
-
-    /**
-     * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
-     * returned by the certificate contains information about the alias of the private key in
-     * keystore. This is needed so that Android Keystore crypto operations using public keys can
-     * find out which key alias to use. These operations cannot work without an alias.
-     */
-    private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
-            String privateKeyAlias, int uid, X509Certificate certificate) {
-        return (certificate != null)
-                ? new KeyStoreX509Certificate(privateKeyAlias, uid, certificate) : null;
-    }
-
-    private static X509Certificate toCertificate(byte[] bytes) {
-        try {
-            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-            return (X509Certificate) certFactory.generateCertificate(
-                    new ByteArrayInputStream(bytes));
-        } catch (CertificateException e) {
-            Log.w(NAME, "Couldn't parse certificate in keystore", e);
-            return null;
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private static Collection<X509Certificate> toCertificates(byte[] bytes) {
-        try {
-            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-            return (Collection<X509Certificate>) certFactory.generateCertificates(
-                            new ByteArrayInputStream(bytes));
-        } catch (CertificateException e) {
-            Log.w(NAME, "Couldn't parse certificates in keystore", e);
-            return new ArrayList<X509Certificate>();
-        }
-    }
-
-    private Date getModificationDate(String alias) {
-        final long epochMillis = mKeyStore.getmtime(alias, mUid);
-        if (epochMillis == -1L) {
-            return null;
-        }
-
-        return new Date(epochMillis);
-    }
-
-    @Override
-    public Date engineGetCreationDate(String alias) {
-        if (alias == null) {
-            throw new NullPointerException("alias == null");
-        }
-
-        Date d = getModificationDate(Credentials.USER_PRIVATE_KEY + alias);
-        if (d != null) {
-            return d;
-        }
-
-        d = getModificationDate(Credentials.USER_SECRET_KEY + alias);
-        if (d != null) {
-            return d;
-        }
-
-        d = getModificationDate(Credentials.USER_CERTIFICATE + alias);
-        if (d != null) {
-            return d;
-        }
-
-        return getModificationDate(Credentials.CA_CERTIFICATE + alias);
-    }
-
-    @Override
-    public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
-            throws KeyStoreException {
-        if ((password != null) && (password.length > 0)) {
-            throw new KeyStoreException("entries cannot be protected with passwords");
-        }
-
-        if (key instanceof PrivateKey) {
-            setPrivateKeyEntry(alias, (PrivateKey) key, chain, null);
-        } else if (key instanceof SecretKey) {
-            setSecretKeyEntry(alias, (SecretKey) key, null);
-        } else {
-            throw new KeyStoreException("Only PrivateKey and SecretKey are supported");
-        }
-    }
-
-    private static KeyProtection getLegacyKeyProtectionParameter(PrivateKey key)
-            throws KeyStoreException {
-        String keyAlgorithm = key.getAlgorithm();
-        KeyProtection.Builder specBuilder;
-        if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
-            specBuilder =
-                    new KeyProtection.Builder(
-                            KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
-            // Authorized to be used with any digest (including no digest).
-            // MD5 was never offered for Android Keystore for ECDSA.
-            specBuilder.setDigests(
-                    KeyProperties.DIGEST_NONE,
-                    KeyProperties.DIGEST_SHA1,
-                    KeyProperties.DIGEST_SHA224,
-                    KeyProperties.DIGEST_SHA256,
-                    KeyProperties.DIGEST_SHA384,
-                    KeyProperties.DIGEST_SHA512);
-        } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
-            specBuilder =
-                    new KeyProtection.Builder(
-                            KeyProperties.PURPOSE_ENCRYPT
-                            | KeyProperties.PURPOSE_DECRYPT
-                            | KeyProperties.PURPOSE_SIGN
-                            | KeyProperties.PURPOSE_VERIFY);
-            // Authorized to be used with any digest (including no digest).
-            specBuilder.setDigests(
-                    KeyProperties.DIGEST_NONE,
-                    KeyProperties.DIGEST_MD5,
-                    KeyProperties.DIGEST_SHA1,
-                    KeyProperties.DIGEST_SHA224,
-                    KeyProperties.DIGEST_SHA256,
-                    KeyProperties.DIGEST_SHA384,
-                    KeyProperties.DIGEST_SHA512);
-            // Authorized to be used with any encryption and signature padding
-            // schemes (including no padding).
-            specBuilder.setEncryptionPaddings(
-                    KeyProperties.ENCRYPTION_PADDING_NONE,
-                    KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
-                    KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
-            specBuilder.setSignaturePaddings(
-                    KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
-                    KeyProperties.SIGNATURE_PADDING_RSA_PSS);
-            // Disable randomized encryption requirement to support encryption
-            // padding NONE above.
-            specBuilder.setRandomizedEncryptionRequired(false);
-        } else {
-            throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm);
-        }
-        specBuilder.setUserAuthenticationRequired(false);
-
-        return specBuilder.build();
-    }
-
-    private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
-            java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
-        int flags = 0;
-        KeyProtection spec;
-        if (param == null) {
-            spec = getLegacyKeyProtectionParameter(key);
-        } else if (param instanceof KeyStoreParameter) {
-            spec = getLegacyKeyProtectionParameter(key);
-            KeyStoreParameter legacySpec = (KeyStoreParameter) param;
-            if (legacySpec.isEncryptionRequired()) {
-                flags = KeyStore.FLAG_ENCRYPTED;
-            }
-        } else if (param instanceof KeyProtection) {
-            spec = (KeyProtection) param;
-            if (spec.isCriticalToDeviceEncryption()) {
-                flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
-            }
-
-            if (spec.isStrongBoxBacked()) {
-                flags |= KeyStore.FLAG_STRONGBOX;
-            }
-        } else {
-            throw new KeyStoreException(
-                    "Unsupported protection parameter class:" + param.getClass().getName()
-                    + ". Supported: " + KeyProtection.class.getName() + ", "
-                    + KeyStoreParameter.class.getName());
-        }
-
-        // Make sure the chain exists since this is a PrivateKey
-        if ((chain == null) || (chain.length == 0)) {
-            throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
-        }
-
-        // Do chain type checking.
-        X509Certificate[] x509chain = new X509Certificate[chain.length];
-        for (int i = 0; i < chain.length; i++) {
-            if (!"X.509".equals(chain[i].getType())) {
-                throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
-                        + i);
-            }
-
-            if (!(chain[i] instanceof X509Certificate)) {
-                throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
-                        + i);
-            }
-
-            x509chain[i] = (X509Certificate) chain[i];
-        }
-
-        final byte[] userCertBytes;
-        try {
-            userCertBytes = x509chain[0].getEncoded();
-        } catch (CertificateEncodingException e) {
-            throw new KeyStoreException("Failed to encode certificate #0", e);
-        }
-
-        /*
-         * If we have a chain, store it in the CA certificate slot for this
-         * alias as concatenated DER-encoded certificates. These can be
-         * deserialized by {@link CertificateFactory#generateCertificates}.
-         */
-        final byte[] chainBytes;
-        if (chain.length > 1) {
-            /*
-             * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
-             * so we only need the certificates starting at index 1.
-             */
-            final byte[][] certsBytes = new byte[x509chain.length - 1][];
-            int totalCertLength = 0;
-            for (int i = 0; i < certsBytes.length; i++) {
-                try {
-                    certsBytes[i] = x509chain[i + 1].getEncoded();
-                    totalCertLength += certsBytes[i].length;
-                } catch (CertificateEncodingException e) {
-                    throw new KeyStoreException("Failed to encode certificate #" + i, e);
-                }
-            }
-
-            /*
-             * Serialize this into one byte array so we can later call
-             * CertificateFactory#generateCertificates to recover them.
-             */
-            chainBytes = new byte[totalCertLength];
-            int outputOffset = 0;
-            for (int i = 0; i < certsBytes.length; i++) {
-                final int certLength = certsBytes[i].length;
-                System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
-                outputOffset += certLength;
-                certsBytes[i] = null;
-            }
-        } else {
-            chainBytes = null;
-        }
-
-        final String pkeyAlias;
-        if (key instanceof AndroidKeyStorePrivateKey) {
-            pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
-        } else {
-            pkeyAlias = null;
-        }
-
-        byte[] pkcs8EncodedPrivateKeyBytes;
-        KeymasterArguments importArgs;
-        final boolean shouldReplacePrivateKey;
-        if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
-            final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
-            if (!alias.equals(keySubalias)) {
-                throw new KeyStoreException("Can only replace keys with same alias: " + alias
-                        + " != " + keySubalias);
-            }
-            shouldReplacePrivateKey = false;
-            importArgs = null;
-            pkcs8EncodedPrivateKeyBytes = null;
-        } else {
-            shouldReplacePrivateKey = true;
-            // Make sure the PrivateKey format is the one we support.
-            final String keyFormat = key.getFormat();
-            if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
-                throw new KeyStoreException(
-                        "Unsupported private key export format: " + keyFormat
-                        + ". Only private keys which export their key material in PKCS#8 format are"
-                        + " supported.");
-            }
-
-            // Make sure we can actually encode the key.
-            pkcs8EncodedPrivateKeyBytes = key.getEncoded();
-            if (pkcs8EncodedPrivateKeyBytes == null) {
-                throw new KeyStoreException("Private key did not export any key material");
-            }
-
-            importArgs = new KeymasterArguments();
-            try {
-                importArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
-                        KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
-                                key.getAlgorithm()));
-                @KeyProperties.PurposeEnum int purposes = spec.getPurposes();
-                importArgs.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
-                        KeyProperties.Purpose.allToKeymaster(purposes));
-                if (spec.isDigestsSpecified()) {
-                    importArgs.addEnums(KeymasterDefs.KM_TAG_DIGEST,
-                            KeyProperties.Digest.allToKeymaster(spec.getDigests()));
-                }
-
-                importArgs.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE,
-                        KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()));
-                int[] keymasterEncryptionPaddings =
-                        KeyProperties.EncryptionPadding.allToKeymaster(
-                                spec.getEncryptionPaddings());
-                if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                        && (spec.isRandomizedEncryptionRequired())) {
-                    for (int keymasterPadding : keymasterEncryptionPaddings) {
-                        if (!KeymasterUtils
-                                .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
-                                        keymasterPadding)) {
-                            throw new KeyStoreException(
-                                    "Randomized encryption (IND-CPA) required but is violated by"
-                                    + " encryption padding mode: "
-                                    + KeyProperties.EncryptionPadding.fromKeymaster(
-                                            keymasterPadding)
-                                    + ". See KeyProtection documentation.");
-                        }
-                    }
-                }
-                importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
-                importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
-                        KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
-                KeymasterUtils.addUserAuthArgs(importArgs, spec);
-                importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
-                        spec.getKeyValidityStart());
-                importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                        spec.getKeyValidityForOriginationEnd());
-                importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                        spec.getKeyValidityForConsumptionEnd());
-            } catch (IllegalArgumentException | IllegalStateException e) {
-                throw new KeyStoreException(e);
-            }
-        }
-
-
-        boolean success = false;
-        try {
-            // Store the private key, if necessary
-            if (shouldReplacePrivateKey) {
-                // Delete the stored private key and any related entries before importing the
-                // provided key
-                Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
-                KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
-                int errorCode = mKeyStore.importKey(
-                        Credentials.USER_PRIVATE_KEY + alias,
-                        importArgs,
-                        KeymasterDefs.KM_KEY_FORMAT_PKCS8,
-                        pkcs8EncodedPrivateKeyBytes,
-                        mUid,
-                        flags,
-                        resultingKeyCharacteristics);
-                if (errorCode != KeyStore.NO_ERROR) {
-                    throw new KeyStoreException("Failed to store private key",
-                            KeyStore.getKeyStoreException(errorCode));
-                }
-            } else {
-                // Keep the stored private key around -- delete all other entry types
-                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
-                Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
-            }
-
-            // Store the leaf certificate
-            int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes,
-                    mUid, flags);
-            if (errorCode != KeyStore.NO_ERROR) {
-                throw new KeyStoreException("Failed to store certificate #0",
-                        KeyStore.getKeyStoreException(errorCode));
-            }
-
-            // Store the certificate chain
-            errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes,
-                    mUid, flags);
-            if (errorCode != KeyStore.NO_ERROR) {
-                throw new KeyStoreException("Failed to store certificate chain",
-                        KeyStore.getKeyStoreException(errorCode));
-            }
-            success = true;
-        } finally {
-            if (!success) {
-                if (shouldReplacePrivateKey) {
-                    Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
-                } else {
-                    Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
-                    Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
-                }
-            }
-        }
-    }
-
-    private void setSecretKeyEntry(String entryAlias, SecretKey key,
-            java.security.KeyStore.ProtectionParameter param)
-            throws KeyStoreException {
-        if ((param != null) && (!(param instanceof KeyProtection))) {
-            throw new KeyStoreException(
-                    "Unsupported protection parameter class: " + param.getClass().getName()
-                    + ". Supported: " + KeyProtection.class.getName());
-        }
-        KeyProtection params = (KeyProtection) param;
-
-        if (key instanceof AndroidKeyStoreSecretKey) {
-            // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
-            // overwrite its own entry.
-            String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
-            if (keyAliasInKeystore == null) {
-                throw new KeyStoreException("KeyStore-backed secret key does not have an alias");
-            }
-            String keyAliasPrefix = Credentials.USER_PRIVATE_KEY;
-            if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
-                // try legacy prefix
-                keyAliasPrefix = Credentials.USER_SECRET_KEY;
-                if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
-                    throw new KeyStoreException("KeyStore-backed secret key has invalid alias: "
-                            + keyAliasInKeystore);
-                }
-            }
-            String keyEntryAlias =
-                    keyAliasInKeystore.substring(keyAliasPrefix.length());
-            if (!entryAlias.equals(keyEntryAlias)) {
-                throw new KeyStoreException("Can only replace KeyStore-backed keys with same"
-                        + " alias: " + entryAlias + " != " + keyEntryAlias);
-            }
-            // This is the entry where this key is already stored. No need to do anything.
-            if (params != null) {
-                throw new KeyStoreException("Modifying KeyStore-backed key using protection"
-                        + " parameters not supported");
-            }
-            return;
-        }
-
-        if (params == null) {
-            throw new KeyStoreException(
-                    "Protection parameters must be specified when importing a symmetric key");
-        }
-
-        // Not a KeyStore-backed secret key -- import its key material into keystore.
-        String keyExportFormat = key.getFormat();
-        if (keyExportFormat == null) {
-            throw new KeyStoreException(
-                    "Only secret keys that export their key material are supported");
-        } else if (!"RAW".equals(keyExportFormat)) {
-            throw new KeyStoreException(
-                    "Unsupported secret key material export format: " + keyExportFormat);
-        }
-        byte[] keyMaterial = key.getEncoded();
-        if (keyMaterial == null) {
-            throw new KeyStoreException("Key did not export its key material despite supporting"
-                    + " RAW format export");
-        }
-
-        KeymasterArguments args = new KeymasterArguments();
-        try {
-            int keymasterAlgorithm =
-                    KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
-            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
-
-            int[] keymasterDigests;
-            if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
-                // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
-                // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
-                // digest, we don't let import parameters override the digest implied by the key.
-                // If the parameters specify digests at all, they must specify only one digest, the
-                // only implied by key algorithm.
-                int keymasterImpliedDigest =
-                        KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
-                if (keymasterImpliedDigest == -1) {
-                    throw new ProviderException(
-                            "HMAC key algorithm digest unknown for key algorithm "
-                                    + key.getAlgorithm());
-                }
-                keymasterDigests = new int[] {keymasterImpliedDigest};
-                if (params.isDigestsSpecified()) {
-                    // Digest(s) explicitly specified in params -- check that the list consists of
-                    // exactly one digest, the one implied by key algorithm.
-                    int[] keymasterDigestsFromParams =
-                            KeyProperties.Digest.allToKeymaster(params.getDigests());
-                    if ((keymasterDigestsFromParams.length != 1)
-                            || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
-                        throw new KeyStoreException(
-                                "Unsupported digests specification: "
-                                + Arrays.asList(params.getDigests()) + ". Only "
-                                + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
-                                + " supported for HMAC key algorithm " + key.getAlgorithm());
-                    }
-                }
-            } else {
-                // Key algorithm does not imply a digest.
-                if (params.isDigestsSpecified()) {
-                    keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
-                } else {
-                    keymasterDigests = EmptyArray.INT;
-                }
-            }
-            args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
-
-            @KeyProperties.PurposeEnum int purposes = params.getPurposes();
-            int[] keymasterBlockModes =
-                    KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
-            if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                    && (params.isRandomizedEncryptionRequired())) {
-                for (int keymasterBlockMode : keymasterBlockModes) {
-                    if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
-                            keymasterBlockMode)) {
-                        throw new KeyStoreException(
-                                "Randomized encryption (IND-CPA) required but may be violated by"
-                                + " block mode: "
-                                + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
-                                + ". See KeyProtection documentation.");
-                    }
-                }
-            }
-            args.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
-                    KeyProperties.Purpose.allToKeymaster(purposes));
-            args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
-            if (params.getSignaturePaddings().length > 0) {
-                throw new KeyStoreException("Signature paddings not supported for symmetric keys");
-            }
-            int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
-                    params.getEncryptionPaddings());
-            args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
-            KeymasterUtils.addUserAuthArgs(args, params);
-            KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
-                    args,
-                    keymasterAlgorithm,
-                    keymasterBlockModes,
-                    keymasterDigests);
-            args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
-                    params.getKeyValidityStart());
-            args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                    params.getKeyValidityForOriginationEnd());
-            args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                    params.getKeyValidityForConsumptionEnd());
-
-            if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
-                    && (!params.isRandomizedEncryptionRequired())) {
-                // Permit caller-provided IV when encrypting with this key
-                args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
-            }
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw new KeyStoreException(e);
-        }
-        int flags = 0;
-        if (params.isCriticalToDeviceEncryption()) {
-            flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
-        }
-        if (params.isStrongBoxBacked()) {
-            flags |= KeyStore.FLAG_STRONGBOX;
-        }
-
-        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
-        String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
-        int errorCode = mKeyStore.importKey(
-                keyAliasInKeystore,
-                args,
-                KeymasterDefs.KM_KEY_FORMAT_RAW,
-                keyMaterial,
-                mUid,
-                flags,
-                new KeyCharacteristics());
-        if (errorCode != KeyStore.NO_ERROR) {
-            throw new KeyStoreException("Failed to import secret key. Keystore error code: "
-                + errorCode);
-        }
-    }
-
-    private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry,
-            java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
-        if (param != null) {
-            throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
-        }
-
-        byte[] maskingKey = new byte[32];
-
-
-        KeymasterArguments args = new KeymasterArguments();
-        String[] parts = entry.getTransformation().split("/");
-
-        String algorithm = parts[0];
-        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
-            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
-            args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        }
-
-        if (parts.length > 1) {
-            String mode = parts[1];
-            if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) {
-                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
-            } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) {
-                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC);
-            } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) {
-                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
-            } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) {
-                args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
-            }
-        }
-
-        if (parts.length > 2) {
-            String padding = parts[2];
-            if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
-                // Noop
-            } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
-                args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
-            } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
-                args.addEnums(KeymasterDefs.KM_TAG_PADDING,
-                    KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
-            } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
-                args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
-            }
-        }
-
-        KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec();
-        if (spec.isDigestsSpecified()) {
-            String digest = spec.getDigests()[0];
-            if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
-                // Noop
-            } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
-            } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
-            } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
-            } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
-            } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
-            } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) {
-                args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
-            }
-        }
-
-        int errorCode = mKeyStore.importWrappedKey(
-            Credentials.USER_PRIVATE_KEY + alias,
-            entry.getWrappedKeyBytes(),
-            Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
-            maskingKey,
-            args,
-            GateKeeper.getSecureUserId(),
-            0, // FIXME fingerprint id?
-            mUid,
-            new KeyCharacteristics());
-        if (errorCode == KeymasterDefs.KM_ERROR_UNIMPLEMENTED) {
-          throw new SecureKeyImportUnavailableException("Could not import wrapped key");
-        } else if (errorCode != KeyStore.NO_ERROR) {
-            throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
-                + errorCode);
-        }
-    }
-
-    @Override
-    public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)
-            throws KeyStoreException {
-        throw new KeyStoreException("Operation not supported because key encoding is unknown");
-    }
-
-    @Override
-    public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
-        if (isKeyEntry(alias)) {
-            throw new KeyStoreException("Entry exists and is not a trusted certificate");
-        }
-
-        // We can't set something to null.
-        if (cert == null) {
-            throw new NullPointerException("cert == null");
-        }
-
-        final byte[] encoded;
-        try {
-            encoded = cert.getEncoded();
-        } catch (CertificateEncodingException e) {
-            throw new KeyStoreException(e);
-        }
-
-        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded, mUid, KeyStore.FLAG_NONE)) {
-            throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
-        }
-    }
-
-    @Override
-    public void engineDeleteEntry(String alias) throws KeyStoreException {
-        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
-            throw new KeyStoreException("Failed to delete entry: " + alias);
-        }
-    }
-
-    private Set<String> getUniqueAliases() {
-        final String[] rawAliases = mKeyStore.list("", mUid);
-        if (rawAliases == null) {
-            return new HashSet<String>();
-        }
-
-        final Set<String> aliases = new HashSet<String>(rawAliases.length);
-        for (String alias : rawAliases) {
-            final int idx = alias.indexOf('_');
-            if ((idx == -1) || (alias.length() <= idx)) {
-                Log.e(NAME, "invalid alias: " + alias);
-                continue;
-            }
-
-            aliases.add(new String(alias.substring(idx + 1)));
-        }
-
-        return aliases;
-    }
-
-    @Override
-    public Enumeration<String> engineAliases() {
-        return Collections.enumeration(getUniqueAliases());
-    }
-
-    @Override
-    public boolean engineContainsAlias(String alias) {
-        if (alias == null) {
-            throw new NullPointerException("alias == null");
-        }
-
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid)
-                || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid)
-                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias, mUid)
-                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
-    }
-
-    @Override
-    public int engineSize() {
-        return getUniqueAliases().size();
-    }
-
-    @Override
-    public boolean engineIsKeyEntry(String alias) {
-        return isKeyEntry(alias);
-    }
-
-    private boolean isKeyEntry(String alias) {
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid) ||
-                mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid);
-    }
-
-
-    private boolean isCertificateEntry(String alias) {
-        if (alias == null) {
-            throw new NullPointerException("alias == null");
-        }
-
-        return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
-    }
-
-    @Override
-    public boolean engineIsCertificateEntry(String alias) {
-        return !isKeyEntry(alias) && isCertificateEntry(alias);
-    }
-
-    @Override
-    public String engineGetCertificateAlias(Certificate cert) {
-        if (cert == null) {
-            return null;
-        }
-        if (!"X.509".equalsIgnoreCase(cert.getType())) {
-            // Only X.509 certificates supported
-            return null;
-        }
-        byte[] targetCertBytes;
-        try {
-            targetCertBytes = cert.getEncoded();
-        } catch (CertificateEncodingException e) {
-            return null;
-        }
-        if (targetCertBytes == null) {
-            return null;
-        }
-
-        final Set<String> nonCaEntries = new HashSet<String>();
-
-        /*
-         * First scan the PrivateKeyEntry types. The KeyStoreSpi documentation
-         * says to only compare the first certificate in the chain which is
-         * equivalent to the USER_CERTIFICATE prefix for the Android keystore
-         * convention.
-         */
-        final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE, mUid);
-        if (certAliases != null) {
-            for (String alias : certAliases) {
-                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
-                if (certBytes == null) {
-                    continue;
-                }
-
-                nonCaEntries.add(alias);
-
-                if (Arrays.equals(certBytes, targetCertBytes)) {
-                    return alias;
-                }
-            }
-        }
-
-        /*
-         * Look at all the TrustedCertificateEntry types. Skip all the
-         * PrivateKeyEntry we looked at above.
-         */
-        final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE, mUid);
-        if (certAliases != null) {
-            for (String alias : caAliases) {
-                if (nonCaEntries.contains(alias)) {
-                    continue;
-                }
-
-                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
-                if (certBytes == null) {
-                    continue;
-                }
-
-                if (Arrays.equals(certBytes, targetCertBytes)) {
-                    return alias;
-                }
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public void engineStore(OutputStream stream, char[] password) throws IOException,
-            NoSuchAlgorithmException, CertificateException {
-        throw new UnsupportedOperationException("Can not serialize AndroidKeyStore to OutputStream");
-    }
-
-    @Override
-    public void engineLoad(InputStream stream, char[] password) throws IOException,
-            NoSuchAlgorithmException, CertificateException {
-        if (stream != null) {
-            throw new IllegalArgumentException("InputStream not supported");
-        }
-
-        if (password != null) {
-            throw new IllegalArgumentException("password not supported");
-        }
-
-        // Unfortunate name collision.
-        mKeyStore = KeyStore.getInstance();
-        mUid = KeyStore.UID_SELF;
-    }
-
-    @Override
-    public void engineLoad(LoadStoreParameter param) throws IOException,
-            NoSuchAlgorithmException, CertificateException {
-        int uid = KeyStore.UID_SELF;
-        if (param != null) {
-            if (param instanceof AndroidKeyStoreLoadStoreParameter) {
-                uid = ((AndroidKeyStoreLoadStoreParameter) param).getUid();
-            } else {
-                throw new IllegalArgumentException(
-                        "Unsupported param type: " + param.getClass());
-            }
-        }
-        mKeyStore = KeyStore.getInstance();
-        mUid = uid;
-    }
-
-    @Override
-    public void engineSetEntry(String alias, Entry entry, ProtectionParameter param)
-            throws KeyStoreException {
-        if (entry == null) {
-            throw new KeyStoreException("entry == null");
-        }
-
-        Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
-
-        if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) {
-            java.security.KeyStore.TrustedCertificateEntry trE =
-                    (java.security.KeyStore.TrustedCertificateEntry) entry;
-            engineSetCertificateEntry(alias, trE.getTrustedCertificate());
-            return;
-        }
-
-        if (entry instanceof PrivateKeyEntry) {
-            PrivateKeyEntry prE = (PrivateKeyEntry) entry;
-            setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param);
-        } else if (entry instanceof SecretKeyEntry) {
-            SecretKeyEntry secE = (SecretKeyEntry) entry;
-            setSecretKeyEntry(alias, secE.getSecretKey(), param);
-        } else if (entry instanceof WrappedKeyEntry) {
-            WrappedKeyEntry wke = (WrappedKeyEntry) entry;
-            setWrappedKeyEntry(alias, wke, param);
-        } else {
-            throw new KeyStoreException(
-                    "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
-                    + "; was " + entry);
-        }
-    }
-
-    /**
-     * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
-     * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
-     * can find out which keystore private key entry to use. This is needed so that Android Keystore
-     * crypto operations using public keys can find out which key alias to use. These operations
-     * require an alias.
-     */
-    static class KeyStoreX509Certificate extends DelegatingX509Certificate {
-        private final String mPrivateKeyAlias;
-        private final int mPrivateKeyUid;
-        KeyStoreX509Certificate(String privateKeyAlias, int privateKeyUid,
-                X509Certificate delegate) {
-            super(delegate);
-            mPrivateKeyAlias = privateKeyAlias;
-            mPrivateKeyUid = privateKeyUid;
-        }
-
-        @Override
-        public PublicKey getPublicKey() {
-            PublicKey original = super.getPublicKey();
-            return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                    mPrivateKeyAlias, mPrivateKeyUid,
-                    original.getAlgorithm(), original.getEncoded());
-        }
-    }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
deleted file mode 100644
index 1f1d36f..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,319 +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.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore unauthenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
-    abstract static class ECB extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
-        protected ECB(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
-        }
-
-        public static class NoPadding extends ECB {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-        }
-
-        public static class PKCS7Padding extends ECB {
-            public PKCS7Padding() {
-                super(KeymasterDefs.KM_PAD_PKCS7);
-            }
-        }
-    }
-
-    abstract static class CBC extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
-        protected CBC(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
-        }
-
-        public static class NoPadding extends CBC {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-        }
-
-        public static class PKCS7Padding extends CBC {
-            public PKCS7Padding() {
-                super(KeymasterDefs.KM_PAD_PKCS7);
-            }
-        }
-    }
-
-    abstract static class CTR extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
-        protected CTR(int keymasterPadding) {
-            super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
-        }
-
-        public static class NoPadding extends CTR {
-            public NoPadding() {
-                super(KeymasterDefs.KM_PAD_NONE);
-            }
-        }
-    }
-
-    private static final int BLOCK_SIZE_BYTES = 16;
-
-    private final int mKeymasterBlockMode;
-    private final int mKeymasterPadding;
-    /** Whether this transformation requires an IV. */
-    private final boolean mIvRequired;
-
-    private byte[] mIv;
-
-    /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
-    private boolean mIvHasBeenUsed;
-
-    AndroidKeyStoreUnauthenticatedAESCipherSpi(
-            int keymasterBlockMode,
-            int keymasterPadding,
-            boolean ivRequired) {
-        mKeymasterBlockMode = keymasterBlockMode;
-        mKeymasterPadding = keymasterPadding;
-        mIvRequired = ivRequired;
-    }
-
-    @Override
-    protected final void resetAll() {
-        mIv = null;
-        mIvHasBeenUsed = false;
-        super.resetAll();
-    }
-
-    @Override
-    protected final void resetWhilePreservingInitState() {
-        super.resetWhilePreservingInitState();
-    }
-
-    @Override
-    protected final void initKey(int opmode, Key key) throws InvalidKeyException {
-        if (!(key instanceof AndroidKeyStoreSecretKey)) {
-            throw new InvalidKeyException(
-                    "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
-        }
-        if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
-            throw new InvalidKeyException(
-                    "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
-                    KeyProperties.KEY_ALGORITHM_AES + " supported");
-        }
-        setKey((AndroidKeyStoreSecretKey) key);
-    }
-
-    @Override
-    protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
-        if (!mIvRequired) {
-            return;
-        }
-
-        // IV is used
-        if (!isEncrypting()) {
-            throw new InvalidKeyException("IV required when decrypting"
-                    + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
-        }
-    }
-
-    @Override
-    protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
-            throws InvalidAlgorithmParameterException {
-        if (!mIvRequired) {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
-            }
-            return;
-        }
-
-        // IV is used
-        if (params == null) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException(
-                        "IvParameterSpec must be provided when decrypting");
-            }
-            return;
-        }
-        if (!(params instanceof IvParameterSpec)) {
-            throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
-        }
-        mIv = ((IvParameterSpec) params).getIV();
-        if (mIv == null) {
-            throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
-        }
-    }
-
-    @Override
-    protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
-            throws InvalidAlgorithmParameterException {
-        if (!mIvRequired) {
-            if (params != null) {
-                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
-            }
-            return;
-        }
-
-        // IV is used
-        if (params == null) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException("IV required when decrypting"
-                        + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
-            }
-            return;
-        }
-
-        if (!"AES".equalsIgnoreCase(params.getAlgorithm())) {
-            throw new InvalidAlgorithmParameterException(
-                    "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
-                    + ". Supported: AES");
-        }
-
-        IvParameterSpec ivSpec;
-        try {
-            ivSpec = params.getParameterSpec(IvParameterSpec.class);
-        } catch (InvalidParameterSpecException e) {
-            if (!isEncrypting()) {
-                // IV must be provided by the caller
-                throw new InvalidAlgorithmParameterException("IV required when decrypting"
-                        + ", but not found in parameters: " + params, e);
-            }
-            mIv = null;
-            return;
-        }
-        mIv = ivSpec.getIV();
-        if (mIv == null) {
-            throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
-        }
-    }
-
-    @Override
-    protected final int getAdditionalEntropyAmountForBegin() {
-        if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
-            // IV will need to be generated
-            return BLOCK_SIZE_BYTES;
-        }
-
-        return 0;
-    }
-
-    @Override
-    protected final int getAdditionalEntropyAmountForFinish() {
-        return 0;
-    }
-
-    @Override
-    protected final void addAlgorithmSpecificParametersToBegin(
-            @NonNull KeymasterArguments keymasterArgs) {
-        if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
-            // IV is being reused for encryption: this violates security best practices.
-            throw new IllegalStateException(
-                    "IV has already been used. Reusing IV in encryption mode violates security best"
-                    + " practices.");
-        }
-
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
-        keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
-        if ((mIvRequired) && (mIv != null)) {
-            keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
-        }
-    }
-
-    @Override
-    protected final void loadAlgorithmSpecificParametersFromBeginResult(
-            @NonNull KeymasterArguments keymasterArgs) {
-        mIvHasBeenUsed = true;
-
-        // NOTE: Keymaster doesn't always return an IV, even if it's used.
-        byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
-        if ((returnedIv != null) && (returnedIv.length == 0)) {
-            returnedIv = null;
-        }
-
-        if (mIvRequired) {
-            if (mIv == null) {
-                mIv = returnedIv;
-            } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
-                throw new ProviderException("IV in use differs from provided IV");
-            }
-        } else {
-            if (returnedIv != null) {
-                throw new ProviderException(
-                        "IV in use despite IV not being used by this transformation");
-            }
-        }
-    }
-
-    @Override
-    protected final int engineGetBlockSize() {
-        return BLOCK_SIZE_BYTES;
-    }
-
-    @Override
-    protected final int engineGetOutputSize(int inputLen) {
-        return inputLen + 3 * BLOCK_SIZE_BYTES;
-    }
-
-    @Override
-    protected final byte[] engineGetIV() {
-        return ArrayUtils.cloneIfNotEmpty(mIv);
-    }
-
-    @Nullable
-    @Override
-    protected final AlgorithmParameters engineGetParameters() {
-        if (!mIvRequired) {
-            return null;
-        }
-        if ((mIv != null) && (mIv.length > 0)) {
-            try {
-                AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
-                params.init(new IvParameterSpec(mIv));
-                return params;
-            } catch (NoSuchAlgorithmException e) {
-                throw new ProviderException(
-                        "Failed to obtain AES AlgorithmParameters", e);
-            } catch (InvalidParameterSpecException e) {
-                throw new ProviderException(
-                        "Failed to initialize AES AlgorithmParameters with an IV",
-                        e);
-            }
-        }
-        return null;
-    }
-}
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 1eb8541..be865a0 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -36,9 +36,11 @@
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.SecureRandom;
+import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Random;
 import java.util.Set;
@@ -281,8 +283,9 @@
             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
             keyStore.load(null);
 
+            Certificate[] certs = keyStore.getCertificateChain(keystoreAlias);
             X509Certificate[] certificateChain =
-                    (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias);
+                Arrays.copyOf(certs, certs.length, X509Certificate[].class);
 
             keyStore.deleteEntry(keystoreAlias);
 
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 9ca551b..1f9022b 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -446,13 +446,6 @@
     @UnsupportedAppUsage
     @Deprecated
     public int getUid() {
-        if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
-            // a UID, because we are still being used with the old Keystore SPI.
-            // TODO This if statement and body can be removed when the Keystore 2 migration is
-            //      complete. b/171563717
-            return mNamespace;
-        }
         try {
             return KeyProperties.namespaceToLegacyUid(mNamespace);
         } catch (IllegalArgumentException e) {
@@ -1021,14 +1014,6 @@
         @NonNull
         @Deprecated
         public Builder setUid(int uid) {
-            if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
-                // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
-                // a UID, because we are still being used with the old Keystore SPI.
-                // TODO This if statement and body can be removed when the Keystore 2 migration is
-                //      complete. b/171563717
-                mNamespace = uid;
-                return this;
-            }
             mNamespace = KeyProperties.legacyUidToNamespace(uid);
             return this;
         }
@@ -1666,9 +1651,10 @@
          * Set whether this key is critical to the device encryption flow
          *
          * This is a special flag only available to system servers to indicate the current key
-         * is part of the device encryption flow.
+         * is part of the device encryption flow. Setting this flag causes the key to not
+         * be cryptographically bound to the LSKF even if the key is otherwise authentication
+         * bound.
          *
-         * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
          * @hide
          */
         public Builder setCriticalToDeviceEncryption(boolean critical) {
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 673491e..88d1a5b 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -24,6 +24,7 @@
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricPrompt;
 import android.security.GateKeeper;
+import android.security.keystore2.KeymasterUtils;
 
 import java.security.Key;
 import java.security.KeyStore.ProtectionParameter;
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
deleted file mode 100644
index 2c0f40d..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ /dev/null
@@ -1,225 +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.security.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. Thirdly, when the input is smaller than a threshold, skipping update
- * and passing input data directly to final improves performance. This threshold is configurable;
- * using a threshold <= 1 causes the helper act eagerly, which may be required for some types of
- * operations (e.g. ciphers).
- *
- * <p>The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
- * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
- * parameters to {@code update} and {@code final} operations.
- *
- * @hide
- */
-class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationStreamer {
-
-    /**
-     * Bidirectional chunked data stream over a KeyStore crypto operation.
-     */
-    interface Stream {
-        /**
-         * Returns the result of the KeyStore {@code update} operation or null if keystore couldn't
-         * be reached.
-         */
-        OperationResult update(byte[] input);
-
-        /**
-         * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
-         * be reached.
-         */
-        OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy);
-    }
-
-    // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
-    // Thus, it's safer to use a much smaller upper bound.
-    private static final int DEFAULT_CHUNK_SIZE_MAX = 64 * 1024;
-    // The chunk buffer will be sent to update until its size under this threshold.
-    // This threshold should be <= the max input allowed for finish.
-    // Setting this threshold <= 1 will effectivley disable buffering between updates.
-    private static final int DEFAULT_CHUNK_SIZE_THRESHOLD = 2 * 1024;
-
-    private final Stream mKeyStoreStream;
-    private final int mChunkSizeMax;
-    private final int mChunkSizeThreshold;
-    private final byte[] mChunk;
-    private int mChunkLength = 0;
-    private long mConsumedInputSizeBytes;
-    private long mProducedOutputSizeBytes;
-
-    KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
-        this(operation, DEFAULT_CHUNK_SIZE_THRESHOLD, DEFAULT_CHUNK_SIZE_MAX);
-    }
-
-    KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold) {
-        this(operation, chunkSizeThreshold, DEFAULT_CHUNK_SIZE_MAX);
-    }
-
-    KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold,
-            int chunkSizeMax) {
-        mKeyStoreStream = operation;
-        mChunkSizeMax = chunkSizeMax;
-        if (chunkSizeThreshold <= 0) {
-            mChunkSizeThreshold = 1;
-        } else if (chunkSizeThreshold > chunkSizeMax) {
-            mChunkSizeThreshold = chunkSizeMax;
-        } else {
-            mChunkSizeThreshold = chunkSizeThreshold;
-        }
-        mChunk = new byte[mChunkSizeMax];
-    }
-
-    public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException {
-        if (inputLength == 0 || input == null) {
-            // No input provided
-            return EmptyArray.BYTE;
-        }
-        if (inputLength < 0 || inputOffset < 0 || (inputOffset + inputLength) > input.length) {
-            throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
-                "Input offset and length out of bounds of input array");
-        }
-
-        byte[] output = EmptyArray.BYTE;
-
-        while (inputLength > 0 || mChunkLength >= mChunkSizeThreshold) {
-            int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
-                    inputLength);
-            inputLength -= inputConsumed;
-            inputOffset += inputConsumed;
-            mChunkLength += inputConsumed;
-            mConsumedInputSizeBytes += inputConsumed;
-
-            if (mChunkLength > mChunkSizeMax) {
-                throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
-                    "Chunk size exceeded max chunk size. Max: " + mChunkSizeMax
-                    + " Actual: " + mChunkLength);
-            }
-
-            if (mChunkLength >= mChunkSizeThreshold) {
-                OperationResult opResult = mKeyStoreStream.update(
-                        ArrayUtils.subarray(mChunk, 0, mChunkLength));
-
-                if (opResult == null) {
-                    throw new KeyStoreConnectException();
-                } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-                    throw KeyStore.getKeyStoreException(opResult.resultCode);
-                }
-                if (opResult.inputConsumed <= 0) {
-                    throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
-                        "Keystore consumed 0 of " + mChunkLength + " bytes provided.");
-                } else if (opResult.inputConsumed > mChunkLength) {
-                    throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
-                        "Keystore consumed more input than provided. Provided: "
-                            + mChunkLength + ", consumed: " + opResult.inputConsumed);
-                }
-                mChunkLength -= opResult.inputConsumed;
-
-                if (mChunkLength > 0) {
-                    // Partialy consumed, shift chunk contents
-                    ArrayUtils.copy(mChunk, opResult.inputConsumed, mChunk, 0, mChunkLength);
-                }
-
-                if ((opResult.output != null) && (opResult.output.length > 0)) {
-                    // Output was produced
-                    mProducedOutputSizeBytes += opResult.output.length;
-                    output = ArrayUtils.concat(output, opResult.output);
-                }
-            }
-        }
-        return output;
-    }
-
-    public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-            byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
-        byte[] output = update(input, inputOffset, inputLength);
-        byte[] finalChunk = ArrayUtils.subarray(mChunk, 0, mChunkLength);
-        OperationResult opResult = mKeyStoreStream.finish(finalChunk, signature, additionalEntropy);
-
-        if (opResult == null) {
-            throw new KeyStoreConnectException();
-        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getKeyStoreException(opResult.resultCode);
-        }
-        // If no error, assume all input consumed
-        mConsumedInputSizeBytes += finalChunk.length;
-
-        if ((opResult.output != null) && (opResult.output.length > 0)) {
-            mProducedOutputSizeBytes += opResult.output.length;
-            output = ArrayUtils.concat(output, opResult.output);
-        }
-
-        return output;
-    }
-
-    @Override
-    public long getConsumedInputSizeBytes() {
-        return mConsumedInputSizeBytes;
-    }
-
-    @Override
-    public long getProducedOutputSizeBytes() {
-        return mProducedOutputSizeBytes;
-    }
-
-    /**
-     * Main data stream via a KeyStore streaming operation.
-     *
-     * <p>For example, for an encryption operation, this is the stream through which plaintext is
-     * provided and ciphertext is obtained.
-     */
-    public static class MainDataStream implements Stream {
-
-        private final KeyStore mKeyStore;
-        private final IBinder mOperationToken;
-
-        public MainDataStream(KeyStore keyStore, IBinder operationToken) {
-            mKeyStore = keyStore;
-            mOperationToken = operationToken;
-        }
-
-        @Override
-        public OperationResult update(byte[] input) {
-            return mKeyStore.update(mOperationToken, null, input);
-        }
-
-        @Override
-        public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
-            return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy);
-        }
-    }
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
deleted file mode 100644
index 062c2d4..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
+++ /dev/null
@@ -1,42 +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.security.keystore;
-
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * @hide
- */
-interface KeyStoreCryptoOperationStreamer {
-    byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
-    byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
-            byte[] additionalEntropy) throws KeyStoreException;
-    long getConsumedInputSizeBytes();
-    long getProducedOutputSizeBytes();
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
deleted file mode 100644
index c82b6e6..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
+++ /dev/null
@@ -1,118 +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.security.keystore;
-
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.SecureRandom;
-
-/**
- * Assorted utility methods for implementing crypto operations on top of KeyStore.
- *
- * @hide
- */
-abstract class KeyStoreCryptoOperationUtils {
-
-    private static volatile SecureRandom sRng;
-
-    private KeyStoreCryptoOperationUtils() {}
-
-    /**
-     * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
-     * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
-     * the {@code init} method should succeed.
-     */
-    static InvalidKeyException getInvalidKeyExceptionForInit(
-            KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
-        if (beginOpResultCode == KeyStore.NO_ERROR) {
-            return null;
-        }
-
-        // An error occurred. However, some errors should not lead to init throwing an exception.
-        // See below.
-        InvalidKeyException e =
-                keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
-        switch (beginOpResultCode) {
-            case KeyStore.OP_AUTH_NEEDED:
-                // Operation needs to be authorized by authenticating the user. Don't throw an
-                // exception is such authentication is possible for this key
-                // (UserNotAuthenticatedException). An example of when it's not possible is where
-                // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
-                if (e instanceof UserNotAuthenticatedException) {
-                    return null;
-                }
-                break;
-        }
-        return e;
-    }
-
-    /**
-     * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
-     * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
-     * should succeed.
-     */
-    public static GeneralSecurityException getExceptionForCipherInit(
-            KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
-        if (beginOpResultCode == KeyStore.NO_ERROR) {
-            return null;
-        }
-
-        // Cipher-specific cases
-        switch (beginOpResultCode) {
-            case KeymasterDefs.KM_ERROR_INVALID_NONCE:
-                return new InvalidAlgorithmParameterException("Invalid IV");
-            case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
-                return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
-        }
-
-        // General cases
-        return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
-    }
-
-    /**
-     * Returns the requested number of random bytes to mix into keystore/keymaster RNG.
-     *
-     * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default
-     *        RNG.
-     */
-    static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) {
-        if (sizeBytes <= 0) {
-            return EmptyArray.BYTE;
-        }
-        if (rng == null) {
-            rng = getRng();
-        }
-        byte[] result = new byte[sizeBytes];
-        rng.nextBytes(result);
-        return result;
-    }
-
-    private static SecureRandom getRng() {
-        // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is
-        // required to be thread-safe.
-        if (sRng == null) {
-            sRng = new SecureRandom();
-        }
-        return sRng;
-    }
-}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
deleted file mode 100644
index 670ef5e..0000000
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ /dev/null
@@ -1,241 +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.security.keystore;
-
-import android.hardware.biometrics.BiometricManager;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.ProviderException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @hide
- */
-public abstract class KeymasterUtils {
-
-    private KeymasterUtils() {}
-
-    public static int getDigestOutputSizeBits(int keymasterDigest) {
-        switch (keymasterDigest) {
-            case KeymasterDefs.KM_DIGEST_NONE:
-                return -1;
-            case KeymasterDefs.KM_DIGEST_MD5:
-                return 128;
-            case KeymasterDefs.KM_DIGEST_SHA1:
-                return 160;
-            case KeymasterDefs.KM_DIGEST_SHA_2_224:
-                return 224;
-            case KeymasterDefs.KM_DIGEST_SHA_2_256:
-                return 256;
-            case KeymasterDefs.KM_DIGEST_SHA_2_384:
-                return 384;
-            case KeymasterDefs.KM_DIGEST_SHA_2_512:
-                return 512;
-            default:
-                throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
-        }
-    }
-
-    public static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
-            int keymasterBlockMode) {
-        switch (keymasterBlockMode) {
-            case KeymasterDefs.KM_MODE_ECB:
-                return false;
-            case KeymasterDefs.KM_MODE_CBC:
-            case KeymasterDefs.KM_MODE_CTR:
-            case KeymasterDefs.KM_MODE_GCM:
-                return true;
-            default:
-                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
-        }
-    }
-
-    public static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
-            int keymasterPadding) {
-        switch (keymasterPadding) {
-            case KeymasterDefs.KM_PAD_NONE:
-                return false;
-            case KeymasterDefs.KM_PAD_RSA_OAEP:
-            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
-                return true;
-            default:
-                throw new IllegalArgumentException(
-                        "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
-        }
-    }
-
-    private static void addSids(KeymasterArguments args, UserAuthArgs spec) {
-        // If both biometric and credential are accepted, then just use the root sid from gatekeeper
-        if (spec.getUserAuthenticationType() == (KeyProperties.AUTH_BIOMETRIC_STRONG
-                                                 | KeyProperties.AUTH_DEVICE_CREDENTIAL)) {
-            if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
-                args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
-                        KeymasterArguments.toUint64(spec.getBoundToSpecificSecureUserId()));
-            } else {
-                // The key is authorized for use for the specified amount of time after the user has
-                // authenticated. Whatever unlocks the secure lock screen should authorize this key.
-                args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
-                        KeymasterArguments.toUint64(getRootSid()));
-            }
-        } else {
-            List<Long> sids = new ArrayList<>();
-            if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_BIOMETRIC_STRONG) != 0) {
-                final BiometricManager bm = KeyStore.getApplicationContext()
-                        .getSystemService(BiometricManager.class);
-
-                // TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
-                // needed here.
-
-                final long[] biometricSids = bm.getAuthenticatorIds();
-
-                if (biometricSids.length == 0) {
-                    throw new IllegalStateException(
-                            "At least one biometric must be enrolled to create keys requiring user"
-                            + " authentication for every use");
-                }
-
-                if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
-                    sids.add(spec.getBoundToSpecificSecureUserId());
-                } else if (spec.isInvalidatedByBiometricEnrollment()) {
-                    // The biometric-only SIDs will change on biometric enrollment or removal of all
-                    // enrolled templates, invalidating the key.
-                    for (long sid : biometricSids) {
-                        sids.add(sid);
-                    }
-                } else {
-                    // The root SID will *not* change on fingerprint enrollment, or removal of all
-                    // enrolled fingerprints, allowing the key to remain valid.
-                    sids.add(getRootSid());
-                }
-            } else if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_DEVICE_CREDENTIAL)
-                            != 0) {
-                sids.add(getRootSid());
-            } else {
-                throw new IllegalStateException("Invalid or no authentication type specified.");
-            }
-
-            for (int i = 0; i < sids.size(); i++) {
-                args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
-                        KeymasterArguments.toUint64(sids.get(i)));
-            }
-        }
-    }
-
-    /**
-     * Adds keymaster arguments to express the key's authorization policy supported by user
-     * authentication.
-     *
-     * @param args The arguments sent to keymaster that need to be populated from the spec
-     * @param spec The user authentication relevant portions of the spec passed in from the caller.
-     *        This spec will be translated into the relevant keymaster tags to be loaded into args.
-     * @throws IllegalStateException if user authentication is required but the system is in a wrong
-     *         state (e.g., secure lock screen not set up) for generating or importing keys that
-     *         require user authentication.
-     */
-    public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
-
-        if (spec.isUserConfirmationRequired()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
-        }
-
-        if (spec.isUserPresenceRequired()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
-        }
-
-        if (spec.isUnlockedDeviceRequired()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
-        }
-
-        if (!spec.isUserAuthenticationRequired()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-            return;
-        }
-
-        if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
-            // Every use of this key needs to be authorized by the user.
-            addSids(args, spec);
-            args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
-
-            if (spec.isUserAuthenticationValidWhileOnBody()) {
-                throw new ProviderException("Key validity extension while device is on-body is not "
-                        + "supported for keys requiring fingerprint authentication");
-            }
-        } else {
-            addSids(args, spec);
-            args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
-            args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
-                    spec.getUserAuthenticationValidityDurationSeconds());
-            if (spec.isUserAuthenticationValidWhileOnBody()) {
-                args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
-            }
-        }
-    }
-
-    /**
-     * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
-     * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
-     * AES-GCM).
-     */
-    public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
-            int keymasterAlgorithm,
-            int[] keymasterBlockModes,
-            int[] keymasterDigests) {
-        switch (keymasterAlgorithm) {
-            case KeymasterDefs.KM_ALGORITHM_AES:
-                if (com.android.internal.util.ArrayUtils.contains(
-                        keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
-                    // AES GCM key needs the minimum length of AEAD tag specified.
-                    args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
-                            AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
-                                    .MIN_SUPPORTED_TAG_LENGTH_BITS);
-                }
-                break;
-            case KeymasterDefs.KM_ALGORITHM_HMAC:
-                // HMAC key needs the minimum length of MAC set to the output size of the associated
-                // digest. This is because we do not offer a way to generate shorter MACs and
-                // don't offer a way to verify MACs (other than by generating them).
-                if (keymasterDigests.length != 1) {
-                    throw new ProviderException(
-                            "Unsupported number of authorized digests for HMAC key: "
-                                    + keymasterDigests.length
-                                    + ". Exactly one digest must be authorized");
-                }
-                int keymasterDigest = keymasterDigests[0];
-                int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
-                if (digestOutputSizeBits == -1) {
-                    throw new ProviderException(
-                            "HMAC key authorized for unsupported digest: "
-                                    + KeyProperties.Digest.fromKeymaster(keymasterDigest));
-                }
-                args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
-                break;
-        }
-    }
-
-    private static long getRootSid() {
-        long rootSid = GateKeeper.getSecureUserId();
-        if (rootSid == 0) {
-            throw new IllegalStateException("Secure lock screen must be enabled"
-                    + " to create keys requiring user authentication");
-        }
-        return rootSid;
-    }
-}
diff --git a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
index d1cc572..c1842b4 100644
--- a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
+++ b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
@@ -16,8 +16,8 @@
 
 package android.security.keystore;
 
-import android.security.KeyStore;
 import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
 
 import java.security.ProviderException;
 
@@ -31,7 +31,7 @@
     }
 
     public SecureKeyImportUnavailableException(String message) {
-        super(message, new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE,
+        super(message, new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
                 "Secure Key Import not available"));
     }
 
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index 6c7e9a9..1f4e12e 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -16,8 +16,8 @@
 
 package android.security.keystore;
 
-import android.security.KeyStore;
 import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
 
 import java.security.ProviderException;
 
@@ -33,7 +33,8 @@
 
     public StrongBoxUnavailableException(String message) {
         super(message,
-                new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
+                new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
+                        "No StrongBox available")
         );
     }
 
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index 0f77749..268b15b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -21,7 +21,6 @@
 import android.security.KeyStoreOperation;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyStoreCryptoOperation;
-import android.security.keystore.KeymasterUtils;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 1575bb4..f1681ec 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -20,12 +20,10 @@
 import android.hardware.security.keymint.SecurityLevel;
 import android.security.KeyStore2;
 import android.security.KeyStoreSecurityLevel;
-import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.ArrayUtils;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
 import android.security.keystore.StrongBoxUnavailableException;
 import android.system.keystore2.Domain;
 import android.system.keystore2.IKeystoreSecurityLevel;
@@ -259,7 +257,7 @@
                 // Check that user authentication related parameters are acceptable. This method
                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
                 // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
+                KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), spec);
             } catch (IllegalStateException | IllegalArgumentException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 2d8901a..c26d9f5 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.content.Context;
 import android.hardware.security.keymint.KeyParameter;
 import android.hardware.security.keymint.KeyPurpose;
@@ -28,7 +29,6 @@
 import android.security.GenerateRkpKey;
 import android.security.GenerateRkpKeyException;
 import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
 import android.security.KeyStore2;
 import android.security.KeyStoreException;
 import android.security.KeyStoreSecurityLevel;
@@ -39,7 +39,6 @@
 import android.security.keystore.DeviceIdAttestationException;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
 import android.security.keystore.SecureKeyImportUnavailableException;
 import android.security.keystore.StrongBoxUnavailableException;
 import android.system.keystore2.Authorization;
@@ -270,7 +269,7 @@
                 // Check that user authentication related parameters are acceptable. This method
                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
                 // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
+                KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), mSpec);
             } catch (IllegalArgumentException | IllegalStateException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -572,7 +571,8 @@
             AndroidKeyStorePublicKey publicKey =
                     AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
                             descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
-            GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+            GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+                    .currentApplication());
             try {
                 if (mSpec.getAttestationChallenge() != null) {
                     keyGen.notifyKeyGenerated(securityLevel);
@@ -589,7 +589,8 @@
                 case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
                     throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
                 case ResponseCode.OUT_OF_KEYS:
-                    GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+                    GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+                            .currentApplication());
                     try {
                         keyGen.notifyEmpty(securityLevel);
                     } catch (RemoteException f) {
@@ -665,8 +666,8 @@
             if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
                     || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
                 telephonyService =
-                    (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
-                        Context.TELEPHONY_SERVICE);
+                    (TelephonyManager) android.app.AppGlobals.getInitialApplication()
+                            .getSystemService(Context.TELEPHONY_SERVICE);
                 if (telephonyService == null) {
                     throw new DeviceIdAttestationException("Unable to access telephony service");
                 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index ba6d22f..89d2b74 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -110,23 +110,6 @@
         putSecretKeyFactoryImpl("HmacSHA512");
     }
 
-    private static boolean sInstalled = false;
-
-    /**
-     * This function indicates whether or not this provider was installed. This is manly used
-     * as indicator for
-     * {@link android.security.keystore.AndroidKeyStoreProvider#getKeyStoreForUid(int)}
-     * to whether or not to retrieve the Keystore provider by "AndroidKeyStoreLegacy".
-     * This function can be removed once the transition to Keystore 2.0 is complete.
-     * b/171305684
-     *
-     * @return true if this provider was installed.
-     * @hide
-     */
-    public static boolean isInstalled() {
-        return sInstalled;
-    }
-
     /**
      * Installs a new instance of this provider (and the
      * {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -142,7 +125,6 @@
                 break;
             }
         }
-        sInstalled = true;
 
         Security.addProvider(new AndroidKeyStoreProvider());
         Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 6ff9432..5848247 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -21,7 +21,6 @@
 import android.hardware.security.keymint.KeyParameter;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
 import android.system.keystore2.Authorization;
 
 import java.security.AlgorithmParameters;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 32f98a2..3e2fb94 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -30,7 +30,6 @@
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
-import android.security.keystore.KeymasterUtils;
 import android.security.keystore.SecureKeyImportUnavailableException;
 import android.security.keystore.WrappedKeyEntry;
 import android.system.keystore2.AuthenticatorSpec;
diff --git a/keystore/java/android/security/keystore2/KeymasterUtils.java b/keystore/java/android/security/keystore2/KeymasterUtils.java
new file mode 100644
index 0000000..de4696c
--- /dev/null
+++ b/keystore/java/android/security/keystore2/KeymasterUtils.java
@@ -0,0 +1,124 @@
+/*
+ * 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.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyProperties;
+
+import java.security.ProviderException;
+
+/**
+ * @hide
+ */
+public abstract class KeymasterUtils {
+
+    private KeymasterUtils() {}
+
+    /** @hide */
+    static int getDigestOutputSizeBits(int keymasterDigest) {
+        switch (keymasterDigest) {
+            case KeymasterDefs.KM_DIGEST_NONE:
+                return -1;
+            case KeymasterDefs.KM_DIGEST_MD5:
+                return 128;
+            case KeymasterDefs.KM_DIGEST_SHA1:
+                return 160;
+            case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                return 224;
+            case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                return 256;
+            case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                return 384;
+            case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                return 512;
+            default:
+                throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+        }
+    }
+
+    /** @hide */
+    static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
+            int keymasterBlockMode) {
+        switch (keymasterBlockMode) {
+            case KeymasterDefs.KM_MODE_ECB:
+                return false;
+            case KeymasterDefs.KM_MODE_CBC:
+            case KeymasterDefs.KM_MODE_CTR:
+            case KeymasterDefs.KM_MODE_GCM:
+                return true;
+            default:
+                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+        }
+    }
+
+    /** @hide */
+    static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
+            int keymasterPadding) {
+        switch (keymasterPadding) {
+            case KeymasterDefs.KM_PAD_NONE:
+                return false;
+            case KeymasterDefs.KM_PAD_RSA_OAEP:
+            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+                return true;
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
+        }
+    }
+
+    /**
+     * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
+     * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
+     * AES-GCM).
+     */
+    public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
+            int keymasterAlgorithm,
+            int[] keymasterBlockModes,
+            int[] keymasterDigests) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_AES:
+                if (com.android.internal.util.ArrayUtils.contains(
+                        keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
+                    // AES GCM key needs the minimum length of AEAD tag specified.
+                    args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+                            AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+                                    .MIN_SUPPORTED_TAG_LENGTH_BITS);
+                }
+                break;
+            case KeymasterDefs.KM_ALGORITHM_HMAC:
+                // HMAC key needs the minimum length of MAC set to the output size of the associated
+                // digest. This is because we do not offer a way to generate shorter MACs and
+                // don't offer a way to verify MACs (other than by generating them).
+                if (keymasterDigests.length != 1) {
+                    throw new ProviderException(
+                            "Unsupported number of authorized digests for HMAC key: "
+                                    + keymasterDigests.length
+                                    + ". Exactly one digest must be authorized");
+                }
+                int keymasterDigest = keymasterDigests[0];
+                int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
+                if (digestOutputSizeBits == -1) {
+                    throw new ProviderException(
+                            "HMAC key authorized for unsupported digest: "
+                                    + KeyProperties.Digest.fromKeymaster(keymasterDigest));
+                }
+                args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
+                break;
+        }
+    }
+}
diff --git a/location/java/Android.bp b/location/java/Android.bp
new file mode 100644
index 0000000..543f2b1
--- /dev/null
+++ b/location/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-location-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/lowpan/java/Android.bp b/lowpan/java/Android.bp
new file mode 100644
index 0000000..58513d7
--- /dev/null
+++ b/lowpan/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-lowpan-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/media/java/Android.bp b/media/java/Android.bp
index aea63a0..eeaf6e9 100644
--- a/media/java/Android.bp
+++ b/media/java/Android.bp
@@ -8,6 +8,18 @@
 }
 
 filegroup {
+    name: "framework-media-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    exclude_srcs: [
+        ":framework-media-tv-tunerresourcemanager-sources-aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+filegroup {
     name: "IMidiDeviceServer.aidl",
     srcs: ["android/media/midi/IMidiDeviceServer.aidl"],
 }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 7062f83..5633236 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -4412,14 +4412,25 @@
 
         int i = 0;
         for (final String key: params.keySet()) {
-            keys[i] = key;
-            Object value = params.get(key);
-
-            // Bundle's byte array is a byte[], JNI layer only takes ByteBuffer
-            if (value instanceof byte[]) {
-                values[i] = ByteBuffer.wrap((byte[])value);
+            if (key.equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
+                int sessionId = 0;
+                try {
+                    sessionId = (Integer)params.get(key);
+                } catch (Exception e) {
+                    throw new IllegalArgumentException("Wrong Session ID Parameter!");
+                }
+                keys[i] = "audio-hw-sync";
+                values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
             } else {
-                values[i] = value;
+                keys[i] = key;
+                Object value = params.get(key);
+
+                // Bundle's byte array is a byte[], JNI layer only takes ByteBuffer
+                if (value instanceof byte[]) {
+                    values[i] = ByteBuffer.wrap((byte[])value);
+                } else {
+                    values[i] = value;
+                }
             }
             ++i;
         }
diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp
index 66c7bd4..e365ee1 100644
--- a/media/java/android/media/tv/tunerresourcemanager/Android.bp
+++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp
@@ -6,6 +6,12 @@
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_base_license"],
 }
+filegroup {
+    // NOTE: This is purposefully left empty, and exists only so that it can be
+    // referenced in frameworks/base/Android.bp.
+    name: "framework-media-tv-tunerresourcemanager-sources-aidl",
+    srcs: [],
+}
 
 filegroup {
     name: "framework-media-tv-tunerresourcemanager-sources",
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index ed56b43..9fe700a 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -821,8 +821,10 @@
             ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteStream);
 
-            if (byteStream.size() > MAX_THUMB_SIZE)
+            if (byteStream.size() > MAX_THUMB_SIZE) {
+                Log.w(TAG, "getThumbnailProcess: size=" + byteStream.size());
                 return null;
+            }
 
             byte[] byteArray = byteStream.toByteArray();
 
@@ -852,7 +854,15 @@
                     outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0;
                     outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0);
                     outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0);
-                    return true;
+                    if (exif.getThumbnailRange() != null) {
+                        if ((outLongs[0] == 0) || (outLongs[1] == 0) || (outLongs[2] == 0)) {
+                            Log.d(TAG, "getThumbnailInfo: check thumb info:"
+                                    + thumbOffsetAndSize[0] + "," + thumbOffsetAndSize[1]
+                                    + "," + outLongs[1] + "," + outLongs[2]);
+                        }
+
+                        return true;
+                    }
                 } catch (IOException e) {
                     // ignore and fall through
                 }
@@ -885,7 +895,9 @@
             case MtpConstants.FORMAT_JFIF:
                 try {
                     ExifInterface exif = new ExifInterface(path);
-                    return exif.getThumbnail();
+
+                    if (exif.getThumbnailRange() != null)
+                        return exif.getThumbnail();
                 } catch (IOException e) {
                     // ignore and fall through
                 }
diff --git a/media/mca/effect/java/Android.bp b/media/mca/effect/java/Android.bp
new file mode 100644
index 0000000..70d999f
--- /dev/null
+++ b/media/mca/effect/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-mca-effect-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/media/mca/filterfw/java/Android.bp b/media/mca/filterfw/java/Android.bp
new file mode 100644
index 0000000..77afcff
--- /dev/null
+++ b/media/mca/filterfw/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-mca-filterfw-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/media/mca/filterpacks/java/Android.bp b/media/mca/filterpacks/java/Android.bp
new file mode 100644
index 0000000..f370b21
--- /dev/null
+++ b/media/mca/filterpacks/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-mca-filterpacks-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/media/tests/MtpTests/res/raw/test_bad_thumb.jpg b/media/tests/MtpTests/res/raw/test_bad_thumb.jpg
index e69de29..78ac703 100644
--- a/media/tests/MtpTests/res/raw/test_bad_thumb.jpg
+++ b/media/tests/MtpTests/res/raw/test_bad_thumb.jpg
Binary files differ
diff --git a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
index e2e8ff4..0bf99cf 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
@@ -271,9 +271,10 @@
 
         Log.d(TAG, "testMtpDatabaseThumbnail: Test bad JPG");
 
-        testThumbnail(handleJpgBadThumb, jpgfileBadThumb, false);
+// Now we support to generate thumbnail if embedded thumbnail is corrupted or not existed
+        testThumbnail(handleJpgBadThumb, jpgfileBadThumb, true);
 
-        testThumbnail(handleJpgNoThumb, jpgFileNoThumb, false);
+        testThumbnail(handleJpgNoThumb, jpgFileNoThumb, true);
 
         testThumbnail(handleJpgBad, jpgfileBad, false);
 
diff --git a/mime/java/Android.bp b/mime/java/Android.bp
new file mode 100644
index 0000000..07cada8e
--- /dev/null
+++ b/mime/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-mime-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/mms/java/Android.bp b/mms/java/Android.bp
new file mode 100644
index 0000000..4d51439
--- /dev/null
+++ b/mms/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-mms-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/native/android/OWNERS b/native/android/OWNERS
index d414ed4..02dfd39 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,4 +1,16 @@
+jreck@google.com
+
 per-file libandroid_net.map.txt, net.c = set noparent
 per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
 per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
 per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS
+
+per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+
+per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file hardware_buffer_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file native_window_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_control.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_texture.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/opengl/java/Android.bp b/opengl/java/Android.bp
new file mode 100644
index 0000000..6dbae42
--- /dev/null
+++ b/opengl/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-opengl-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 550e324..10d68ba 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -50,7 +50,7 @@
 import android.widget.TextView;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -238,7 +238,7 @@
                 HttpURLConnection urlConnection = null;
                 int httpResponseCode = 500;
                 int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                        TrafficStatsConstants.TAG_SYSTEM_PROBE);
+                        NetworkStackConstants.TAG_SYSTEM_PROBE);
                 try {
                     urlConnection = (HttpURLConnection) mNetwork.openConnection(
                             new URL(mCm.getCaptivePortalServerUrl()));
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
index 0d70f2a..3495efc 100644
--- a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
+++ b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
@@ -18,5 +18,5 @@
 package android.net;
 
 // @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
-@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// build rule).
+@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index ad44b27..ab290f9 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -68,6 +68,7 @@
     method public boolean bindProcessToNetwork(@Nullable android.net.Network);
     method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
@@ -297,7 +298,6 @@
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
     method public int getOwnerUid();
     method public int getSignalStrength();
-    method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
     method @Nullable public android.net.TransportInfo getTransportInfo();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
@@ -387,7 +387,9 @@
   public class NetworkRequest implements android.os.Parcelable {
     method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
     method public int describeContents();
+    method @NonNull public int[] getCapabilities();
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+    method @NonNull public int[] getTransportTypes();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -405,7 +407,6 @@
     method public android.net.NetworkRequest.Builder removeTransportType(int);
     method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
     method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
-    method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
   }
 
   public class ParseException extends java.lang.RuntimeException {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index ac69a3e..8dfdd614 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -20,17 +20,24 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+    method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
     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);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
     method public void systemReady();
+    field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
+    field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
+    field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+    field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
     field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
     field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+    field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
     field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
     field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
     field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
     field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+    field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
     field public static final int BLOCKED_REASON_NONE = 0; // 0x0
     field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
     field public static final String PRIVATE_DNS_MODE_OFF = "off";
@@ -40,6 +47,56 @@
     field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
   }
 
+  public static class ConnectivityManager.NetworkCallback {
+    method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
+  }
+
+  public class ConnectivitySettingsManager {
+    method public static void clearGlobalProxy(@NonNull android.content.Context);
+    method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
+    method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
+    method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
+    method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
+    method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
+    method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+    method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
+    method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
+    method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
+    method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
+    method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
+    method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+    method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+    method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
+    method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
+    method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
+    method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
+    method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
+    method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+    method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
+    method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
+    method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
+    method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
+    method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+    method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
+    method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+    method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+    method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+    field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+    field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+    field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+    field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
+    field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
+    field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
+  }
+
   public final class NetworkAgentConfig implements android.os.Parcelable {
     method @Nullable public String getSubscriberId();
     method public boolean isBypassableVpn();
@@ -51,7 +108,6 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
     method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
     method public boolean hasUnwantedCapability(int);
     field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
@@ -67,6 +123,7 @@
   }
 
   public class NetworkRequest implements android.os.Parcelable {
+    method @NonNull public int[] getUnwantedCapabilities();
     method public boolean hasUnwantedCapability(int);
   }
 
@@ -122,10 +179,12 @@
   }
 
   public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
-    ctor public VpnTransportInfo(int);
+    ctor public VpnTransportInfo(int, @Nullable String);
     method public int describeContents();
+    method @NonNull public android.net.VpnTransportInfo makeCopy(long);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+    field @Nullable public final String sessionId;
     field public final int type;
   }
 
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 8e6e846..0a82cb7 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -217,7 +217,9 @@
     method public void markConnected();
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
     method public void onAutomaticReconnectDisabled();
+    method public void onBandwidthUpdateRequested();
     method public void onNetworkCreated();
+    method public void onNetworkDestroyed();
     method public void onNetworkUnwanted();
     method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
     method public void onQosCallbackUnregistered(int);
@@ -235,6 +237,8 @@
     method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
     method public final void sendQosSessionLost(int, int, int);
     method public final void sendSocketKeepaliveEvent(int, int);
+    method @Deprecated public void setLegacySubtype(int, @NonNull String);
+    method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int);
     method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
     method public void unregister();
     field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
@@ -255,7 +259,12 @@
   public static final class NetworkAgentConfig.Builder {
     ctor public NetworkAgentConfig.Builder();
     method @NonNull public android.net.NetworkAgentConfig build();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
     method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
@@ -264,15 +273,19 @@
 
   public final class NetworkCapabilities implements android.os.Parcelable {
     method @NonNull public int[] getAdministratorUids();
+    method @Nullable public static String getCapabilityCarrierName(int);
     method @Nullable public String getSsid();
+    method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
     method @NonNull public int[] getTransportTypes();
     method public boolean isPrivateDnsBroken();
     method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+    field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
     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
     field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+    field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
   }
 
   public static final class NetworkCapabilities.Builder {
@@ -316,6 +329,7 @@
 
   public static class NetworkRequest.Builder {
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+    method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
   }
 
   public final class NetworkScore implements android.os.Parcelable {
@@ -404,6 +418,7 @@
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
     field public static final int SUCCESS = 0; // 0x0
   }
 
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index bc668f3..9fbf049 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -38,7 +38,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -423,7 +425,8 @@
      *
      * @hide
      */
-    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
 
     /**
      * Action used to display a dialog that asks the user whether to avoid a network that is no
@@ -431,8 +434,9 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_LOST_VALIDATION =
-            "android.net.conn.PROMPT_LOST_VALIDATION";
+            "android.net.action.PROMPT_LOST_VALIDATION";
 
     /**
      * Action used to display a dialog that asks the user whether to stay connected to a network
@@ -441,8 +445,18 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
-            "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY";
+            "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+
+    /**
+     * Clear DNS Cache Action: This is broadcast when networks have changed and old
+     * DNS entries should be cleared.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
 
     /**
      * Invalid tethering type.
@@ -872,6 +886,17 @@
     public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
 
     /**
+     * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
+     * is not currently connected.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
+
+    /**
      * Flag to indicate that an app is subject to Data saver restrictions that would
      * result in its metered network access being blocked.
      *
@@ -908,12 +933,21 @@
             BLOCKED_REASON_DOZE,
             BLOCKED_REASON_APP_STANDBY,
             BLOCKED_REASON_RESTRICTED_MODE,
+            BLOCKED_REASON_LOCKDOWN_VPN,
             BLOCKED_METERED_REASON_DATA_SAVER,
             BLOCKED_METERED_REASON_USER_RESTRICTED,
             BLOCKED_METERED_REASON_ADMIN_DISABLED,
     })
     public @interface BlockedReason {}
 
+    /**
+     * Set of blocked reasons that are only applicable on metered networks.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     private final IConnectivityManager mService;
 
@@ -1168,8 +1202,7 @@
      *
      * @return a {@link Network} object for the current default network for the
      *         given UID or {@code null} if no default network is currently active
-     *
-     * @hide
+     * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     @Nullable
@@ -3119,18 +3152,27 @@
     }
 
     /**
-     * Set a network-independent global http proxy.  This is not normally what you want
-     * for typical HTTP proxies - they are general network dependent.  However if you're
-     * doing something unusual like general internal filtering this may be useful.  On
-     * a private network where the proxy is not accessible, you may break HTTP using this.
+     * Set a network-independent global HTTP proxy.
      *
-     * @param p A {@link ProxyInfo} object defining the new global
-     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
+     * This sets an HTTP proxy that applies to all networks and overrides any network-specific
+     * proxy. If set, HTTP libraries that are proxy-aware will use this global proxy when
+     * accessing any network, regardless of what the settings for that network are.
+     *
+     * Note that HTTP proxies are by nature typically network-dependent, and setting a global
+     * proxy is likely to break networking on multiple networks. This method is only meant
+     * for device policy clients looking to do general internal filtering or similar use cases.
+     *
+     * {@see #getGlobalProxy}
+     * {@see LinkProperties#getHttpProxy}
+     *
+     * @param p A {@link ProxyInfo} object defining the new global HTTP proxy. Calling this
+     *          method with a {@code null} value will clear the global HTTP proxy.
      * @hide
      */
+    // Used by Device Policy Manager to set the global proxy.
     @SystemApi(client = MODULE_LIBRARIES)
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-    public void setGlobalProxy(@Nullable ProxyInfo p) {
+    public void setGlobalProxy(@Nullable final ProxyInfo p) {
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
@@ -3388,6 +3430,8 @@
          * not include location sensitive info.
          * </p>
          */
+        // Note: Some existing fields which are location sensitive may still be included without
+        // this flag if the app targets SDK < S (to maintain backwards compatibility).
         public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
 
         /** @hide */
@@ -3442,12 +3486,30 @@
          * @param blocked Whether access to the {@link Network} is blocked due to system policy.
          * @hide
          */
-        public void onAvailable(@NonNull Network network,
+        public final void onAvailable(@NonNull Network network,
                 @NonNull NetworkCapabilities networkCapabilities,
-                @NonNull LinkProperties linkProperties, boolean blocked) {
+                @NonNull LinkProperties linkProperties, @BlockedReason int blocked) {
             // Internally only this method is called when a new network is available, and
             // it calls the callback in the same way and order that older versions used
             // to call so as not to change the behavior.
+            onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
+            onBlockedStatusChanged(network, blocked);
+        }
+
+        /**
+         * Legacy variant of onAvailable that takes a boolean blocked reason.
+         *
+         * This method has never been public API, but it's not final, so there may be apps that
+         * implemented it and rely on it being called. Do our best not to break them.
+         * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
+         * this method is called. There does not seem to be a way to avoid this.
+         * TODO: add a compat check to move apps off this method, and eventually stop calling it.
+         *
+         * @hide
+         */
+        public void onAvailable(@NonNull Network network,
+                @NonNull NetworkCapabilities networkCapabilities,
+                @NonNull LinkProperties linkProperties, boolean blocked) {
             onAvailable(network);
             if (!networkCapabilities.hasCapability(
                     NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -3455,7 +3517,7 @@
             }
             onCapabilitiesChanged(network, networkCapabilities);
             onLinkPropertiesChanged(network, linkProperties);
-            onBlockedStatusChanged(network, blocked);
+            // No call to onBlockedStatusChanged here. That is done by the caller.
         }
 
         /**
@@ -3619,6 +3681,27 @@
          */
         public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
 
+        /**
+         * Called when access to the specified network is blocked or unblocked, or the reason for
+         * access being blocked changes.
+         *
+         * If a NetworkCallback object implements this method,
+         * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
+         *
+         * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+         * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+         * this callback as this is prone to race conditions : calling these methods while in a
+         * callback may return an outdated or even a null object.
+         *
+         * @param network The {@link Network} whose blocked status has changed.
+         * @param blocked The blocked status of this {@link Network}.
+         * @hide
+         */
+        @SystemApi(client = MODULE_LIBRARIES)
+        public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
+            onBlockedStatusChanged(network, blocked != 0);
+        }
+
         private NetworkRequest networkRequest;
         private final int mFlags;
     }
@@ -3733,7 +3816,7 @@
                 case CALLBACK_AVAILABLE: {
                     NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
                     LinkProperties lp = getObject(message, LinkProperties.class);
-                    callback.onAvailable(network, cap, lp, message.arg1 != 0);
+                    callback.onAvailable(network, cap, lp, message.arg1);
                     break;
                 }
                 case CALLBACK_LOSING: {
@@ -3767,8 +3850,7 @@
                     break;
                 }
                 case CALLBACK_BLK_CHANGED: {
-                    boolean blocked = message.arg1 != 0;
-                    callback.onBlockedStatusChanged(network, blocked);
+                    callback.onBlockedStatusChanged(network, message.arg1);
                 }
             }
         }
@@ -5371,4 +5453,23 @@
         if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
         return mode;
     }
+
+    /**
+     * Set private DNS mode to settings.
+     *
+     * @param context The {@link Context} to set the private DNS mode.
+     * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static void setPrivateDnsMode(@NonNull Context context,
+            @NonNull @PrivateDnsMode String mode) {
+        if (!(mode == PRIVATE_DNS_MODE_OFF
+                || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+                || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+            throw new IllegalArgumentException("Invalid private dns mode");
+        }
+        Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
index bbd8393..9a00055 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -16,16 +16,38 @@
 
 package android.net;
 
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.ConnectivityManager.MultipathPreference;
+import android.net.ConnectivityManager.PrivateDnsMode;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Range;
+
+import com.android.net.module.util.ProxyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.util.List;
 
 /**
  * A manager class for connectivity module settings.
  *
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public class ConnectivitySettingsManager {
 
     private ConnectivitySettingsManager() {}
@@ -45,12 +67,16 @@
      * Network activity refers to transmitting or receiving data on the network interfaces.
      *
      * Tracking is disabled if set to zero or negative value.
+     *
+     * @hide
      */
     public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
 
     /**
      * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
      * but for Wifi network.
+     *
+     * @hide
      */
     public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
 
@@ -58,12 +84,16 @@
 
     /**
      * Sample validity in seconds to configure for the system DNS resolver.
+     *
+     * @hide
      */
     public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
             "dns_resolver_sample_validity_seconds";
 
     /**
      * Success threshold in percent for use with the system DNS resolver.
+     *
+     * @hide
      */
     public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
             "dns_resolver_success_threshold_percent";
@@ -71,24 +101,35 @@
     /**
      * Minimum number of samples needed for statistics to be considered meaningful in the
      * system DNS resolver.
+     *
+     * @hide
      */
     public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
 
     /**
      * Maximum number taken into account for statistics purposes in the system DNS resolver.
+     *
+     * @hide
      */
     public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
 
+    private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+    private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
     /** Network switch notification settings */
 
     /**
      * The maximum number of notifications shown in 24 hours when switching networks.
+     *
+     * @hide
      */
     public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
             "network_switch_notification_daily_limit";
 
     /**
      * The minimum time in milliseconds between notifications when switching networks.
+     *
+     * @hide
      */
     public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
             "network_switch_notification_rate_limit_millis";
@@ -98,14 +139,18 @@
     /**
      * The URL used for HTTP captive portal detection upon a new connection.
      * A 204 response code from the server is used for validation.
+     *
+     * @hide
      */
     public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
 
     /**
      * What to do when connecting a network that presents a captive portal.
-     * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
+     * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
      *
      * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+     *
+     * @hide
      */
     public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
 
@@ -139,11 +184,15 @@
 
     /**
      * Host name for global http proxy. Set via ConnectivityManager.
+     *
+     * @hide
      */
     public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
 
     /**
      * Integer host port for global http proxy. Set via ConnectivityManager.
+     *
+     * @hide
      */
     public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
 
@@ -153,12 +202,16 @@
      * Domains should be listed in a comma- separated list. Example of
      * acceptable formats: ".domain1.com,my.domain2.com" Use
      * ConnectivityManager to set/get.
+     *
+     * @hide
      */
     public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
             "global_http_proxy_exclusion_list";
 
     /**
      * The location PAC File for the proxy.
+     *
+     * @hide
      */
     public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
 
@@ -171,11 +224,15 @@
      * a specific provider. It may be used to store the provider name even when the
      * mode changes so that temporarily disabling and re-enabling the specific
      * provider mode does not necessitate retyping the provider hostname.
+     *
+     * @hide
      */
     public static final String PRIVATE_DNS_MODE = "private_dns_mode";
 
     /**
      * The specific Private DNS provider name.
+     *
+     * @hide
      */
     public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
 
@@ -185,6 +242,8 @@
      * all of which require explicit user action to enable/configure. See also b/79719289.
      *
      * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+     *
+     * @hide
      */
     public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
 
@@ -194,6 +253,8 @@
      * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
      * the receivers of the PendingIntent an opportunity to make a new network request before
      * the Network satisfying the request is potentially removed.
+     *
+     * @hide
      */
     public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
             "connectivity_release_pending_intent_delay_ms";
@@ -205,6 +266,8 @@
      * See ConnectivityService for more info.
      *
      * (0 = disabled, 1 = enabled)
+     *
+     * @hide
      */
     public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
 
@@ -217,6 +280,8 @@
      * See ConnectivityService for more info.
      *
      * (0 = disabled, 1 = enabled)
+     *
+     * @hide
      */
     public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
 
@@ -228,14 +293,637 @@
      * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
      * null: Ask the user whether to switch away from bad wifi.
      * 1: Avoid bad wifi.
+     *
+     * @hide
      */
     public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
 
     /**
+     * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+     */
+    public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
+
+    /**
+     * Ask the user whether to switch away from bad wifi.
+     */
+    public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
+
+    /**
+     * Avoid bad wifi.
+     */
+    public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            NETWORK_AVOID_BAD_WIFI_IGNORE,
+            NETWORK_AVOID_BAD_WIFI_PROMPT,
+            NETWORK_AVOID_BAD_WIFI_AVOID,
+    })
+    public @interface NetworkAvoidBadWifi {}
+
+    /**
      * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
      * overridden by the system based on device or application state. If null, the value
      * specified by config_networkMeteredMultipathPreference is used.
+     *
+     * @hide
      */
     public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
             "network_metered_multipath_preference";
+
+    /**
+     * A list of apps that should go on cellular networks in preference even when higher-priority
+     * networks are connected.
+     *
+     * @hide
+     */
+    public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
+
+    /**
+     * Get mobile data activity timeout from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default timeout if no setting value.
+     * @return The {@link Duration} of timeout to track mobile data activity.
+     */
+    @NonNull
+    public static Duration getMobileDataActivityTimeout(@NonNull Context context,
+            @NonNull Duration def) {
+        final int timeout = Settings.Global.getInt(
+                context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
+        return Duration.ofSeconds(timeout);
+    }
+
+    /**
+     * Set mobile data activity timeout to {@link Settings}.
+     * Tracking is disabled if set to zero or negative value.
+     *
+     * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+     * ignored.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param timeout The mobile data activity timeout.
+     */
+    public static void setMobileDataActivityTimeout(@NonNull Context context,
+            @NonNull Duration timeout) {
+        Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
+                (int) timeout.getSeconds());
+    }
+
+    /**
+     * Get wifi data activity timeout from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default timeout if no setting value.
+     * @return The {@link Duration} of timeout to track wifi data activity.
+     */
+    @NonNull
+    public static Duration getWifiDataActivityTimeout(@NonNull Context context,
+            @NonNull Duration def) {
+        final int timeout = Settings.Global.getInt(
+                context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
+        return Duration.ofSeconds(timeout);
+    }
+
+    /**
+     * Set wifi data activity timeout to {@link Settings}.
+     * Tracking is disabled if set to zero or negative value.
+     *
+     * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+     * ignored.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param timeout The wifi data activity timeout.
+     */
+    public static void setWifiDataActivityTimeout(@NonNull Context context,
+            @NonNull Duration timeout) {
+        Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
+                (int) timeout.getSeconds());
+    }
+
+    /**
+     * Get dns resolver sample validity duration from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default duration if no setting value.
+     * @return The {@link Duration} of sample validity duration to configure for the system DNS
+     *         resolver.
+     */
+    @NonNull
+    public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
+            @NonNull Duration def) {
+        final int duration = Settings.Global.getInt(context.getContentResolver(),
+                DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
+        return Duration.ofSeconds(duration);
+    }
+
+    /**
+     * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
+     * positive number of seconds.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param duration The sample validity duration.
+     */
+    public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
+            @NonNull Duration duration) {
+        final int time = (int) duration.getSeconds();
+        if (time <= 0) {
+            throw new IllegalArgumentException("Invalid duration");
+        }
+        Settings.Global.putInt(
+                context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
+    }
+
+    /**
+     * Get dns resolver success threshold percent from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default value if no setting value.
+     * @return The success threshold in percent for use with the system DNS resolver.
+     */
+    public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
+        return Settings.Global.getInt(
+                context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
+    }
+
+    /**
+     * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
+     * be 0~100.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param percent The success threshold percent.
+     */
+    public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
+            @IntRange(from = 0, to = 100) int percent) {
+        if (percent < 0 || percent > 100) {
+            throw new IllegalArgumentException("Percent must be 0~100");
+        }
+        Settings.Global.putInt(
+                context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
+    }
+
+    /**
+     * Get dns resolver samples range from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The {@link Range<Integer>} of samples needed for statistics to be considered
+     *         meaningful in the system DNS resolver.
+     */
+    @NonNull
+    public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
+        final int minSamples = Settings.Global.getInt(context.getContentResolver(),
+                DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+        final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
+                DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+        return new Range<>(minSamples, maxSamples);
+    }
+
+    /**
+     * Set dns resolver samples range to {@link Settings}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param range The samples range. The minimum number should be more than 0 and the maximum
+     *              number should be less that 64.
+     */
+    public static void setDnsResolverSampleRanges(@NonNull Context context,
+            @NonNull Range<Integer> range) {
+        if (range.getLower() < 0 || range.getUpper() > 64) {
+            throw new IllegalArgumentException("Argument must be 0~64");
+        }
+        Settings.Global.putInt(
+                context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
+        Settings.Global.putInt(
+                context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
+    }
+
+    /**
+     * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
+     * hours.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default value if no setting value.
+     * @return The maximum count of notifications shown in 24 hours when switching networks.
+     */
+    public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+            int def) {
+        return Settings.Global.getInt(
+                context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
+    }
+
+    /**
+     * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
+     * The count must be at least 0.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param count The maximum count of switching network notifications shown in 24 hours.
+     */
+    public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+            @IntRange(from = 0) int count) {
+        if (count < 0) {
+            throw new IllegalArgumentException("Count must be 0~10.");
+        }
+        Settings.Global.putInt(
+                context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
+    }
+
+    /**
+     * Get minimum duration (from {@link Settings}) between each switching network notifications.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default time if no setting value.
+     * @return The minimum duration between notifications when switching networks.
+     */
+    @NonNull
+    public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
+            @NonNull Duration def) {
+        final int duration = Settings.Global.getInt(context.getContentResolver(),
+                NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
+        return Duration.ofMillis(duration);
+    }
+
+    /**
+     * Set minimum duration (to {@link Settings}) between each switching network notifications.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param duration The minimum duration between notifications when switching networks.
+     */
+    public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
+            @NonNull Duration duration) {
+        final int time = (int) duration.toMillis();
+        if (time < 0) {
+            throw new IllegalArgumentException("Invalid duration.");
+        }
+        Settings.Global.putInt(context.getContentResolver(),
+                NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
+    }
+
+    /**
+     * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The URL used for HTTP captive portal detection upon a new connection.
+     */
+    @Nullable
+    public static String getCaptivePortalHttpUrl(@NonNull Context context) {
+        return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
+    }
+
+    /**
+     * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
+     * This URL should respond with a 204 response to a GET request to indicate no captive portal is
+     * present. And this URL must be HTTP as redirect responses are used to find captive portal
+     * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
+     * detection failed and lost the connection.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param url The URL used for HTTP captive portal detection upon a new connection.
+     */
+    public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
+        Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
+    }
+
+    /**
+     * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default mode if no setting value.
+     * @return The mode when connecting a network that presents a captive portal.
+     */
+    @CaptivePortalMode
+    public static int getCaptivePortalMode(@NonNull Context context,
+            @CaptivePortalMode int def) {
+        return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
+    }
+
+    /**
+     * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param mode The mode when connecting a network that presents a captive portal.
+     */
+    public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
+        if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
+                || mode == CAPTIVE_PORTAL_MODE_PROMPT
+                || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
+            throw new IllegalArgumentException("Invalid captive portal mode");
+        }
+        Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
+    }
+
+    /**
+     * Get the global HTTP proxy applied to the device, or null if none.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The {@link ProxyInfo} which build from global http proxy settings.
+     */
+    @Nullable
+    public static ProxyInfo getGlobalProxy(@NonNull Context context) {
+        final String host = Settings.Global.getString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
+        final int port = Settings.Global.getInt(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
+        final String exclusionList = Settings.Global.getString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+        final String pacFileUrl = Settings.Global.getString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
+
+        if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
+            return null; // No global proxy.
+        }
+
+        if (TextUtils.isEmpty(pacFileUrl)) {
+            return ProxyInfo.buildDirectProxy(
+                    host, port, ProxyUtils.exclusionStringAsList(exclusionList));
+        } else {
+            return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
+        }
+    }
+
+    /**
+     * Set global http proxy settings from given {@link ProxyInfo}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
+     *                    {@link ProxyInfo#buildPacProxy(Uri)} or
+     *                    {@link ProxyInfo#buildDirectProxy(String, int, List)}
+     */
+    public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
+        final String host = proxyInfo.getHost();
+        final int port = proxyInfo.getPort();
+        final String exclusionList = proxyInfo.getExclusionListAsString();
+        final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
+
+        if (TextUtils.isEmpty(pacFileUrl)) {
+            Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
+            Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
+            Settings.Global.putString(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
+            Settings.Global.putString(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+        } else {
+            Settings.Global.putString(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+            Settings.Global.putString(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+            Settings.Global.putInt(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+            Settings.Global.putString(
+                    context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+        }
+    }
+
+    /**
+     * Clear all global http proxy settings.
+     *
+     * @param context The {@link Context} to set the setting.
+     */
+    public static void clearGlobalProxy(@NonNull Context context) {
+        Settings.Global.putString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+        Settings.Global.putInt(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+        Settings.Global.putString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+        Settings.Global.putString(
+                context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+    }
+
+    /**
+     * Get specific private dns provider name from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The specific private dns provider name, or null if no setting value.
+     */
+    @Nullable
+    public static String getPrivateDnsHostname(@NonNull Context context) {
+        return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
+    }
+
+    /**
+     * Set specific private dns provider name to {@link Settings}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param specifier The specific private dns provider name.
+     */
+    public static void setPrivateDnsHostname(@NonNull Context context,
+            @Nullable String specifier) {
+        Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
+    }
+
+    /**
+     * Get default private dns mode from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The default private dns mode.
+     */
+    @PrivateDnsMode
+    @NonNull
+    public static String getPrivateDnsDefaultMode(@NonNull Context context) {
+        return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
+    }
+
+    /**
+     * Set default private dns mode to {@link Settings}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
+     *             constants.
+     */
+    public static void setPrivateDnsDefaultMode(@NonNull Context context,
+            @NonNull @PrivateDnsMode String mode) {
+        if (!(mode == PRIVATE_DNS_MODE_OFF
+                || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+                || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+            throw new IllegalArgumentException("Invalid private dns mode");
+        }
+        Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
+    }
+
+    /**
+     * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default duration if no setting value.
+     * @return The duration to keep a PendingIntent-based request.
+     */
+    @NonNull
+    public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
+            @NonNull Duration def) {
+        final int duration = Settings.Secure.getInt(context.getContentResolver(),
+                CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
+        return Duration.ofMillis(duration);
+    }
+
+    /**
+     * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param duration The duration to keep a PendingIntent-based request.
+     */
+    public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
+            @NonNull Duration duration) {
+        final int time = (int) duration.toMillis();
+        if (time < 0) {
+            throw new IllegalArgumentException("Invalid duration.");
+        }
+        Settings.Secure.putInt(
+                context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
+    }
+
+    /**
+     * Read from {@link Settings} whether the mobile data connection should remain active
+     * even when higher priority networks are active.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default value if no setting value.
+     * @return Whether the mobile data connection should remain active even when higher
+     *         priority networks are active.
+     */
+    public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
+        final int enable = Settings.Global.getInt(
+                context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
+        return (enable != 0) ? true : false;
+    }
+
+    /**
+     * Write into {@link Settings} whether the mobile data connection should remain active
+     * even when higher priority networks are active.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param enable Whether the mobile data connection should remain active even when higher
+     *               priority networks are active.
+     */
+    public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
+        Settings.Global.putInt(
+                context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
+    }
+
+    /**
+     * Read from {@link Settings} whether the wifi data connection should remain active
+     * even when higher priority networks are active.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @param def The default value if no setting value.
+     * @return Whether the wifi data connection should remain active even when higher
+     *         priority networks are active.
+     */
+    public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
+        final int enable = Settings.Global.getInt(
+                context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
+        return (enable != 0) ? true : false;
+    }
+
+    /**
+     * Write into {@link Settings} whether the wifi data connection should remain active
+     * even when higher priority networks are active.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param enable Whether the wifi data connection should remain active even when higher
+     *               priority networks are active
+     */
+    public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
+        Settings.Global.putInt(
+                context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
+    }
+
+    /**
+     * Get avoid bad wifi setting from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The setting whether to automatically switch away from wifi networks that lose
+     *         internet access.
+     */
+    @NetworkAvoidBadWifi
+    public static int getNetworkAvoidBadWifi(@NonNull Context context) {
+        final String setting =
+                Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
+        if ("0".equals(setting)) {
+            return NETWORK_AVOID_BAD_WIFI_IGNORE;
+        } else if ("1".equals(setting)) {
+            return NETWORK_AVOID_BAD_WIFI_AVOID;
+        } else {
+            return NETWORK_AVOID_BAD_WIFI_PROMPT;
+        }
+    }
+
+    /**
+     * Set avoid bad wifi setting to {@link Settings}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param value Whether to automatically switch away from wifi networks that lose internet
+     *              access.
+     */
+    public static void setNetworkAvoidBadWifi(@NonNull Context context,
+            @NetworkAvoidBadWifi int value) {
+        final String setting;
+        if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
+            setting = "0";
+        } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
+            setting = "1";
+        } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
+            setting = null;
+        } else {
+            throw new IllegalArgumentException("Invalid avoid bad wifi setting");
+        }
+        Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
+    }
+
+    /**
+     * Get network metered multipath preference from {@link Settings}.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return The network metered multipath preference which should be one of
+     *         ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
+     *         by config_networkMeteredMultipathPreference is used.
+     */
+    @Nullable
+    public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
+        return Settings.Global.getString(
+                context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
+    }
+
+    /**
+     * Set network metered multipath preference to {@link Settings}.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param preference The network metered multipath preference which should be one of
+     *                   ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
+     *                   specified by config_networkMeteredMultipathPreference is used.
+     */
+    public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
+            @NonNull @MultipathPreference String preference) {
+        if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
+                || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
+                || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
+            throw new IllegalArgumentException("Invalid private dns mode");
+        }
+        Settings.Global.putString(
+                context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
+    }
+
+    /**
+     * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference
+     * even when higher-priority networks are connected.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return A list of apps that should go on cellular networks in preference even when
+     *         higher-priority networks are connected or null if no setting value.
+     */
+    @Nullable
+    public static String getMobileDataPreferredApps(@NonNull Context context) {
+        return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS);
+    }
+
+    /**
+     * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference
+     * even when higher-priority networks are connected.
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param list A list of apps that should go on cellular networks in preference even when
+     *             higher-priority networks are connected.
+     */
+    public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
+        Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java
index 3f7660f..dac88ad 100644
--- a/packages/Connectivity/framework/src/android/net/DnsResolver.java
+++ b/packages/Connectivity/framework/src/android/net/DnsResolver.java
@@ -500,7 +500,7 @@
                             try {
                                 resp = resNetworkResult(fd);  // Closes fd, marks it invalid.
                             } catch (ErrnoException e) {
-                                Log.e(TAG, "resNetworkResult:" + e.toString());
+                                Log.w(TAG, "resNetworkResult:" + e.toString());
                                 exception = e;
                             }
                         }
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
index 078acbd..d941d4b 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
@@ -47,4 +47,5 @@
     void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
     void onQosCallbackUnregistered(int qosCallbackId);
     void onNetworkCreated();
+    void onNetworkDestroyed();
 }
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index cbd6193..26cb1ed 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -41,4 +41,5 @@
     void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
     void sendQosSessionLost(int qosCallbackId, in QosSession session);
     void sendQosCallbackError(int qosCallbackId, int exceptionType);
+    void sendTeardownDelayMs(int teardownDelayMs);
 }
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index 0741414..41fad63 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -27,7 +27,6 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -526,11 +525,4 @@
     public String toString() {
         return Integer.toString(netId);
     }
-
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(NetworkProto.NET_ID, netId);
-        proto.end(token);
-    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index aef1a31..c57da53 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -185,6 +185,20 @@
     public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
 
     /**
+     * Sent by the NetworkAgent to ConnectivityService to pass the current value of the teardown
+     * delay.
+     * arg1 = teardown delay in milliseconds
+     * @hide
+     */
+    public static final int EVENT_TEARDOWN_DELAY_CHANGED = BASE + 6;
+
+    /**
+     * The maximum value for the teardown delay, in milliseconds.
+     * @hide
+     */
+    public static final int MAX_TEARDOWN_DELAY_MS = 5000;
+
+    /**
      * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
      * networks status - whether we could use the network or could not, due to
      * either a bad network configuration (no internet link) or captive portal.
@@ -197,7 +211,6 @@
      */
     public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
 
-
     /**
      * Network validation suceeded.
      * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
@@ -370,10 +383,17 @@
      */
     public static final int CMD_NETWORK_CREATED = BASE + 22;
 
+    /**
+     * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+     * network was destroyed.
+     *
+     * @hide
+     */
+    public static final int CMD_NETWORK_DESTROYED = BASE + 23;
+
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
-        // The subtype can be changed with (TODO) setLegacySubtype, but it starts
-        // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
-        final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
+        final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
+                config.legacyTypeName, config.legacySubTypeName);
         ni.setIsAvailable(true);
         ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
                 config.getLegacyExtraInfo());
@@ -574,6 +594,10 @@
                     onNetworkCreated();
                     break;
                 }
+                case CMD_NETWORK_DESTROYED: {
+                    onNetworkDestroyed();
+                    break;
+                }
             }
         }
     }
@@ -719,6 +743,11 @@
         public void onNetworkCreated() {
             mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
         }
+
+        @Override
+        public void onNetworkDestroyed() {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED));
+        }
     }
 
     /**
@@ -835,6 +864,29 @@
     }
 
     /**
+     * Sets the value of the teardown delay.
+     *
+     * The teardown delay is the time between when the network disconnects and when the native
+     * network corresponding to this {@code NetworkAgent} is destroyed. By default, the native
+     * network is destroyed immediately. If {@code teardownDelayMs} is non-zero, then when this
+     * network disconnects, the system will instead immediately mark the network as restricted
+     * and unavailable to unprivileged apps, but will defer destroying the native network until the
+     * teardown delay timer expires.
+     *
+     * The interfaces in use by this network will remain in use until the native network is
+     * destroyed and cannot be reused until {@link #onNetworkDestroyed()} is called.
+     *
+     * This method may be called at any time while the network is connected. It has no effect if
+     * the network is already disconnected and the teardown delay timer is running.
+     *
+     * @param teardownDelayMs the teardown delay to set, or 0 to disable teardown delay.
+     */
+    public void setTeardownDelayMs(
+            @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMs) {
+        queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMs));
+    }
+
+    /**
      * Change the legacy subtype of this network agent.
      *
      * This is only for backward compatibility and should not be used by non-legacy network agents,
@@ -846,6 +898,7 @@
      * @hide
      */
     @Deprecated
+    @SystemApi
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
         queueOrSendNetworkInfo(mNetworkInfo);
@@ -979,6 +1032,7 @@
      * shall try to overwrite this method and produce a bandwidth update if capable.
      * @hide
      */
+    @SystemApi
     public void onBandwidthUpdateRequested() {
         pollLceData();
     }
@@ -1031,6 +1085,12 @@
      */
     public void onNetworkCreated() {}
 
+
+    /**
+     * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
+     */
+    public void onNetworkDestroyed() {}
+
     /**
      * Requests that the network hardware send the specified packet at the specified interval.
      *
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 0bd2371..3f058d8 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -175,6 +175,12 @@
     }
 
     /**
+     * The legacy Sub type of this network agent, or TYPE_NONE if unset.
+     * @hide
+     */
+    public int legacySubType = ConnectivityManager.TYPE_NONE;
+
+    /**
      * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
      * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
      *
@@ -200,6 +206,13 @@
     }
 
     /**
+     * The name of the legacy Sub network type. It's a free-form string.
+     * @hide
+     */
+    @NonNull
+    public String legacySubTypeName = "";
+
+    /**
      * The legacy extra info of the agent. The extra info should only be :
      * <ul>
      *   <li>For cellular agents, the APN name.</li>
@@ -235,6 +248,8 @@
             skip464xlat = nac.skip464xlat;
             legacyType = nac.legacyType;
             legacyTypeName = nac.legacyTypeName;
+            legacySubType = nac.legacySubType;
+            legacySubTypeName = nac.legacySubTypeName;
             mLegacyExtraInfo = nac.mLegacyExtraInfo;
         }
     }
@@ -300,7 +315,6 @@
          * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableNat64Detection() {
@@ -313,7 +327,6 @@
          * perform its own carrier-specific provisioning procedure.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableProvisioningNotification() {
@@ -334,6 +347,18 @@
         }
 
         /**
+         * Sets the legacy sub-type for this network.
+         *
+         * @param legacySubType the type
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubType(final int legacySubType) {
+            mConfig.legacySubType = legacySubType;
+            return this;
+        }
+
+        /**
          * Sets the name of the legacy type of the agent. It's a free-form string used in logging.
          * @param legacyTypeName the name
          * @return this builder, to facilitate chaining.
@@ -345,10 +370,20 @@
         }
 
         /**
+         * Sets the name of the legacy Sub-type of the agent. It's a free-form string.
+         * @param legacySubTypeName the name
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) {
+            mConfig.legacySubTypeName = legacySubTypeName;
+            return this;
+        }
+
+        /**
          * Sets the legacy extra info of the agent.
          * @param legacyExtraInfo the legacy extra info.
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
@@ -435,6 +470,8 @@
         out.writeInt(skip464xlat ? 1 : 0);
         out.writeInt(legacyType);
         out.writeString(legacyTypeName);
+        out.writeInt(legacySubType);
+        out.writeString(legacySubTypeName);
         out.writeString(mLegacyExtraInfo);
     }
 
@@ -452,6 +489,8 @@
             networkAgentConfig.skip464xlat = in.readInt() != 0;
             networkAgentConfig.legacyType = in.readInt();
             networkAgentConfig.legacyTypeName = in.readString();
+            networkAgentConfig.legacySubType = in.readInt();
+            networkAgentConfig.legacySubTypeName = in.readString();
             networkAgentConfig.mLegacyExtraInfo = in.readString();
             return networkAgentConfig;
         }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 881fa8c..a43dd15 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -35,7 +35,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Range;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
@@ -163,7 +162,6 @@
      *                   {@link NetworkCapabilities}.
      * @hide
      */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
         mRedactions = redactions;
         if (nc != null) {
@@ -274,6 +272,8 @@
             NET_CAPABILITY_VEHICLE_INTERNAL,
             NET_CAPABILITY_NOT_VCN_MANAGED,
             NET_CAPABILITY_ENTERPRISE,
+            NET_CAPABILITY_VSIM,
+            NET_CAPABILITY_BIP,
     })
     public @interface NetCapability { }
 
@@ -493,8 +493,22 @@
      */
     public static final int NET_CAPABILITY_ENTERPRISE = 29;
 
+    /**
+     * Indicates that this network has ability to access the carrier's Virtual Sim service.
+     * @hide
+     */
+    @SystemApi
+    public static final int NET_CAPABILITY_VSIM = 30;
+
+    /**
+     * Indicates that this network has ability to support Bearer Independent Protol.
+     * @hide
+     */
+    @SystemApi
+    public static final int NET_CAPABILITY_BIP = 31;
+
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_BIP;
 
     /**
      * Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -538,43 +552,6 @@
             | (1 << NET_CAPABILITY_NOT_VPN);
 
     /**
-     * Capabilities that suggest that a network is restricted.
-     * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
-     */
-    @VisibleForTesting
-    /* package */ static final long RESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_CBS)
-            | (1 << NET_CAPABILITY_DUN)
-            | (1 << NET_CAPABILITY_EIMS)
-            | (1 << NET_CAPABILITY_FOTA)
-            | (1 << NET_CAPABILITY_IA)
-            | (1 << NET_CAPABILITY_IMS)
-            | (1 << NET_CAPABILITY_MCX)
-            | (1 << NET_CAPABILITY_RCS)
-            | (1 << NET_CAPABILITY_VEHICLE_INTERNAL)
-            | (1 << NET_CAPABILITY_XCAP)
-            | (1 << NET_CAPABILITY_ENTERPRISE);
-
-    /**
-     * Capabilities that force network to be restricted.
-     * {@see #maybeMarkCapabilitiesRestricted}.
-     */
-    private static final long FORCE_RESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_OEM_PAID)
-            | (1 << NET_CAPABILITY_OEM_PRIVATE);
-
-    /**
-     * Capabilities that suggest that a network is unrestricted.
-     * {@see #maybeMarkCapabilitiesRestricted}.
-     */
-    @VisibleForTesting
-    /* package */ static final long UNRESTRICTED_CAPABILITIES =
-            (1 << NET_CAPABILITY_INTERNET)
-            | (1 << NET_CAPABILITY_MMS)
-            | (1 << NET_CAPABILITY_SUPL)
-            | (1 << NET_CAPABILITY_WIFI_P2P);
-
-    /**
      * Capabilities that are managed by ConnectivityService.
      */
     private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
@@ -614,8 +591,9 @@
         // TODO: Consider adding unwanted capabilities to the public API and mention this
         // in the documentation.
         checkValidCapability(capability);
-        mNetworkCapabilities |= 1 << capability;
-        mUnwantedNetworkCapabilities &= ~(1 << capability);  // remove from unwanted capability list
+        mNetworkCapabilities |= 1L << capability;
+        // remove from unwanted capability list
+        mUnwantedNetworkCapabilities &= ~(1L << capability);
         return this;
     }
 
@@ -634,8 +612,8 @@
      */
     public void addUnwantedCapability(@NetCapability int capability) {
         checkValidCapability(capability);
-        mUnwantedNetworkCapabilities |= 1 << capability;
-        mNetworkCapabilities &= ~(1 << capability);  // remove from requested capabilities
+        mUnwantedNetworkCapabilities |= 1L << capability;
+        mNetworkCapabilities &= ~(1L << capability);  // remove from requested capabilities
     }
 
     /**
@@ -648,7 +626,7 @@
      */
     public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
         checkValidCapability(capability);
-        final long mask = ~(1 << capability);
+        final long mask = ~(1L << capability);
         mNetworkCapabilities &= mask;
         return this;
     }
@@ -663,7 +641,7 @@
      */
     public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
         checkValidCapability(capability);
-        mUnwantedNetworkCapabilities &= ~(1 << capability);
+        mUnwantedNetworkCapabilities &= ~(1L << capability);
         return this;
     }
 
@@ -731,14 +709,14 @@
      */
     public boolean hasCapability(@NetCapability int capability) {
         return isValidCapability(capability)
-                && ((mNetworkCapabilities & (1 << capability)) != 0);
+                && ((mNetworkCapabilities & (1L << capability)) != 0);
     }
 
     /** @hide */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public boolean hasUnwantedCapability(@NetCapability int capability) {
         return isValidCapability(capability)
-                && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
+                && ((mUnwantedNetworkCapabilities & (1L << capability)) != 0);
     }
 
     /**
@@ -749,6 +727,23 @@
         return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
     }
 
+    /**
+     * Get the name of the given capability that carriers use.
+     * If the capability does not have a carrier-name, returns null.
+     *
+     * @param capability The capability to get the carrier-name of.
+     * @return The carrier-name of the capability, or null if it doesn't exist.
+     * @hide
+     */
+    @SystemApi
+    public static @Nullable String getCapabilityCarrierName(@NetCapability int capability) {
+        if (capability == NET_CAPABILITY_ENTERPRISE) {
+            return capabilityNameOf(capability);
+        } else {
+            return null;
+        }
+    }
+
     private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
         final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
         final long unwantedCaps =
@@ -811,37 +806,12 @@
     }
 
     /**
-     * Deduces that all the capabilities it provides are typically provided by restricted networks
-     * or not.
-     *
-     * @return {@code true} if the network should be restricted.
-     * @hide
-     */
-    public boolean deduceRestrictedCapability() {
-        // Check if we have any capability that forces the network to be restricted.
-        final boolean forceRestrictedCapability =
-                (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
-
-        // Verify there aren't any unrestricted capabilities.  If there are we say
-        // the whole thing is unrestricted unless it is forced to be restricted.
-        final boolean hasUnrestrictedCapabilities =
-                (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;
-
-        // Must have at least some restricted capabilities.
-        final boolean hasRestrictedCapabilities =
-                (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
-
-        return forceRestrictedCapability
-                || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities);
-    }
-
-    /**
-     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted.
+     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if inferring the network is restricted.
      *
      * @hide
      */
     public void maybeMarkCapabilitiesRestricted() {
-        if (deduceRestrictedCapability()) {
+        if (NetworkCapabilitiesUtils.inferRestrictedCapability(this)) {
             removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
         }
     }
@@ -1141,7 +1111,9 @@
      * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
      * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
      * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
-     * callback. The app will be blamed for location access if this field is included.
+     * callback. If the apps targets SDK version equal to {{@link Build.VERSION_CODES#R}, this field
+     * will always be included. The app will be blamed for location access if this field is
+     * included.
      * </p>
      */
     public int getOwnerUid() {
@@ -2087,34 +2059,6 @@
         }
     }
 
-    /** @hide */
-    public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-
-        for (int transport : getTransportTypes()) {
-            proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
-        }
-
-        for (int capability : getCapabilities()) {
-            proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
-        }
-
-        proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
-        proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);
-
-        if (mNetworkSpecifier != null) {
-            proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
-        }
-        if (mTransportInfo != null) {
-            // TODO b/120653863: write transport-specific info to proto?
-        }
-
-        proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
-        proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
-
-        proto.end(token);
-    }
-
     /**
      * @hide
      */
@@ -2163,6 +2107,8 @@
             case NET_CAPABILITY_VEHICLE_INTERNAL:     return "VEHICLE_INTERNAL";
             case NET_CAPABILITY_NOT_VCN_MANAGED:      return "NOT_VCN_MANAGED";
             case NET_CAPABILITY_ENTERPRISE:           return "ENTERPRISE";
+            case NET_CAPABILITY_VSIM:                 return "VSIM";
+            case NET_CAPABILITY_BIP:                  return "BIP";
             default:                                  return Integer.toString(capability);
         }
     }
@@ -2390,9 +2336,15 @@
 
     /**
      * Gets the subscription ID set that associated to this network or request.
+     *
+     * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
+     * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
+     *
      * @return
+     * @hide
      */
     @NonNull
+    @SystemApi
     public Set<Integer> getSubIds() {
         return new ArraySet<>(mSubIds);
     }
@@ -2757,10 +2709,17 @@
         /**
          * Set the subscription ID set.
          *
+         * <p>SubIds are populated in NetworkCapability instances from the system only for callers
+         * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
+         * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
+         * NETWORK_FACTORY permission.
+         *
          * @param subIds a set that represent the subscription IDs. Empty if clean up.
          * @return this builder.
+         * @hide
          */
         @NonNull
+        @SystemApi
         public Builder setSubIds(@NonNull final Set<Integer> subIds) {
             mCaps.setSubIds(subIds);
             return this;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index bcbc04f7..3a8a07a 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -47,7 +47,6 @@
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.Range;
-import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
 import java.util.List;
@@ -501,9 +500,14 @@
          * A network will satisfy this request only if it matches one of the subIds in this set.
          * An empty set matches all networks, including those without a subId.
          *
+         * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
+         * NETWORK_FACTORY permission.
+         *
          * @param subIds A {@code Set} that represents subscription IDs.
+         * @hide
          */
         @NonNull
+        @SystemApi
         public Builder setSubIds(@NonNull Set<Integer> subIds) {
             mNetworkCapabilities.setSubIds(subIds);
             return this;
@@ -675,18 +679,6 @@
         }
     }
 
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-
-        proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
-        proto.write(NetworkRequestProto.REQUEST_ID, requestId);
-        proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
-        networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
-
-        proto.end(token);
-    }
-
     public boolean equals(@Nullable Object obj) {
         if (obj instanceof NetworkRequest == false) return false;
         NetworkRequest that = (NetworkRequest)obj;
@@ -699,4 +691,43 @@
     public int hashCode() {
         return Objects.hash(requestId, legacyType, networkCapabilities, type);
     }
+
+    /**
+     * Gets all the capabilities set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of capability values for this instance.
+     */
+    @NonNull
+    public @NetCapability int[] getCapabilities() {
+        // No need to make a defensive copy here as NC#getCapabilities() already returns
+        // a new array.
+        return networkCapabilities.getCapabilities();
+    }
+
+    /**
+     * Gets all the unwanted capabilities set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of unwanted capability values for this instance.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public @NetCapability int[] getUnwantedCapabilities() {
+        // No need to make a defensive copy here as NC#getUnwantedCapabilities() already returns
+        // a new array.
+        return networkCapabilities.getUnwantedCapabilities();
+    }
+
+    /**
+     * Gets all the transports set on this {@code NetworkRequest} instance.
+     *
+     * @return an array of transport type values for this instance.
+     */
+    @NonNull
+    public @Transport int[] getTransportTypes() {
+        // No need to make a defensive copy here as NC#getTransportTypes() already returns
+        // a new array.
+        return networkCapabilities.getTransportTypes();
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index c4bebc0..a92fda1 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -92,7 +92,10 @@
      * Determine if {@code uid} can access network designated by {@code netId}.
      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
      */
-    public native static boolean queryUserAccess(int uid, int netId);
+    public static boolean queryUserAccess(int uid, int netId) {
+        // TODO (b/183485986): remove this method
+        return false;
+    }
 
     /**
      * DNS resolver series jni method.
diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
index d007a95..f6cae72 100644
--- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
+++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
@@ -55,36 +55,68 @@
     static final String TAG = "SocketKeepalive";
 
     /**
-     * No errors.
+     * Success. It indicates there is no error.
      * @hide
      */
     @SystemApi
     public static final int SUCCESS = 0;
 
-    /** @hide */
+    /**
+     * No keepalive. This should only be internally as it indicates There is no keepalive.
+     * It should not propagate to applications.
+     * @hide
+     */
     public static final int NO_KEEPALIVE = -1;
 
-    /** @hide */
+    /**
+     * Data received.
+     * @hide
+     */
     public static final int DATA_RECEIVED = -2;
 
-    /** @hide */
+    /**
+     * The binder died.
+     * @hide
+     */
     public static final int BINDER_DIED = -10;
 
-    /** The specified {@code Network} is not connected. */
+    /**
+     * The invalid network. It indicates the specified {@code Network} is not connected.
+     */
     public static final int ERROR_INVALID_NETWORK = -20;
-    /** The specified IP addresses are invalid. For example, the specified source IP address is
-     * not configured on the specified {@code Network}. */
+
+    /**
+     * The invalid IP addresses. Indicates the specified IP addresses are invalid.
+     * For example, the specified source IP address is not configured on the
+     * specified {@code Network}.
+     */
     public static final int ERROR_INVALID_IP_ADDRESS = -21;
-    /** The requested port is invalid. */
+
+    /**
+     * The port is invalid.
+     */
     public static final int ERROR_INVALID_PORT = -22;
-    /** The packet length is invalid (e.g., too long). */
+
+    /**
+     * The length is invalid (e.g. too long).
+     */
     public static final int ERROR_INVALID_LENGTH = -23;
-    /** The packet transmission interval is invalid (e.g., too short). */
+
+    /**
+     * The interval is invalid (e.g. too short).
+     */
     public static final int ERROR_INVALID_INTERVAL = -24;
-    /** The target socket is invalid. */
+
+    /**
+     * The socket is invalid.
+     */
     public static final int ERROR_INVALID_SOCKET = -25;
-    /** The target socket is not idle. */
+
+    /**
+     * The socket is not idle.
+     */
     public static final int ERROR_SOCKET_NOT_IDLE = -26;
+
     /**
      * The stop reason is uninitialized. This should only be internally used as initial state
      * of stop reason, instead of propagating to application.
@@ -92,15 +124,29 @@
      */
     public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
 
-    /** The device does not support this request. */
+    /**
+     * The request is unsupported.
+     */
     public static final int ERROR_UNSUPPORTED = -30;
-    /** @hide TODO: delete when telephony code has been updated. */
-    public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
-    /** The hardware returned an error. */
+
+    /**
+     * There was a hardware error.
+     */
     public static final int ERROR_HARDWARE_ERROR = -31;
-    /** The limitation of resource is reached. */
+
+    /**
+     * Resources are insufficient (e.g. all hardware slots are in use).
+     */
     public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
 
+    /**
+     * There was no such slot. This should only be internally as it indicates
+     * a programming error in the system server. It should not propagate to
+     * applications.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_NO_SUCH_SLOT = -33;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -111,7 +157,8 @@
             ERROR_INVALID_LENGTH,
             ERROR_INVALID_INTERVAL,
             ERROR_INVALID_SOCKET,
-            ERROR_SOCKET_NOT_IDLE
+            ERROR_SOCKET_NOT_IDLE,
+            ERROR_NO_SUCH_SLOT
     })
     public @interface ErrorCode {}
 
@@ -122,7 +169,6 @@
             ERROR_INVALID_LENGTH,
             ERROR_UNSUPPORTED,
             ERROR_INSUFFICIENT_RESOURCES,
-            ERROR_HARDWARE_UNSUPPORTED
     })
     public @interface KeepaliveEvent {}
 
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index cd8f4c0..ba83a44 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -17,11 +17,14 @@
 package android.net;
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import java.util.Objects;
 
@@ -38,8 +41,26 @@
     /** Type of this VPN. */
     public final int type;
 
-    public VpnTransportInfo(int type) {
+    @Nullable
+    public final String sessionId;
+
+    @Override
+    public long getApplicableRedactions() {
+        return REDACT_FOR_NETWORK_SETTINGS;
+    }
+
+    /**
+     * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
+     */
+    @NonNull
+    public VpnTransportInfo makeCopy(long redactions) {
+        return new VpnTransportInfo(type,
+            ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
+    }
+
+    public VpnTransportInfo(int type, @Nullable String sessionId) {
         this.type = type;
+        this.sessionId = sessionId;
     }
 
     @Override
@@ -47,17 +68,17 @@
         if (!(o instanceof VpnTransportInfo)) return false;
 
         VpnTransportInfo that = (VpnTransportInfo) o;
-        return this.type == that.type;
+        return (this.type == that.type) && TextUtils.equals(this.sessionId, that.sessionId);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(type);
+        return Objects.hash(type, sessionId);
     }
 
     @Override
     public String toString() {
-        return String.format("VpnTransportInfo{type=%d}", type);
+        return String.format("VpnTransportInfo{type=%d, sessionId=%s}", type, sessionId);
     }
 
     @Override
@@ -68,12 +89,13 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(type);
+        dest.writeString(sessionId);
     }
 
     public static final @NonNull Creator<VpnTransportInfo> CREATOR =
             new Creator<VpnTransportInfo>() {
         public VpnTransportInfo createFromParcel(Parcel in) {
-            return new VpnTransportInfo(in.readInt());
+            return new VpnTransportInfo(in.readInt(), in.readString());
         }
         public VpnTransportInfo[] newArray(int size) {
             return new VpnTransportInfo[size];
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index c57d4ad..cbb5105 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -66,31 +66,40 @@
         @Override
         public void onCapabilitiesChanged(
                 Network network, NetworkCapabilities networkCapabilities) {
+            WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
+            updateWifiInfo(wifiInfo);
+            updateStatusLabel();
+            mCallback.run();
+        }
+
+        @Override
+        public void onLost(Network network) {
+            updateWifiInfo(null);
             updateStatusLabel();
             mCallback.run();
         }
     };
     private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() {
-                @Override
-                public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
-                    // network is now the default network, and its capabilities are nc.
-                    // This method will always be called immediately after the network becomes the
-                    // default, in addition to any time the capabilities change while the network is
-                    // the default.
-                    mDefaultNetwork = network;
-                    mDefaultNetworkCapabilities = nc;
-                    updateStatusLabel();
-                    mCallback.run();
-                }
-                @Override
-                public void onLost(Network network) {
-                    // The system no longer has a default network.
-                    mDefaultNetwork = null;
-                    mDefaultNetworkCapabilities = null;
-                    updateStatusLabel();
-                    mCallback.run();
-                }
-            };
+        @Override
+        public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+            // network is now the default network, and its capabilities are nc.
+            // This method will always be called immediately after the network becomes the
+            // default, in addition to any time the capabilities change while the network is
+            // the default.
+            mDefaultNetwork = network;
+            mDefaultNetworkCapabilities = nc;
+            updateStatusLabel();
+            mCallback.run();
+        }
+        @Override
+        public void onLost(Network network) {
+            // The system no longer has a default network.
+            mDefaultNetwork = null;
+            mDefaultNetworkCapabilities = null;
+            updateStatusLabel();
+            mCallback.run();
+        }
+    };
     private Network mDefaultNetwork = null;
     private NetworkCapabilities mDefaultNetworkCapabilities = null;
     private final Runnable mCallback;
@@ -170,32 +179,22 @@
         String action = intent.getAction();
         if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
             updateWifiState();
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            updateWifiState();
-            final NetworkInfo networkInfo =
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-            connected = networkInfo != null && networkInfo.isConnected();
-            mWifiInfo = null;
-            ssid = null;
-            if (connected) {
-                mWifiInfo = mWifiManager.getConnectionInfo();
-                if (mWifiInfo != null) {
-                    if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
-                        ssid = mWifiInfo.getPasspointProviderFriendlyName();
-                    } else {
-                        ssid = getValidSsid(mWifiInfo);
-                    }
-                    updateRssi(mWifiInfo.getRssi());
-                    maybeRequestNetworkScore();
-                }
+        }
+    }
+
+    private void updateWifiInfo(WifiInfo wifiInfo) {
+        updateWifiState();
+        connected = wifiInfo != null;
+        mWifiInfo = wifiInfo;
+        ssid = null;
+        if (mWifiInfo != null) {
+            if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
+                ssid = mWifiInfo.getPasspointProviderFriendlyName();
+            } else {
+                ssid = getValidSsid(mWifiInfo);
             }
-            updateStatusLabel();
-            mCallback.run();
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            // Default to -200 as its below WifiManager.MIN_RSSI.
-            updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
-            updateStatusLabel();
-            mCallback.run();
+            updateRssi(mWifiInfo.getRssi());
+            maybeRequestNetworkScore();
         }
     }
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index cad4b69..bd5f8ab 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -122,7 +122,8 @@
     <uses-permission android:name="android.permission.CREATE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
-    <uses-permission android:name="android.permission.QUERY_USERS" />
+    <uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
+    <uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
     <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
     <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
@@ -182,6 +183,7 @@
     <uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
     <uses-permission android:name="android.permission.MANAGE_SENSORS" />
     <uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
+    <uses-permission android:name="android.permission.QUERY_AUDIO_STATE" />
     <uses-permission android:name="android.permission.MANAGE_CAMERA" />
     <!-- Permissions needed to test system only camera devices -->
     <uses-permission android:name="android.permission.CAMERA" />
@@ -230,6 +232,9 @@
     <!-- Permission needed to run keyguard manager tests in CTS -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
 
+    <!-- Permission needed to set/clear/verify lockscreen credentials in CTS tests -->
+    <uses-permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS" />
+
     <!-- Permission needed to test wallpaper component -->
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
@@ -355,6 +360,9 @@
     <!-- Permission needed for CTS test - CtsHdmiCecHostTestCases -->
     <uses-permission android:name="android.permission.HDMI_CEC" />
 
+    <!-- Permission needed for CTS test - MediaPlayerTest -->
+    <uses-permission android:name="android.permission.BIND_IMS_SERVICE" />
+
     <!-- Permission needed for CTS test - WifiManagerTest -->
     <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
@@ -370,6 +378,15 @@
     <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
     <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
 
+    <!-- Permission required for CTS test - ResourceObserverNativeTest -->
+    <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
+
+    <!-- Permission required for CTS test - android.widget.cts.ToastTest -->
+    <uses-permission android:name="android.permission.UNLIMITED_TOASTS" />
+
+    <!-- Permission required for CTS test - CtsAlarmManagerTestCases -->
+    <uses-permission android:name="android.permission.SCHEDULE_PRIORITIZED_ALARM" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index f884270..835471d 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -9,6 +9,7 @@
 awickham@google.com
 beverlyt@google.com
 brockman@google.com
+ccassidy@google.com
 cinek@google.com
 cwren@google.com
 dupin@google.com
@@ -19,10 +20,10 @@
 hyunyoungs@google.com
 jaggies@google.com
 jamesoleary@google.com
+jdemeulenaere@google.com
 jeffdq@google.com
 jjaggi@google.com
 jonmiranda@google.com
-joshmcgrath@google.com
 joshtrask@google.com
 juliacr@google.com
 juliatuttle@google.com
@@ -37,7 +38,6 @@
 mpietal@google.com
 mrcasey@google.com
 mrenouf@google.com
-nbenbernou@google.com
 nesciosquid@google.com
 ogunwale@google.com
 peanutbutter@google.com
@@ -45,6 +45,7 @@
 pixel@google.com
 roosa@google.com
 santie@google.com
+shanh@google.com
 snoeberger@google.com
 sreyasr@google.com
 steell@google.com
@@ -59,6 +60,7 @@
 vadimt@google.com
 victortulias@google.com
 winsonc@google.com
+yurilin@google.com
 xuqiu@google.com
 zakcohen@google.com
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index df00a4f..7e3ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -344,8 +344,6 @@
 
         // broadcasts
         IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 4ae9665..3c0b07a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -101,11 +101,7 @@
                 wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
     }
 
-    /**
-     * Fetches wifi initial state replacing the initial sticky broadcast.
-     */
-    public void fetchInitialState() {
-        mWifiTracker.fetchInitialState();
+    private void copyWifiStates() {
         mCurrentState.enabled = mWifiTracker.enabled;
         mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
         mCurrentState.connected = mWifiTracker.connected;
@@ -113,6 +109,14 @@
         mCurrentState.rssi = mWifiTracker.rssi;
         mCurrentState.level = mWifiTracker.level;
         mCurrentState.statusLabel = mWifiTracker.statusLabel;
+    }
+
+    /**
+     * Fetches wifi initial state replacing the initial sticky broadcast.
+     */
+    public void fetchInitialState() {
+        mWifiTracker.fetchInitialState();
+        copyWifiStates();
         notifyListenersIfNecessary();
     }
 
@@ -121,19 +125,12 @@
      */
     public void handleBroadcast(Intent intent) {
         mWifiTracker.handleBroadcast(intent);
-        mCurrentState.enabled = mWifiTracker.enabled;
-        mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
-        mCurrentState.connected = mWifiTracker.connected;
-        mCurrentState.ssid = mWifiTracker.ssid;
-        mCurrentState.rssi = mWifiTracker.rssi;
-        mCurrentState.level = mWifiTracker.level;
-        mCurrentState.statusLabel = mWifiTracker.statusLabel;
+        copyWifiStates();
         notifyListenersIfNecessary();
     }
 
     private void handleStatusUpdated() {
-        mCurrentState.statusLabel = mWifiTracker.statusLabel;
-        mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
+        copyWifiStates();
         notifyListenersIfNecessary();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 3a84e31..0dfcf7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -40,7 +40,9 @@
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.net.NetworkScoreManager;
+import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.provider.Settings;
@@ -51,7 +53,6 @@
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
 import android.testing.TestableLooper;
@@ -115,6 +116,7 @@
     protected int mSubId;
 
     private NetworkCapabilities mNetCapabilities;
+    private ConnectivityManager.NetworkCallback mDefaultNetworkCallback;
     private ConnectivityManager.NetworkCallback mNetworkCallback;
 
     @Rule
@@ -214,6 +216,10 @@
             ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
         verify(mMockCm, atLeastOnce())
             .registerDefaultNetworkCallback(callbackArg.capture(), isA(Handler.class));
+        mDefaultNetworkCallback = callbackArg.getValue();
+        assertNotNull(mDefaultNetworkCallback);
+        verify(mMockCm, atLeastOnce()).registerNetworkCallback(
+                isA(NetworkRequest.class), callbackArg.capture(), isA(Handler.class));
         mNetworkCallback = callbackArg.getValue();
         assertNotNull(mNetworkCallback);
     }
@@ -270,10 +276,19 @@
     }
 
     public void setConnectivityViaCallback(
-        int networkType, boolean validated, boolean isConnected){
+            int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) {
+        mNetCapabilities.setTransportInfo(wifiInfo);
         setConnectivityCommon(networkType, validated, isConnected);
-        mNetworkCallback.onCapabilitiesChanged(
+        mDefaultNetworkCallback.onCapabilitiesChanged(
             mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+        if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
+            if (isConnected) {
+                mNetworkCallback.onCapabilitiesChanged(
+                        mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+            } else {
+                mNetworkCallback.onLost(mock(Network.class));
+            }
+        }
     }
 
     private void setConnectivityCommon(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 988e022..9c9d6ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -32,6 +32,7 @@
     // These match the constants in WifiManager and need to be kept up to date.
     private static final int MIN_RSSI = -100;
     private static final int MAX_RSSI = -55;
+    private WifiInfo mWifiInfo = mock(WifiInfo.class);
 
     @Test
     public void testWifiIcon() {
@@ -41,15 +42,16 @@
 
         setWifiState(true, testSsid);
         setWifiLevel(0);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
         // Connected, but still not validated - does not show
         verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
 
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
             setWifiLevel(testLevel);
 
-            setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+            setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
             verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
-            setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+            setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
             // Icon does not show if not validated
             verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
         }
@@ -69,10 +71,10 @@
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
             setWifiLevel(testLevel);
 
-            setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+            setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
             verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel],
                     testSsid);
-            setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+            setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
             verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
                     testSsid);
         }
@@ -86,7 +88,7 @@
         setWifiEnabled(true);
         setWifiState(true, testSsid);
         setWifiLevel(testLevel);
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
         verifyLastQsWifiIcon(true, true,
                 WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
 
@@ -111,14 +113,14 @@
         setWifiEnabled(true);
         setWifiState(true, testSsid);
         setWifiLevel(testLevel);
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
 
         setupDefaultSignal();
         setGsmRoaming(true);
         // Still be on wifi though.
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_CELLULAR, false, false, mWifiInfo);
         verifyLastMobileDataIndicators(true,
                 DEFAULT_LEVEL,
                 0, true);
@@ -132,10 +134,10 @@
         setWifiEnabled(true);
         setWifiState(true, testSsid);
         setWifiLevel(testLevel);
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
 
-        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
         verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
     }
 
@@ -147,11 +149,11 @@
         setWifiEnabled(true);
         setWifiState(true, testSsid);
         setWifiLevel(testLevel);
-        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
 
         setWifiState(false, testSsid);
-        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, false);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, false, mWifiInfo);
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
     }
 
@@ -162,14 +164,14 @@
         setWifiEnabled(true);
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
-        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, false, true);
-        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, false, true, mWifiInfo);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, true, true, mWifiInfo);
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
         // Mock calling setUnderlyingNetworks.
         setWifiState(true, testSsid);
         setWifiLevel(testLevel);
-        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+        setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
     }
 
@@ -209,6 +211,7 @@
         int rssi = (int)(MIN_RSSI + level * amountPerLevel);
         // Put RSSI in the middle of the range.
         rssi += amountPerLevel / 2;
+        when(mWifiInfo.getRssi()).thenReturn(rssi);
         Intent i = new Intent(WifiManager.RSSI_CHANGED_ACTION);
         i.putExtra(WifiManager.EXTRA_NEW_RSSI, rssi);
         mNetworkController.onReceive(mContext, i);
@@ -224,10 +227,8 @@
         Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         NetworkInfo networkInfo = mock(NetworkInfo.class);
         when(networkInfo.isConnected()).thenReturn(connected);
-
-        WifiInfo wifiInfo = mock(WifiInfo.class);
-        when(wifiInfo.getSSID()).thenReturn(ssid);
-        when(mMockWm.getConnectionInfo()).thenReturn(wifiInfo);
+        when(mWifiInfo.getSSID()).thenReturn(ssid);
+        when(mMockWm.getConnectionInfo()).thenReturn(mWifiInfo);
 
         i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
         mNetworkController.onReceive(mContext, i);
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index a75fb2d..15f01e6 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -27,7 +27,8 @@
 
     <original-package android:name="com.android.smspush" />
     <application
-        android:allowClearUserData="false">
+        android:allowClearUserData="false"
+        android:directBootAware="true">
         <service android:name=".WapPushManager"
             android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND"
             android:exported="true">
diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
index dc2707b..951e64f 100755
--- a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
+++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
@@ -26,17 +26,21 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.UserManager;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IWapPushManager;
 import com.android.internal.telephony.WapPushManagerParams;
 
+import java.io.File;
+
 /**
  * The WapPushManager service is implemented to process incoming
  * WAP Push messages and to maintain the Receiver Application/Application
@@ -67,8 +71,13 @@
     /**
      * Inner class that deals with application ID table
      */
-    private class WapPushManDBHelper extends SQLiteOpenHelper {
-        WapPushManDBHelper(Context context) {
+    @VisibleForTesting
+    public static class WapPushManDBHelper extends SQLiteOpenHelper {
+        /**
+         * Constructor
+         */
+        @VisibleForTesting
+        public WapPushManDBHelper(Context context) {
             super(context, DATABASE_NAME, null, WAP_PUSH_MANAGER_VERSION);
             if (LOCAL_LOGV) Log.v(LOG_TAG, "helper instance created.");
         }
@@ -269,10 +278,6 @@
                 int app_type, boolean need_signature, boolean further_processing) {
             WapPushManDBHelper dbh = getDatabase(mContext);
             SQLiteDatabase db = dbh.getWritableDatabase();
-            WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type);
-            boolean ret = false;
-            boolean insert = false;
-            int sq = 0;
 
             if (!appTypeCheck(app_type)) {
                 Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be "
@@ -280,34 +285,8 @@
                         + WapPushManagerParams.APP_TYPE_SERVICE);
                 return false;
             }
-
-            if (lastapp == null) {
-                insert = true;
-                sq = 0;
-            } else if (!lastapp.packageName.equals(package_name) ||
-                    !lastapp.className.equals(class_name)) {
-                insert = true;
-                sq = lastapp.installOrder + 1;
-            }
-
-            if (insert) {
-                ContentValues values = new ContentValues();
-
-                values.put("x_wap_application", x_app_id);
-                values.put("content_type", content_type);
-                values.put("package_name", package_name);
-                values.put("class_name", class_name);
-                values.put("app_type", app_type);
-                values.put("need_signature", need_signature ? 1 : 0);
-                values.put("further_processing", further_processing ? 1 : 0);
-                values.put("install_order", sq);
-                db.insert(APPID_TABLE_NAME, null, values);
-                if (LOCAL_LOGV) Log.v(LOG_TAG, "add:" + x_app_id + ":" + content_type
-                        + " " + package_name + "." + class_name
-                        + ", newsq:" + sq);
-                ret = true;
-            }
-
+            boolean ret = insertPackage(dbh, db, x_app_id, content_type, package_name, class_name,
+                    app_type, need_signature, further_processing);
             db.close();
 
             return ret;
@@ -404,11 +383,91 @@
     protected WapPushManDBHelper getDatabase(Context context) {
         if (mDbHelper == null) {
             if (LOCAL_LOGV) Log.v(LOG_TAG, "create new db inst.");
-            mDbHelper = new WapPushManDBHelper(context);
+            mDbHelper = new WapPushManDBHelper(context.createDeviceProtectedStorageContext());
         }
+        // Migrate existing legacy database into the device encrypted storage.
+        migrateWapPushManDBIfNeeded(context);
         return mDbHelper;
     }
 
+    /**
+     * Inserts a package information into a database
+     */
+    @VisibleForTesting
+    public boolean insertPackage(WapPushManDBHelper dbh, SQLiteDatabase db, String appId,
+            String contentType, String packageName, String className, int appType,
+            boolean needSignature, boolean furtherProcessing) {
+
+        WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, appId, contentType);
+        boolean insert = false;
+        int sq = 0;
+
+        if (lastapp == null) {
+            insert = true;
+            sq = 0;
+        } else if (!lastapp.packageName.equals(packageName)
+                || !lastapp.className.equals(className)) {
+            insert = true;
+            sq = lastapp.installOrder + 1;
+        }
+
+        if (insert) {
+            ContentValues values = new ContentValues();
+
+            values.put("x_wap_application", appId);
+            values.put("content_type", contentType);
+            values.put("package_name", packageName);
+            values.put("class_name", className);
+            values.put("app_type", appType);
+            values.put("need_signature", needSignature ? 1 : 0);
+            values.put("further_processing", furtherProcessing ? 1 : 0);
+            values.put("install_order", sq);
+            db.insert(APPID_TABLE_NAME, null, values);
+            if (LOCAL_LOGV) {
+                Log.v(LOG_TAG, "add:" + appId + ":" + contentType + " " + packageName
+                        + "." + className + ", newsq:" + sq);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Migrates a legacy database into the device encrypted storage
+     */
+    private void migrateWapPushManDBIfNeeded(Context context) {
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        File file = context.getDatabasePath(DATABASE_NAME);
+        if (!userManager.isUserUnlocked() || !file.exists()) {
+            // Check if the device is unlocked because a legacy database can't access during
+            // DirectBoot.
+            return;
+        }
+
+        // Migration steps below:
+        // 1. Merge the package info to legacy database if there is any package info which is
+        // registered during DirectBoot.
+        // 2. Move the data base to the device encryped storage.
+        WapPushManDBHelper legacyDbHelper = new WapPushManDBHelper(context);
+        SQLiteDatabase legacyDb = legacyDbHelper.getWritableDatabase();
+        SQLiteDatabase db = mDbHelper.getWritableDatabase();
+        Cursor cur = db.query(APPID_TABLE_NAME, null, null, null, null, null, null);
+        while (cur.moveToNext()) {
+            insertPackage(legacyDbHelper, legacyDb,
+                    cur.getString(cur.getColumnIndex("x_wap_application")),
+                    cur.getString(cur.getColumnIndex("content_type")),
+                    cur.getString(cur.getColumnIndex("package_name")),
+                    cur.getString(cur.getColumnIndex("class_name")),
+                    cur.getInt(cur.getColumnIndex("app_type")),
+                    cur.getInt(cur.getColumnIndex("need_signature")) == 1,
+                    cur.getInt(cur.getColumnIndex("further_processing")) == 1);
+        }
+        cur.close();
+        legacyDb.close();
+        db.close();
+        context.createDeviceProtectedStorageContext().moveDatabaseFrom(context, DATABASE_NAME);
+        Log.i(LOG_TAG, "Migrated the legacy database.");
+    }
 
     /**
      * This method is used for testing
diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
index f7afc57..b9dac4e 100644
--- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
+++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.database.sqlite.SQLiteDatabase;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.provider.Telephony.Sms.Intents;
@@ -33,7 +34,9 @@
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.HexDump;
 import com.android.smspush.WapPushManager;
+import com.android.smspush.WapPushManager.WapPushManDBHelper;
 
+import java.io.File;
 import java.util.Random;
 
 /**
@@ -467,8 +470,9 @@
         try {
             super.setUp();
             // get verifier
-            getContext().bindService(new Intent(IDataVerify.class.getName()),
-                    mConn, Context.BIND_AUTO_CREATE);
+            Intent intent = new Intent(IDataVerify.class.getName());
+            intent.setPackage("com.android.smspush.unitTests");
+            getContext().bindService(intent, mConn, Context.BIND_AUTO_CREATE);
         } catch (Exception e) {
             Log.w(LOG_TAG, "super exception");
         }
@@ -552,15 +556,15 @@
     }
 
     /**
-     * Add sqlite injection test
+     * Sqlite injection test
      */
-    public void testAddPackage0() {
+    public void testSqliteInjection() {
         String inject = "' union select 0,'com.android.settings','com.android.settings.Settings',0,0,0--";
 
-        // insert new data
+        // update data
         IWapPushManager iwapman = getInterface();
         try {
-            assertFalse(iwapman.addPackage(
+            assertFalse(iwapman.updatePackage(
                     inject,
                     Integer.toString(mContentTypeValue),
                     mPackageName, mClassName,
@@ -2528,4 +2532,45 @@
         mMessageBody = originalMessageBody;
     }
 
+    /**
+     * DataBase migration test.
+     */
+    public void testDataBaseMigration() {
+        IWapPushManager iwapman = getInterface();
+        WapPushManager wpman = getService();
+        Context context = getContext();
+
+        addPackageToLegacyDB(mAppIdValue, mContentTypeValue, mPackageName, mClassName,
+                WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+        addPackageToLegacyDB(mAppIdValue + 10, mContentTypeValue, mPackageName, mClassName,
+                WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+
+        File oldDbFile = context.getDatabasePath("wappush.db");
+        assertTrue(oldDbFile.exists());
+        assertTrue(wpman.verifyData(Integer.toString(mAppIdValue),
+                Integer.toString(mContentTypeValue),
+                mPackageName, mClassName,
+                WapPushManagerParams.APP_TYPE_SERVICE, true, true));
+        assertFalse(oldDbFile.exists());
+
+        // Clean up DB
+        try {
+            iwapman.deletePackage(Integer.toString(mAppIdValue),
+                    Integer.toString(mContentTypeValue), mPackageName, mClassName);
+            iwapman.deletePackage(Integer.toString(mAppIdValue + 10),
+                    Integer.toString(mContentTypeValue), mPackageName, mClassName);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+    }
+
+    private void addPackageToLegacyDB(int appId, int contextType, String packagename,
+            String classnName, int appType, boolean signature, boolean furtherProcessing) {
+        WapPushManager wpman = getService();
+        WapPushManDBHelper dbh = new WapPushManDBHelper(getContext());
+        SQLiteDatabase db = dbh.getWritableDatabase();
+
+        wpman.insertPackage(dbh, db, Integer.toString(appId), Integer.toString(contextType),
+                packagename, classnName, appType, signature, furtherProcessing);
+    }
 }
diff --git a/rs/java/Android.bp b/rs/java/Android.bp
new file mode 100644
index 0000000..1c2b575
--- /dev/null
+++ b/rs/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-rs-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/sax/java/Android.bp b/sax/java/Android.bp
new file mode 100644
index 0000000..0ed69e4
--- /dev/null
+++ b/sax/java/Android.bp
@@ -0,0 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-sax-sources",
+    srcs: ["**/*.java"],
+    visibility: ["//frameworks/base"],
+}
diff --git a/services/Android.bp b/services/Android.bp
index 872b118..0a01c95 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -107,6 +107,7 @@
     libs: [
         "android.hidl.manager-V1.0-java",
         "framework-tethering.stubs.module_lib",
+        "service-art.stubs.system_server",
     ],
 
     // Uncomment to enable output of certain warnings (deprecated, unchecked)
@@ -146,7 +147,7 @@
         " --hide DeprecationMismatch" +
         " --hide HiddenTypedefConstant",
     visibility: ["//visibility:private"],
-    filter_packages: ["com.android."]
+    filter_packages: ["com.android."],
 }
 
 droidstubs {
@@ -161,7 +162,7 @@
         last_released: {
             api_file: ":android.api.system-server.latest",
             removed_api_file: ":removed.api.system-server.latest",
-            baseline_file: ":android-incompatibilities.api.system-server.latest"
+            baseline_file: ":android-incompatibilities.api.system-server.latest",
         },
         api_lint: {
             enabled: true,
@@ -171,18 +172,24 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system-server/api",
             dest: "android.txt",
-            tag: ".api.txt"
+            tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system-server/api",
             dest: "removed.txt",
             tag: ".removed-api.txt",
         },
-    ]
+    ],
 }
 
 java_library {
@@ -216,16 +223,22 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system-server/api",
             dest: "android-non-updatable.txt",
-            tag: ".api.txt"
+            tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system-server/api",
             dest: "android-non-updatable-removed.tx",
             tag: ".removed-api.txt",
         },
-    ]
-}
\ No newline at end of file
+    ],
+}
diff --git a/services/api/current.txt b/services/api/current.txt
index 17ca369..7c5c01e 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -80,6 +80,14 @@
 
 }
 
+package com.android.server.stats {
+
+  public final class StatsHelper {
+    method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context);
+  }
+
+}
+
 package com.android.server.wifi {
 
   public class SupplicantManager {
diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt
index 647739f..6419b70 100644
--- a/services/api/non-updatable-current.txt
+++ b/services/api/non-updatable-current.txt
@@ -35,6 +35,14 @@
 
 }
 
+package com.android.server.stats {
+
+  public final class StatsHelper {
+    method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context);
+  }
+
+}
+
 package com.android.server.wifi {
 
   public class SupplicantManager {
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index ba2a63a..cc36b47 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -9,4 +9,3 @@
 niamhfw@google.com
 philippov@google.com
 rthakohov@google.com
-tobiast@google.com
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b737189..5aa3e5b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,8 @@
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
 import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -108,6 +110,7 @@
 import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
 import android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.BlockedReason;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.ConnectivityManager.RestrictBackgroundStatus;
 import android.net.ConnectivityResources;
@@ -315,6 +318,9 @@
     // The maximum number of network request allowed per uid before an exception is thrown.
     private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
 
+    // The maximum number of network request allowed for system UIDs before an exception is thrown.
+    private static final int MAX_NETWORK_REQUESTS_PER_SYSTEM_UID = 250;
+
     @VisibleForTesting
     protected int mLingerDelayMs;  // Can't be final, or test subclass constructors can't change it.
     @VisibleForTesting
@@ -330,6 +336,7 @@
     protected final PermissionMonitor mPermissionMonitor;
 
     private final PerUidCounter mNetworkRequestCounter;
+    private final PerUidCounter mSystemNetworkRequestCounter;
 
     private volatile boolean mLockdownEnabled;
 
@@ -1146,8 +1153,8 @@
         /**
          * @see NetworkUtils#queryUserAccess(int, int)
          */
-        public boolean queryUserAccess(int uid, int netId) {
-            return NetworkUtils.queryUserAccess(uid, netId);
+        public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) {
+            return cs.queryUserAccess(uid, network);
         }
 
         /**
@@ -1198,6 +1205,7 @@
         mContext = Objects.requireNonNull(context, "missing Context");
         mResources = deps.getResources(mContext);
         mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
+        mSystemNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID);
 
         mMetricsLog = logger;
         mNetworkRanker = new NetworkRanker();
@@ -1273,14 +1281,22 @@
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
+        mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
         // Listen for user add/removes to inform PermissionMonitor.
         // Should run on mHandler to avoid any races.
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_ADDED);
-        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        final IntentFilter userIntentFilter = new IntentFilter();
+        userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+        userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mUserAllContext.registerReceiver(mUserIntentReceiver, userIntentFilter,
+                null /* broadcastPermission */, mHandler);
 
-        mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
-        mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+        // Listen to package add/removes for netd
+        final IntentFilter packageIntentFilter = new IntentFilter();
+        packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        packageIntentFilter.addDataScheme("package");
+        mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
                 null /* broadcastPermission */, mHandler);
 
         mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
@@ -1548,16 +1564,16 @@
         mNetworkInfoBlockingLogs.log(action + " " + uid);
     }
 
-    private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net,
-            boolean blocked) {
+    private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net, int blocked) {
         if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
             return;
         }
-        final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+        final String action = (blocked != 0) ? "BLOCKED" : "UNBLOCKED";
         final int requestId = nri.getActiveRequest() != null
                 ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
         mNetworkInfoBlockingLogs.log(String.format(
-                "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId()));
+                "%s %d(%d) on netId %d: %s", action, nri.mAsUid, requestId, net.getNetId(),
+                blockedReasonsToString(blocked)));
     }
 
     /**
@@ -1887,6 +1903,10 @@
             newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
         }
         newNc.setAdministratorUids(new int[0]);
+        if (!checkAnyPermissionOf(
+                callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
+            newNc.setSubIds(Collections.emptySet());
+        }
 
         return newNc;
     }
@@ -2338,15 +2358,15 @@
 
     private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
         @Override
-        public void onUidBlockedReasonChanged(int uid, int blockedReasons) {
+        public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
             mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
                     uid, blockedReasons));
         }
     };
 
-    void handleUidBlockedReasonChanged(int uid, int blockedReasons) {
+    private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
         maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
-        mUidBlockedReasons.put(uid, blockedReasons);
+        setUidBlockedReasons(uid, blockedReasons);
     }
 
     private boolean checkAnyPermissionOf(String... permissions) {
@@ -3119,6 +3139,13 @@
                     }
                     break;
                 }
+                case NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED: {
+                    if (msg.arg1 >= 0 && msg.arg1 <= NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
+                        nai.teardownDelayMs = msg.arg1;
+                    } else {
+                        logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
+                    }
+                }
             }
         }
 
@@ -3689,6 +3716,23 @@
         mLegacyTypeTracker.remove(nai, wasDefault);
         rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
+
+        // Immediate teardown.
+        if (nai.teardownDelayMs == 0) {
+            destroyNetwork(nai);
+            return;
+        }
+
+        // Delayed teardown.
+        try {
+            mNetd.networkSetPermissionForNetwork(nai.network.netId, INetd.PERMISSION_SYSTEM);
+        } catch (RemoteException e) {
+            Log.d(TAG, "Error marking network restricted during teardown: " + e);
+        }
+        mHandler.postDelayed(() -> destroyNetwork(nai), nai.teardownDelayMs);
+    }
+
+    private void destroyNetwork(NetworkAgentInfo nai) {
         if (nai.created) {
             // Tell netd to clean up the configuration for this network
             // (routing rules, DNS, etc).
@@ -3701,6 +3745,7 @@
             mDnsManager.removeNetwork(nai.network);
         }
         mNetIdManager.releaseNetId(nai.network.getNetId());
+        nai.onNetworkDestroyed();
     }
 
     private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -3728,6 +3773,10 @@
     private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
         try {
             mNetd.networkDestroy(networkAgent.network.getNetId());
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Exception destroying network(networkDestroy): " + e);
+        }
+        try {
             mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             loge("Exception destroying network: " + e);
@@ -4001,7 +4050,7 @@
                 }
             }
         }
-        mNetworkRequestCounter.decrementCount(nri.mUid);
+        nri.decrementRequestCount();
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
 
         if (null != nri.getActiveRequest()) {
@@ -4112,6 +4161,12 @@
         }
     }
 
+    private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
+        return checkAnyPermissionOf(
+                nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+                ? mSystemNetworkRequestCounter : mNetworkRequestCounter;
+    }
+
     @Override
     public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
         enforceNetworkStackSettingsOrSetup();
@@ -4839,6 +4894,42 @@
         nai.networkMonitor().forceReevaluation(uid);
     }
 
+    // TODO: call into netd.
+    private boolean queryUserAccess(int uid, Network network) {
+        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai == null) return false;
+
+        // Any UID can use its default network.
+        if (nai == getDefaultNetworkForUid(uid)) return true;
+
+        // Privileged apps can use any network.
+        if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) {
+            return true;
+        }
+
+        // An unprivileged UID can use a VPN iff the VPN applies to it.
+        if (nai.isVPN()) {
+            return nai.networkCapabilities.appliesToUid(uid);
+        }
+
+        // An unprivileged UID can bypass the VPN that applies to it only if it can protect its
+        // sockets, i.e., if it is the owner.
+        final NetworkAgentInfo vpn = getVpnForUid(uid);
+        if (vpn != null && !vpn.networkAgentConfig.allowBypass
+                && uid != vpn.networkCapabilities.getOwnerUid()) {
+            return false;
+        }
+
+        // The UID's permission must be at least sufficient for the network. Since the restricted
+        // permission was already checked above, that just leaves background networks.
+        if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
+            return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
+        }
+
+        // Unrestricted network. Anyone gets to use it.
+        return true;
+    }
+
     /**
      * Returns information about the proxy a certain network is using. If given a null network, it
      * it will return the proxy for the bound network for the caller app or the default proxy if
@@ -4859,7 +4950,7 @@
                 return null;
             }
             return getLinkPropertiesProxyInfo(activeNetwork);
-        } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) {
+        } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) {
             // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
             // caller may not have.
             return getLinkPropertiesProxyInfo(network);
@@ -4879,7 +4970,7 @@
     }
 
     @Override
-    public void setGlobalProxy(final ProxyInfo proxyProperties) {
+    public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
         mProxyTracker.setGlobalProxy(proxyProperties);
     }
@@ -5224,14 +5315,14 @@
         }
     }
 
-    private void onUserAdded(UserHandle user) {
+    private void onUserAdded(@NonNull final UserHandle user) {
         mPermissionMonitor.onUserAdded(user);
         if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
             handleSetOemNetworkPreference(mOemNetworkPreferences, null);
         }
     }
 
-    private void onUserRemoved(UserHandle user) {
+    private void onUserRemoved(@NonNull final UserHandle user) {
         mPermissionMonitor.onUserRemoved(user);
         // If there was a network preference for this user, remove it.
         handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
@@ -5241,7 +5332,18 @@
         }
     }
 
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+    private void onPackageChanged(@NonNull final String packageName) {
+        // This is necessary in case a package is added or removed, but also when it's replaced to
+        // run as a new UID by its manifest rules. Also, if a separate package shares the same UID
+        // as one in the preferences, then it should follow the same routing as that other package,
+        // which means updating the rules is never to be needed in this case (whether it joins or
+        // leaves a UID with a preference).
+        if (isMappedInOemNetworkPreference(packageName)) {
+            handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+        }
+    }
+
+    private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             ensureRunningOnConnectivityServiceThread();
@@ -5264,6 +5366,22 @@
         }
     };
 
+    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            ensureRunningOnConnectivityServiceThread();
+            switch (intent.getAction()) {
+                case Intent.ACTION_PACKAGE_ADDED:
+                case Intent.ACTION_PACKAGE_REMOVED:
+                case Intent.ACTION_PACKAGE_REPLACED:
+                    onPackageChanged(intent.getData().getSchemeSpecificPart());
+                    break;
+                default:
+                    Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
+            }
+        }
+    };
+
     private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
 
@@ -5374,6 +5492,9 @@
         @Nullable
         final String mCallingAttributionTag;
 
+        // Counter keeping track of this NRI.
+        final PerUidCounter mPerUidCounter;
+
         // Effective UID of this request. This is different from mUid when a privileged process
         // files a request on behalf of another UID. This UID is used to determine blocked status,
         // UID matching, and so on. mUid above is used for permission checks and to enforce the
@@ -5424,7 +5545,8 @@
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mAsUid = asUid;
-            mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mPerUidCounter = getRequestCounter(this);
+            mPerUidCounter.incrementCountOrThrow(mUid);
             /**
              * Location sensitive data not included in pending intent. Only included in
              * {@link NetworkCallback}.
@@ -5456,15 +5578,11 @@
             mUid = mDeps.getCallingUid();
             mAsUid = asUid;
             mPendingIntent = null;
-            mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mPerUidCounter = getRequestCounter(this);
+            mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = callbackFlags;
             mCallingAttributionTag = callingAttributionTag;
-
-            try {
-                mBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
+            linkDeathRecipient();
         }
 
         NetworkRequestInfo(@NonNull final NetworkRequestInfo nri,
@@ -5499,9 +5617,11 @@
             mUid = nri.mUid;
             mAsUid = nri.mAsUid;
             mPendingIntent = nri.mPendingIntent;
-            mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mPerUidCounter = getRequestCounter(this);
+            mPerUidCounter.incrementCountOrThrow(mUid);
             mCallbackFlags = nri.mCallbackFlags;
             mCallingAttributionTag = nri.mCallingAttributionTag;
+            linkDeathRecipient();
         }
 
         NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
@@ -5530,8 +5650,22 @@
             return Collections.unmodifiableList(tempRequests);
         }
 
+        void decrementRequestCount() {
+            mPerUidCounter.decrementCount(mUid);
+        }
+
+        void linkDeathRecipient() {
+            if (null != mBinder) {
+                try {
+                    mBinder.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    binderDied();
+                }
+            }
+        }
+
         void unlinkDeathRecipient() {
-            if (mBinder != null) {
+            if (null != mBinder) {
                 mBinder.unlinkToDeath(this, 0);
             }
         }
@@ -5552,7 +5686,7 @@
                     + mNetworkRequestForCallback.requestId
                     + " " + mRequests
                     + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
-                    + "callback flags: " + mCallbackFlags;
+                    + " callback flags: " + mCallbackFlags;
         }
     }
 
@@ -5577,6 +5711,10 @@
                     "Insufficient permissions to request a specific signal strength");
         }
         mAppOpsManager.checkPackage(callerUid, callerPackageName);
+
+        if (!nc.getSubIds().isEmpty()) {
+            enforceNetworkFactoryPermission();
+        }
     }
 
     private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
@@ -6067,6 +6205,15 @@
     @NonNull
     private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
 
+    /**
+     * Determine whether a given package has a mapping in the current OemNetworkPreferences.
+     * @param packageName the package name to check existence of a mapping for.
+     * @return true if a mapping exists, false otherwise
+     */
+    private boolean isMappedInOemNetworkPreference(@NonNull final String packageName) {
+        return mOemNetworkPreferences.getNetworkPreferences().containsKey(packageName);
+    }
+
     // The always-on request for an Internet-capable network that apps without a specific default
     // fall back to.
     @VisibleForTesting
@@ -6087,7 +6234,7 @@
      * @return the NetworkRequestInfo tracking the given uid.
      */
     @NonNull
-    private NetworkRequestInfo getDefaultRequestTrackingUid(@NonNull final int uid) {
+    private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
         for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
             if (nri == mDefaultRequest) {
                 continue;
@@ -6213,8 +6360,8 @@
     // Request used to optionally keep vehicle internal network always active
     private final NetworkRequest mDefaultVehicleRequest;
 
-    // TODO replace with INetd.DUMMY_NET_ID when available.
-    private static final int NO_SERVICE_NET_ID = 51;
+    // TODO replace with INetd.UNREACHABLE_NET_ID when available.
+    private static final int NO_SERVICE_NET_ID = 52;
     // Sentinel NAI used to direct apps with default networks that should have no connectivity to a
     // network with no service. This NAI should never be matched against, nor should any public API
     // ever return the associated network. For this reason, this NAI is not in the list of available
@@ -6534,7 +6681,7 @@
                     mDeps.reportNetworkInterfaceForTransports(mContext, iface,
                             caps.getTransportTypes());
                 } catch (Exception e) {
-                    loge("Exception adding interface: " + e);
+                    logw("Exception adding interface: " + e);
                 }
             }
         }
@@ -7308,7 +7455,7 @@
                 break;
             }
             case ConnectivityManager.CALLBACK_BLK_CHANGED: {
-                maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1 != 0);
+                maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1);
                 msg.arg1 = arg1;
                 break;
             }
@@ -8052,12 +8199,11 @@
             return;
         }
 
+        final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
         final boolean metered = nai.networkCapabilities.isMetered();
-        boolean blocked;
-        blocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
-        blocked |= NetworkPolicyManager.isUidBlocked(
-                mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE), metered);
-        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
+        final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
+        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
+                getBlockedState(blockedReasons, metered, vpnBlocked));
     }
 
     // Notify the requests on this NAI that the network is now lingered.
@@ -8066,6 +8212,21 @@
         notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
     }
 
+    private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
+        if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
+        return vpnBlocked
+                ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
+                : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
+    }
+
+    private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
+        if (blockedReasons == BLOCKED_REASON_NONE) {
+            mUidBlockedReasons.delete(uid);
+        } else {
+            mUidBlockedReasons.put(uid, blockedReasons);
+        }
+    }
+
     /**
      * Notify of the blocked state apps with a registered callback matching a given NAI.
      *
@@ -8073,7 +8234,10 @@
      * any given nai, all requests need to be considered according to the uid who filed it.
      *
      * @param nai The target NetworkAgentInfo.
-     * @param oldMetered True if the previous network capabilities is metered.
+     * @param oldMetered True if the previous network capabilities were metered.
+     * @param newMetered True if the current network capabilities are metered.
+     * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
+     * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
      */
     private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
             boolean newMetered, List<UidRange> oldBlockedUidRanges,
@@ -8082,22 +8246,18 @@
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest nr = nai.requestAt(i);
             NetworkRequestInfo nri = mNetworkRequests.get(nr);
-            final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
 
-            oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
-            newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
+            final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
+            final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
+            final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
                     ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
                     : oldVpnBlocked;
 
-            final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
-            oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked(
-                    blockedReasons, oldMetered);
-            newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked(
-                    blockedReasons, newMetered);
-
-            if (oldBlocked != newBlocked) {
+            final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
+            final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
+            if (oldBlockedState != newBlockedState) {
                 callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
-                        encodeBool(newBlocked));
+                        newBlockedState);
             }
         }
     }
@@ -8107,25 +8267,23 @@
      * @param uid The uid for which the rules changed.
      * @param blockedReasons The reasons for why an uid is blocked.
      */
-    private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) {
+    private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
         for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             final boolean metered = nai.networkCapabilities.isMetered();
             final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
-            final boolean oldBlocked, newBlocked;
 
-            oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
-                    mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered);
-            newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
-                    blockedReasons, metered);
-            if (oldBlocked == newBlocked) {
+            final int oldBlockedState = getBlockedState(
+                    mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
+            final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
+            if (oldBlockedState == newBlockedState) {
                 continue;
             }
-            final int arg = encodeBool(newBlocked);
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
                 NetworkRequest nr = nai.requestAt(i);
                 NetworkRequestInfo nri = mNetworkRequests.get(nr);
                 if (nri != null && nri.mAsUid == uid) {
-                    callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
+                    callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
+                            newBlockedState);
                 }
             }
         }
@@ -8673,7 +8831,7 @@
             // Decrement the reference count for this NetworkRequestInfo. The reference count is
             // incremented when the NetworkRequestInfo is created as part of
             // enforceRequestCountLimit().
-            mNetworkRequestCounter.decrementCount(nri.mUid);
+            nri.decrementRequestCount();
             return;
         }
 
@@ -8739,7 +8897,7 @@
         // Decrement the reference count for this NetworkRequestInfo. The reference count is
         // incremented when the NetworkRequestInfo is created as part of
         // enforceRequestCountLimit().
-        mNetworkRequestCounter.decrementCount(nri.mUid);
+        nri.decrementRequestCount();
 
         iCb.unlinkToDeath(cbInfo, 0);
     }
@@ -9315,14 +9473,8 @@
             throw new IllegalArgumentException("Must explicitly specify a user handle ("
                     + "UserHandle.CURRENT not supported)");
         }
-        final UserManager um;
-        try {
-            um = mContext.createContextAsUser(profile, 0 /* flags */)
-                    .getSystemService(UserManager.class);
-        } catch (IllegalStateException e) {
-            throw new IllegalArgumentException("Profile does not exist");
-        }
-        if (!um.isManagedProfile()) {
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        if (!um.isManagedProfile(profile.getIdentifier())) {
             throw new IllegalArgumentException("Profile must be a managed profile");
         }
         // Strictly speaking, mOemNetworkPreferences should only be touched on the
@@ -9489,7 +9641,6 @@
                 new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
         replaceDefaultNetworkRequestsForPreference(nris);
         mOemNetworkPreferences = preference;
-        // TODO http://b/176496396 persist data to shared preferences.
 
         if (null != listener) {
             try {
@@ -9646,7 +9797,6 @@
                     // packages are sent on a network preference as the system will watch for
                     // package installations associated with this network preference and update
                     // accordingly. This is done so as to minimize race conditions on app install.
-                    // TODO b/177092163 add app install watching.
                     continue;
                 }
             }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 3bcde12..9821cdc 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -20,6 +20,7 @@
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppOp* = file:/core/java/android/permission/OWNERS
 per-file *Battery* = file:/BATTERY_STATS_OWNERS
+per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
 per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
 per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
 per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 351e616..c6fdb9d 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -45,6 +44,7 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.security.MessageDigest;
@@ -131,13 +131,13 @@
     private static final String FLASH_LOCK_UNLOCKED = "0";
 
     private final Context mContext;
+    private final String mDataBlockFile;
     private final boolean mIsRunningDSU;
     private final Object mLock = new Object();
     private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);
 
     private int mAllowedUid = -1;
     private long mBlockDeviceSize;
-    private String mDataBlockFile;
 
     @GuardedBy("mLock")
     private boolean mIsWritable = true;
@@ -145,8 +145,12 @@
     public PersistentDataBlockService(Context context) {
         super(context);
         mContext = context;
-        mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
         mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
+        if (mIsRunningDSU) {
+            mDataBlockFile = GSI_SANDBOX;
+        } else {
+            mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
+        }
         mBlockDeviceSize = -1; // Load lazily
     }
 
@@ -260,7 +264,11 @@
     private long getBlockDeviceSize() {
         synchronized (mLock) {
             if (mBlockDeviceSize == -1) {
-                mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+                if (mIsRunningDSU) {
+                    mBlockDeviceSize = MAX_DATA_BLOCK_SIZE;
+                } else {
+                    mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+                }
             }
         }
 
@@ -290,40 +298,30 @@
         return true;
     }
 
-    private FileOutputStream getBlockOutputStream() throws IOException {
-        if (!mIsRunningDSU) {
-            return new FileOutputStream(new File(mDataBlockFile));
-        } else {
-            File sandbox = new File(GSI_SANDBOX);
-            File realpdb = new File(SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP));
-            if (!sandbox.exists()) {
-                FileUtils.copy(realpdb, sandbox);
-                mDataBlockFile = GSI_SANDBOX;
-            }
-            Slog.i(TAG, "PersistentDataBlock copy-on-write");
-            return new FileOutputStream(sandbox);
-        }
+    private FileChannel getBlockOutputChannel() throws IOException {
+        return new RandomAccessFile(mDataBlockFile, "rw").getChannel();
     }
 
     private boolean computeAndWriteDigestLocked() {
         byte[] digest = computeDigestLocked(null);
         if (digest != null) {
-            DataOutputStream outputStream;
+            FileChannel channel;
             try {
-                outputStream = new DataOutputStream(getBlockOutputStream());
+                channel = getBlockOutputChannel();
             } catch (IOException e) {
                 Slog.e(TAG, "partition not available?", e);
                 return false;
             }
 
             try {
-                outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
-                outputStream.flush();
+                ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES);
+                buf.put(digest);
+                buf.flip();
+                channel.write(buf);
+                channel.force(true);
             } catch (IOException e) {
                 Slog.e(TAG, "failed to write block checksum", e);
                 return false;
-            } finally {
-                IoUtils.closeQuietly(outputStream);
             }
             return true;
         } else {
@@ -374,25 +372,18 @@
     }
 
     private void formatPartitionLocked(boolean setOemUnlockEnabled) {
-        DataOutputStream outputStream;
-        try {
-            outputStream = new DataOutputStream(getBlockOutputStream());
-        } catch (IOException e) {
-            Slog.e(TAG, "partition not available?", e);
-            return;
-        }
 
-        byte[] data = new byte[DIGEST_SIZE_BYTES];
         try {
-            outputStream.write(data, 0, DIGEST_SIZE_BYTES);
-            outputStream.writeInt(PARTITION_TYPE_MARKER);
-            outputStream.writeInt(0); // data size
-            outputStream.flush();
+            FileChannel channel = getBlockOutputChannel();
+            ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
+            buf.put(new byte[DIGEST_SIZE_BYTES]);
+            buf.putInt(PARTITION_TYPE_MARKER);
+            buf.putInt(0);
+            channel.write(buf);
+            channel.force(true);
         } catch (IOException e) {
             Slog.e(TAG, "failed to format block", e);
             return;
-        } finally {
-            IoUtils.closeQuietly(outputStream);
         }
 
         doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
@@ -400,16 +391,9 @@
     }
 
     private void doSetOemUnlockEnabledLocked(boolean enabled) {
-        FileOutputStream outputStream;
-        try {
-            outputStream = getBlockOutputStream();
-        } catch (IOException e) {
-            Slog.e(TAG, "partition not available", e);
-            return;
-        }
 
         try {
-            FileChannel channel = outputStream.getChannel();
+            FileChannel channel = getBlockOutputChannel();
 
             channel.position(getBlockDeviceSize() - 1);
 
@@ -417,13 +401,12 @@
             data.put(enabled ? (byte) 1 : (byte) 0);
             data.flip();
             channel.write(data);
-            outputStream.flush();
+            channel.force(true);
         } catch (IOException e) {
             Slog.e(TAG, "unable to access persistent partition", e);
             return;
         } finally {
             SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
-            IoUtils.closeQuietly(outputStream);
         }
     }
 
@@ -477,35 +460,32 @@
                 return (int) -maxBlockSize;
             }
 
-            DataOutputStream outputStream;
+            FileChannel channel;
             try {
-                outputStream = new DataOutputStream(getBlockOutputStream());
+                channel = getBlockOutputChannel();
             } catch (IOException e) {
                 Slog.e(TAG, "partition not available?", e);
-                return -1;
+               return -1;
             }
 
-            ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
+            ByteBuffer headerAndData = ByteBuffer.allocate(
+                                           data.length + HEADER_SIZE + DIGEST_SIZE_BYTES);
+            headerAndData.put(new byte[DIGEST_SIZE_BYTES]);
             headerAndData.putInt(PARTITION_TYPE_MARKER);
             headerAndData.putInt(data.length);
             headerAndData.put(data);
-
+            headerAndData.flip();
             synchronized (mLock) {
                 if (!mIsWritable) {
-                    IoUtils.closeQuietly(outputStream);
                     return -1;
                 }
 
                 try {
-                    byte[] checksum = new byte[DIGEST_SIZE_BYTES];
-                    outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
-                    outputStream.write(headerAndData.array());
-                    outputStream.flush();
+                    channel.write(headerAndData);
+                    channel.force(true);
                 } catch (IOException e) {
                     Slog.e(TAG, "failed writing to the persistent data block", e);
                     return -1;
-                } finally {
-                    IoUtils.closeQuietly(outputStream);
                 }
 
                 if (computeAndWriteDigestLocked()) {
@@ -565,17 +545,6 @@
         public void wipe() {
             enforceOemUnlockWritePermission();
 
-            if (mIsRunningDSU) {
-                File sandbox = new File(GSI_SANDBOX);
-                if (sandbox.exists()) {
-                    if (sandbox.delete()) {
-                        mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
-                    } else {
-                        Slog.e(TAG, "Failed to wipe sandbox persistent data block");
-                    }
-                }
-                return;
-            }
             synchronized (mLock) {
                 int ret = nativeWipe(mDataBlockFile);
 
@@ -733,28 +702,18 @@
         }
 
         private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
-            FileOutputStream outputStream;
-            try {
-                outputStream = getBlockOutputStream();
-            } catch (IOException e) {
-                Slog.e(TAG, "partition not available", e);
-                return;
-            }
             synchronized (mLock) {
                 if (!mIsWritable) {
-                    IoUtils.closeQuietly(outputStream);
                     return;
                 }
                 try {
-                    FileChannel channel = outputStream.getChannel();
+                    FileChannel channel = getBlockOutputChannel();
                     channel.position(offset);
                     channel.write(dataBuffer);
-                    outputStream.flush();
+                    channel.force(true);
                 } catch (IOException e) {
                     Slog.e(TAG, "unable to access persistent partition", e);
                     return;
-                } finally {
-                    IoUtils.closeQuietly(outputStream);
                 }
 
                 computeAndWriteDigestLocked();
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..1241b77 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -270,18 +270,9 @@
      * Handler for on start pinning message
      */
     private void handlePinOnStart() {
-        final String bootImage = SystemProperties.get("dalvik.vm.boot-image", "");
-        String[] filesToPin = null;
-        if (bootImage.endsWith("boot-image.prof")) {
-            // Use the files listed for that specific boot image.
-            // TODO: find a better way to know we're using the JIT zygote configuration.
-            filesToPin = mContext.getResources().getStringArray(
-                  com.android.internal.R.array.config_jitzygoteBootImagePinnerServiceFiles);
-        } else {
-            // Files to pin come from the overlay and can be specified per-device config
-            filesToPin = mContext.getResources().getStringArray(
-                  com.android.internal.R.array.config_defaultPinnerServiceFiles);
-        }
+        // Files to pin come from the overlay and can be specified per-device config
+        String[] filesToPin = mContext.getResources().getStringArray(
+            com.android.internal.R.array.config_defaultPinnerServiceFiles);
         // Continue trying to pin each file even if we fail to pin some of them
         for (String fileToPin : filesToPin) {
             PinnedFile pf = pinFile(fileToPin,
@@ -291,10 +282,32 @@
                 Slog.e(TAG, "Failed to pin file = " + fileToPin);
                 continue;
             }
-
             synchronized (this) {
                 mPinnedFiles.add(pf);
             }
+            if (fileToPin.endsWith(".jar") | fileToPin.endsWith(".apk")) {
+                // Check whether the runtime has compilation artifacts to pin.
+                String arch = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
+                String[] files = null;
+                try {
+                    files = DexFile.getDexFileOutputPaths(fileToPin, arch);
+                } catch (IOException ioe) { }
+                if (files == null) {
+                    continue;
+                }
+                for (String file : files) {
+                    PinnedFile df = pinFile(file,
+                                            Integer.MAX_VALUE,
+                                            /*attemptPinIntrospection=*/false);
+                    if (df == null) {
+                        Slog.i(TAG, "Failed to pin ART file = " + file);
+                        continue;
+                    }
+                    synchronized (this) {
+                        mPinnedFiles.add(df);
+                    }
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a95589b..0affda4 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -402,10 +402,15 @@
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
                     if (VDBG) log("MSG_USER_SWITCHED userId=" + msg.arg1);
-                    int numPhones = getTelephonyManager().getPhoneCount();
-                    for (int sub = 0; sub < numPhones; sub++) {
-                        TelephonyRegistry.this.notifyCellLocationForSubscriber(sub,
-                                mCellIdentity[sub]);
+                    int numPhones = getTelephonyManager().getActiveModemCount();
+                    for (int phoneId = 0; phoneId < numPhones; phoneId++) {
+                        int[] subIds = SubscriptionManager.getSubId(phoneId);
+                        int subId =
+                                (subIds != null) && (subIds.length > 0)
+                                        ? subIds[0]
+                                        : SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+                        TelephonyRegistry.this.notifyCellLocationForSubscriber(
+                                subId, mCellIdentity[phoneId], true /* hasUserSwitched */);
                     }
                     break;
                 }
@@ -1879,20 +1884,20 @@
     }
 
     @Override
-    public void notifyCellLocation(CellIdentity cellLocation) {
-        notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
+    public void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity) {
+        notifyCellLocationForSubscriber(subId, cellIdentity, false /* hasUserSwitched */);
     }
 
-    @Override
-    public void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity) {
-        log("notifyCellLocationForSubscriber: subId=" + subId
-                + " cellIdentity=" + cellIdentity);
+    private void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity,
+            boolean hasUserSwitched) {
+        log("notifyCellLocationForSubscriber: subId=" + subId + " cellIdentity=" + cellIdentity);
         if (!checkNotifyPermission("notifyCellLocation()")) {
             return;
         }
         int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
-            if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) {
+            if (validatePhoneId(phoneId)
+                    && (hasUserSwitched || !Objects.equals(cellIdentity, mCellIdentity[phoneId]))) {
                 mCellIdentity[phoneId] = cellIdentity;
                 for (Record r : mRecords) {
                     if (validateEventAndUserLocked(
@@ -2553,7 +2558,7 @@
             final int recordCount = mRecords.size();
             pw.println("last known state:");
             pw.increaseIndent();
-            for (int i = 0; i < getTelephonyManager().getPhoneCount(); i++) {
+            for (int i = 0; i < getTelephonyManager().getActiveModemCount(); i++) {
                 pw.println("Phone Id=" + i);
                 pw.increaseIndent();
                 pw.println("mCallState=" + mCallState[i]);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 4622e98..f7ae58c 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -35,13 +37,13 @@
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
+import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.TelephonyNetworkSpecifier;
+import android.net.NetworkRequest;
 import android.net.vcn.IVcnManagementService;
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
-import android.net.vcn.VcnManager;
 import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnManager.VcnStatusCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
@@ -163,6 +165,9 @@
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final BroadcastReceiver mPkgChangeReceiver;
 
+    @NonNull
+    private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback();
+
     /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
     @Nullable private LocationPermissionChecker mLocationPermissionChecker;
 
@@ -359,6 +364,10 @@
     public void systemReady() {
         mContext.getSystemService(ConnectivityManager.class)
                 .registerNetworkProvider(mNetworkProvider);
+        mContext.getSystemService(ConnectivityManager.class)
+                .registerNetworkCallback(
+                        new NetworkRequest.Builder().clearCapabilities().build(),
+                        mTrackingNetworkCallback);
         mTelephonySubscriptionTracker.register();
         mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
     }
@@ -533,15 +542,7 @@
 
         if (mVcns.containsKey(subscriptionGroup)) {
             final Vcn vcn = mVcns.get(subscriptionGroup);
-            final boolean isActive = vcn.isActive();
             vcn.updateConfig(config);
-
-            // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
-            if (!isActive) {
-                // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
-                notifyAllPermissionedStatusCallbacksLocked(
-                        subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
-            }
         } else {
             startVcnLocked(subscriptionGroup, config);
         }
@@ -717,19 +718,29 @@
         });
     }
 
-    private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
-        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
-            TelephonyNetworkSpecifier telephonyNetworkSpecifier =
-                    (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier();
-            return telephonyNetworkSpecifier.getSubscriptionId();
-        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
-                && networkCapabilities.getTransportInfo() instanceof WifiInfo) {
-            WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
-            return mDeps.getSubIdForWifiInfo(wifiInfo);
+    private ParcelUuid getSubGroupForNetworkCapabilities(
+            @NonNull NetworkCapabilities networkCapabilities) {
+        ParcelUuid subGrp = null;
+        final TelephonySubscriptionSnapshot snapshot;
+
+        // Always access mLastSnapshot under lock. Technically this can be treated as a volatile
+        // but for consistency and safety, always access under lock.
+        synchronized (mLock) {
+            snapshot = mLastSnapshot;
         }
 
-        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        // If multiple subscription IDs exist, they MUST all point to the same subscription
+        // group. Otherwise undefined behavior may occur.
+        for (int subId : networkCapabilities.getSubIds()) {
+            // Verify that all subscriptions point to the same group
+            if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) {
+                Slog.wtf(TAG, "Got multiple subscription groups for a single network");
+            }
+
+            subGrp = snapshot.getGroupForSubId(subId);
+        }
+
+        return subGrp;
     }
 
     /**
@@ -754,23 +765,19 @@
             // mutates
             final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities);
 
-            final int subId = getSubIdForNetworkCapabilities(ncCopy);
+            final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy);
             boolean isVcnManagedNetwork = false;
             boolean isRestrictedCarrierWifi = false;
-            if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                synchronized (mLock) {
-                    ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
+            synchronized (mLock) {
+                final Vcn vcn = mVcns.get(subGrp);
+                if (vcn != null) {
+                    if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) {
+                        isVcnManagedNetwork = true;
+                    }
 
-                    final Vcn vcn = mVcns.get(subGroup);
-                    if (vcn != null) {
-                        if (vcn.isActive()) {
-                            isVcnManagedNetwork = true;
-                        }
-
-                        if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-                            // Carrier WiFi always restricted if VCN exists (even in safe mode).
-                            isRestrictedCarrierWifi = true;
-                        }
+                    if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                        // Carrier WiFi always restricted if VCN exists (even in safe mode).
+                        isRestrictedCarrierWifi = true;
                     }
                 }
             }
@@ -787,8 +794,9 @@
                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
             }
 
+            final NetworkCapabilities result = ncBuilder.build();
             return new VcnUnderlyingNetworkPolicy(
-                    false /* isTearDownRequested */, ncBuilder.build());
+                    mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
         });
     }
 
@@ -875,20 +883,23 @@
                 // now that callback is registered, send it the VCN's current status
                 final VcnConfig vcnConfig = mConfigs.get(subGroup);
                 final Vcn vcn = mVcns.get(subGroup);
-                final int vcnStatus;
+                final int vcnStatus =
+                        vcn == null ? VCN_STATUS_CODE_NOT_CONFIGURED : vcn.getStatus();
+                final int resultStatus;
                 if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
+                    resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
                 } else if (vcn == null) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE;
-                } else if (vcn.isActive()) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE;
+                    resultStatus = VCN_STATUS_CODE_INACTIVE;
+                } else if (vcnStatus == VCN_STATUS_CODE_ACTIVE
+                        || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) {
+                    resultStatus = vcnStatus;
                 } else {
-                    // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+                    Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus);
+                    resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
                 }
 
                 try {
-                    cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+                    cbInfo.mCallback.onVcnStatusChanged(resultStatus);
                 } catch (RemoteException e) {
                     Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
                 }
@@ -921,17 +932,60 @@
     // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
     /** Callback for Vcn signals sent up to VcnManagementService. */
     public interface VcnCallback {
-        /** Called by a Vcn to signal that it has entered safe mode. */
-        void onEnteredSafeMode();
+        /** Called by a Vcn to signal that its safe mode status has changed. */
+        void onSafeModeStatusChanged(boolean isInSafeMode);
 
         /** Called by a Vcn to signal that an error occurred. */
         void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
     }
 
+    /**
+     * TrackingNetworkCallback tracks all active networks
+     *
+     * <p>This is used to ensure that no underlying networks have immutable capabilities changed
+     * without requiring a Network restart.
+     */
+    private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>();
+
+        @Override
+        public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
+            synchronized (mCaps) {
+                mCaps.put(network, caps);
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            synchronized (mCaps) {
+                mCaps.remove(network);
+            }
+        }
+
+        private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
+            if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) {
+                return false;
+            }
+
+            synchronized (mCaps) {
+                for (NetworkCapabilities existing : mCaps.values()) {
+                    if (existing.hasTransport(TRANSPORT_WIFI)
+                            && caps.getSubIds().equals(existing.getSubIds())) {
+                        // Restart if any immutable capabilities have changed
+                        return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                                != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+
     /** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
     private class VcnCallbackImpl implements VcnCallback {
         @NonNull private final ParcelUuid mSubGroup;
@@ -941,21 +995,24 @@
         }
 
         @Override
-        public void onEnteredSafeMode() {
+        public void onSafeModeStatusChanged(boolean isInSafeMode) {
             synchronized (mLock) {
                 // Ignore if this subscription group doesn't exist anymore
                 if (!mVcns.containsKey(mSubGroup)) {
                     return;
                 }
 
+                final int status =
+                        isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+
                 notifyAllPolicyListenersLocked();
-                notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
+                notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status);
             }
         }
 
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
@@ -971,7 +1028,7 @@
                         Binder.withCleanCallingIdentity(
                                 () ->
                                         cbInfo.mCallback.onGatewayConnectionError(
-                                                networkCapabilities,
+                                                gatewayConnectionName,
                                                 errorCode,
                                                 exceptionClass,
                                                 exceptionMessage));
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cc5a25a..2744f11 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -236,6 +236,7 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.location.LocationManager;
 import android.media.audiofx.AudioEffect;
+import android.net.ConnectivityManager;
 import android.net.Proxy;
 import android.net.Uri;
 import android.os.AppZygote;
@@ -16458,7 +16459,7 @@
                         stats.noteCurrentTimeChangedLocked();
                     }
                     break;
-                case Intent.ACTION_CLEAR_DNS_CACHE:
+                case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
                     mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                     break;
                 case Proxy.PROXY_CHANGE_ACTION:
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index d4eb104..72160c2 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -52,6 +52,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.VmSocketAddress;
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -63,8 +67,11 @@
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
-import java.io.IOException;
-import java.io.RandomAccessFile;
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -76,10 +83,10 @@
         void onHostClipboardUpdated(String contents);
     }
 
-    private RandomAccessFile mPipe = null;
+    private FileDescriptor mPipe = null;
     private HostClipboardCallback mHostClipboardCallback;
     private static final String PIPE_NAME = "pipe:clipboard";
-    private static final String PIPE_DEVICE = "/dev/qemu_pipe";
+    private static final int HOST_PORT = 5000;
 
     private static byte[] createOpenHandshake() {
         // String.getBytes doesn't include the null terminator,
@@ -93,37 +100,66 @@
 
     private boolean openPipe() {
         try {
-            final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw");
+            final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
+
             try {
-                pipe.write(createOpenHandshake());
-                mPipe = pipe;
+                Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
+
+                final byte[] handshake = createOpenHandshake();
+                Os.write(fd, handshake, 0, handshake.length);
+                mPipe = fd;
                 return true;
-            } catch (IOException ignore) {
-                pipe.close();
+            } catch (ErrnoException | SocketException | InterruptedIOException e) {
+                Os.close(fd);
             }
-        } catch (IOException ignore) {
+        } catch (ErrnoException e) {
         }
+
         return false;
     }
 
     private void closePipe() {
         try {
-            final RandomAccessFile pipe = mPipe;
+            final FileDescriptor fd = mPipe;
             mPipe = null;
-            if (pipe != null) {
-                pipe.close();
+            if (fd != null) {
+                Os.close(fd);
             }
-        } catch (IOException ignore) {
+        } catch (ErrnoException ignore) {
         }
     }
 
+    private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
+        final byte[] lengthBits = new byte[4];
+        Os.read(mPipe, lengthBits, 0, lengthBits.length);
+
+        final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        final int msgLen = bb.getInt();
+
+        final byte[] msg = new byte[msgLen];
+        Os.read(mPipe, msg, 0, msg.length);
+
+        return msg;
+    }
+
+    private void sendMessage(byte[] msg) throws ErrnoException, InterruptedIOException {
+        final byte[] lengthBits = new byte[4];
+        final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        bb.putInt(msg.length);
+
+        Os.write(mPipe, lengthBits, 0, lengthBits.length);
+        Os.write(mPipe, msg, 0, msg.length);
+    }
+
     public HostClipboardMonitor(HostClipboardCallback cb) {
         mHostClipboardCallback = cb;
     }
 
     @Override
     public void run() {
-        while(!Thread.interrupted()) {
+        while (!Thread.interrupted()) {
             try {
                 // There's no guarantee that QEMU pipes will be ready at the moment
                 // this method is invoked. We simply try to get the pipe open and
@@ -131,25 +167,23 @@
                 while ((mPipe == null) && !openPipe()) {
                     Thread.sleep(100);
                 }
-                int size = mPipe.readInt();
-                size = Integer.reverseBytes(size);
-                byte[] receivedData = new byte[size];
-                mPipe.readFully(receivedData);
+
+                final byte[] receivedData = receiveMessage();
                 mHostClipboardCallback.onHostClipboardUpdated(
                     new String(receivedData));
-            } catch (IOException e) {
+            } catch (ErrnoException | InterruptedIOException e) {
                 closePipe();
-            } catch (InterruptedException e) {}
+            } catch (InterruptedException e) {
+            }
         }
     }
 
     public void setHostClipboard(String content) {
         try {
             if (mPipe != null) {
-                mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
-                mPipe.write(content.getBytes());
+                sendMessage(content.getBytes());
             }
-        } catch(IOException e) {
+        } catch (ErrnoException | InterruptedIOException e) {
             Slog.e("HostClipboardMonitor",
                    "Failed to set host clipboard " + e.getMessage());
         }
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index ffeb77d..cf4fe1e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -420,7 +420,7 @@
         /*
          * Tell the VMs to toss their DNS caches
          */
-        final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
+        final Intent intent = new Intent(ConnectivityManager.ACTION_CLEAR_DNS_CACHE);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         /*
          * Connectivity events can happen before boot has completed ...
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7b20ded..058dac8 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -26,6 +26,7 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT;
 import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
 import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
 import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
@@ -518,6 +519,8 @@
             }
         } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
             throw new IllegalStateException("Unexpected stop reason: " + reason);
+        } else if (reason == ERROR_NO_SUCH_SLOT) {
+            throw new IllegalStateException("No such slot: " + reason);
         } else {
             notifyErrorCallback(ki.mCallback, reason);
         }
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index f3d2012..6ea84ce 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -18,12 +18,14 @@
 
 import static android.util.TimeUtils.NANOS_PER_MS;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetdEventCallback;
 import android.net.MacAddress;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.net.metrics.ConnectStats;
 import android.net.metrics.DnsEvent;
 import android.net.metrics.INetdEventListener;
@@ -98,6 +100,7 @@
     private final TokenBucket mConnectTb =
             new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
 
+    final TransportForNetIdNetworkCallback mCallback = new TransportForNetIdNetworkCallback();
 
     /**
      * There are only 3 possible callbacks.
@@ -158,6 +161,9 @@
     public NetdEventListenerService(ConnectivityManager cm) {
         // We are started when boot is complete, so ConnectivityService should already be running.
         mCm = cm;
+        // Clear all capabilities to listen all networks.
+        mCm.registerNetworkCallback(new NetworkRequest.Builder().clearCapabilities().build(),
+                mCallback);
     }
 
     private static long projectSnapshotTime(long timeMs) {
@@ -389,18 +395,13 @@
     }
 
     private long getTransports(int netId) {
-        // TODO: directly query ConnectivityService instead of going through Binder interface.
-        NetworkCapabilities nc = mCm.getNetworkCapabilities(new Network(netId));
+        final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
         if (nc == null) {
             return 0;
         }
         return BitUtils.packBits(nc.getTransportTypes());
     }
 
-    private static void maybeLog(String s, Object... args) {
-        if (DBG) Log.d(TAG, String.format(s, args));
-    }
-
     /** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
     static class NetworkMetricsSnapshot {
 
@@ -428,4 +429,29 @@
             return String.format("%tT.%tL: %s", timeMs, timeMs, j.toString());
         }
     }
+
+    private class TransportForNetIdNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private final SparseArray<NetworkCapabilities> mCapabilities = new SparseArray<>();
+
+        @Override
+        public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+            synchronized (mCapabilities) {
+                mCapabilities.put(network.getNetId(), nc);
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            synchronized (mCapabilities) {
+                mCapabilities.remove(network.getNetId());
+            }
+        }
+
+        @Nullable
+        public NetworkCapabilities getNetworkCapabilities(int netId) {
+            synchronized (mCapabilities) {
+                return mCapabilities.get(netId);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4963353..ee32fbf 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -201,6 +201,9 @@
     // Set to true when partial connectivity was detected.
     public boolean partialConnectivity;
 
+    // Delay between when the network is disconnected and when the native network is destroyed.
+    public int teardownDelayMs;
+
     // Captive portal info of the network from RFC8908, if any.
     // Obtained by ConnectivityService and merged into NetworkAgent-provided information.
     public CaptivePortalData capportApiData;
@@ -588,6 +591,17 @@
         }
     }
 
+    /**
+     * Notify the NetworkAgent that the native network has been destroyed.
+     */
+    public void onNetworkDestroyed() {
+        try {
+            networkAgent.onNetworkDestroyed();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending network destroyed event", e);
+        }
+    }
+
     // TODO: consider moving out of NetworkAgentInfo into its own class
     private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
         private final Handler mHandler;
@@ -664,6 +678,12 @@
                 @QosCallbackException.ExceptionType final int exceptionType) {
             mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
         }
+
+        @Override
+        public void sendTeardownDelayMs(int teardownDelayMs) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
+                    teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5e6b9f3..2e51be3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -36,7 +36,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
 
 import libcore.io.IoUtils;
 
@@ -446,7 +446,7 @@
                 int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
                 throws ErrnoException, IOException {
             final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                    TrafficStatsConstants.TAG_SYSTEM_PROBE);
+                    NetworkStackConstants.TAG_SYSTEM_PROBE);
             try {
                 mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
             } finally {
@@ -745,7 +745,7 @@
             if (ensureMeasurementNecessary()) return;
 
             // No need to restore the tag, since this thread is only used for this measurement.
-            TrafficStats.getAndSetThreadStatsTag(TrafficStatsConstants.TAG_SYSTEM_PROBE);
+            TrafficStats.getAndSetThreadStatsTag(NetworkStackConstants.TAG_SYSTEM_PROBE);
 
             try (SSLSocket sslSocket = setupSSLSocket()) {
                 sendDoTProbe(sslSocket);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 488677a..3711679 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -271,6 +271,13 @@
         return mApps.containsKey(uid);
     }
 
+    /**
+     * Returns whether the given uid has permission to use restricted networks.
+     */
+    public synchronized boolean hasRestrictedNetworksPermission(int uid) {
+        return Boolean.TRUE.equals(mApps.get(uid));
+    }
+
     private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
         List<Integer> network = new ArrayList<>();
         List<Integer> system = new ArrayList<>();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e5ce4f0..0a76bdc 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -101,7 +101,6 @@
 import android.provider.Settings;
 import android.security.Credentials;
 import android.security.KeyStore2;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
 import android.system.keystore2.Domain;
 import android.system.keystore2.KeyDescriptor;
@@ -463,7 +462,7 @@
                 .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
-                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
                 .build();
 
         loadAlwaysOnPackage();
@@ -527,7 +526,7 @@
     private void resetNetworkCapabilities() {
         mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
                 .setUids(null)
-                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
                 .build();
     }
 
@@ -1257,7 +1256,7 @@
         capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
 
-        capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+        capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType(), mConfig.session));
 
         // Only apps targeting Q and above can explicitly declare themselves as metered.
         // These VPNs are assumed metered unless they state otherwise.
@@ -2055,10 +2054,6 @@
         if (alias == null) {
             return null;
         }
-        // If Keystore 2.0 is not enabled the legacy private key prefix is used.
-        if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
-            return Credentials.USER_PRIVATE_KEY + alias;
-        }
         final KeyStore2 keystore2 = KeyStore2.getInstance();
 
         KeyDescriptor key = new KeyDescriptor();
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 6f12155..6a407e9 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -440,9 +440,8 @@
     }
 
     private float permissibleRatio(float currLux, float prevLux) {
-        return MathUtils.exp(MAX_GRAD
-                * (MathUtils.log(currLux + LUX_GRAD_SMOOTHING)
-                    - MathUtils.log(prevLux + LUX_GRAD_SMOOTHING)));
+        return MathUtils.pow((currLux + LUX_GRAD_SMOOTHING)
+                / (prevLux + LUX_GRAD_SMOOTHING), MAX_GRAD);
     }
 
     protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 470a25b..3d1a49e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -201,7 +201,6 @@
 
     // Only source devices that react to routing control messages should implement
     // this method (e.g. a TV with built in switch).
-    // TODO(): decide which type will handle the routing when multi device type is supported
     protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
         // do nothing
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 58a7025..8bb5204 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -800,7 +800,9 @@
         assertRunOnServiceThread();
         if (!mService.isPowerStandbyOrTransient()) {
             addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
-            if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+            if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+                startArcAction(false);
+            } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
                     && !hasAction(SetArcTransmissionStateAction.class)) {
                 startArcAction(true);
             }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index ee3427f..740407c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -35,9 +35,23 @@
 
     private final IHdmiControlService.Stub mBinderService;
 
+    final CountDownLatch mLatch;
+    AtomicInteger mCecResult;
+    IHdmiControlCallback.Stub mHdmiControlCallback;
 
     HdmiControlShellCommand(IHdmiControlService.Stub binderService) {
         mBinderService = binderService;
+        mLatch = new CountDownLatch(1);
+        mCecResult = new AtomicInteger();
+        mHdmiControlCallback =
+                new IHdmiControlCallback.Stub() {
+                    @Override
+                    public void onComplete(int result) {
+                        getOutPrintWriter().println(" done (" + getResultString(result) + ")");
+                        mCecResult.set(result);
+                        mLatch.countDown();
+                    }
+                };
     }
 
     @Override
@@ -70,6 +84,8 @@
         pw.println("                --args <vendor specific arguments>");
         pw.println("                [--id <true if vendor command should be sent with vendor id>]");
         pw.println("      Send a Vendor Command to the given target device");
+        pw.println("  setsystemaudiomode, setsam [on|off]");
+        pw.println("      Sets the System Audio Mode feature on or off on TV devices");
     }
 
     private int handleShellCommand(String cmd) throws RemoteException {
@@ -81,6 +97,9 @@
                 return oneTouchPlay(pw);
             case "vendorcommand":
                 return vendorCommand(pw);
+            case "setsystemaudiomode":
+            case "setsam":
+                return setSystemAudioMode(pw);
         }
 
         getErrPrintWriter().println("Unhandled command: " + cmd);
@@ -88,28 +107,14 @@
     }
 
     private int oneTouchPlay(PrintWriter pw) throws RemoteException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        AtomicInteger cecResult = new AtomicInteger();
         pw.print("Sending One Touch Play...");
-        mBinderService.oneTouchPlay(new IHdmiControlCallback.Stub() {
-            @Override
-            public void onComplete(int result) {
-                pw.println(" done (" + result + ")");
-                latch.countDown();
-                cecResult.set(result);
-            }
-        });
+        mBinderService.oneTouchPlay(mHdmiControlCallback);
 
-        try {
-            if (!latch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                getErrPrintWriter().println("One Touch Play timed out.");
-                return 1;
-            }
-        } catch (InterruptedException e) {
-            getErrPrintWriter().println("Caught InterruptedException");
-            Thread.currentThread().interrupt();
+        if (!receiveCallback("One Touch Play")) {
+            return 1;
         }
-        return cecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+
+        return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
     }
 
     private int vendorCommand(PrintWriter pw) throws RemoteException {
@@ -157,4 +162,62 @@
         mBinderService.sendVendorCommand(deviceType, destination, params, hasVendorId);
         return 0;
     }
+
+    private int setSystemAudioMode(PrintWriter pw) throws RemoteException {
+        if (1 > getRemainingArgsCount()) {
+            throw new IllegalArgumentException(
+                    "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+        }
+
+        String arg = getNextArg();
+        if (arg.equals("on")) {
+            pw.println("Setting System Audio Mode on");
+            mBinderService.setSystemAudioMode(true, mHdmiControlCallback);
+        } else if (arg.equals("off")) {
+            pw.println("Setting System Audio Mode off");
+            mBinderService.setSystemAudioMode(false, mHdmiControlCallback);
+        } else {
+            throw new IllegalArgumentException(
+                    "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+        }
+
+        if (!receiveCallback("Set System Audio Mode")) {
+            return 1;
+        }
+
+        return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+    }
+
+    private boolean receiveCallback(String command) {
+        try {
+            if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                getErrPrintWriter().println(command + " timed out.");
+                return false;
+            }
+        } catch (InterruptedException e) {
+            getErrPrintWriter().println("Caught InterruptedException");
+            Thread.currentThread().interrupt();
+        }
+        return true;
+    }
+
+    private String getResultString(int result) {
+        switch (result) {
+            case HdmiControlManager.RESULT_SUCCESS:
+                return "Success";
+            case HdmiControlManager.RESULT_TIMEOUT:
+                return "Timeout";
+            case HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE:
+                return "Source not available";
+            case HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE:
+                return "Target not available";
+            case HdmiControlManager.RESULT_EXCEPTION:
+                return "Exception";
+            case HdmiControlManager.RESULT_INCORRECT_MODE:
+                return "Incorrect mode";
+            case HdmiControlManager.RESULT_COMMUNICATION_FAILED:
+                return "Communication Failed";
+        }
+        return Integer.toString(result);
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0215188..f96fa09 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -99,6 +99,7 @@
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryCertPath;
 import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.keystore2.AndroidKeyStoreProvider;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
@@ -262,7 +263,7 @@
 
         @Override
         public void onStart() {
-            android.security.keystore2.AndroidKeyStoreProvider.install();
+            AndroidKeyStoreProvider.install();
             mLockSettingsService = new LockSettingsService(getContext());
             publishBinderService("lock_settings", mLockSettingsService);
         }
@@ -796,10 +797,6 @@
                 // Notify keystore that a new user was added.
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 AndroidKeyStoreMaintenance.onUserAdded(userHandle);
-                final KeyStore ks = KeyStore.getInstance();
-                final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
-                final int parentHandle = parentInfo != null ? parentInfo.id : -1;
-                ks.onUserAdded(userHandle, parentHandle);
             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mStorage.prefetchUser(userHandle);
@@ -1264,19 +1261,11 @@
 
     private void setKeystorePassword(byte[] password, int userHandle) {
         AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
-        final KeyStore ks = KeyStore.getInstance();
-        // TODO(b/120484642): Update keystore to accept byte[] passwords
-        String passwordString = password == null ? null : new String(password);
-        ks.onUserPasswordChanged(userHandle, passwordString);
     }
 
     private void unlockKeystore(byte[] password, int userHandle) {
         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
         Authorization.onLockScreenEvent(false, userHandle, password);
-        // TODO(b/120484642): Update keystore to accept byte[] passwords
-        String passwordString = password == null ? null : new String(password);
-        final KeyStore ks = KeyStore.getInstance();
-        ks.unlock(userHandle, passwordString);
     }
 
     @VisibleForTesting /** Note: this method is overridden in unit tests */
@@ -2296,8 +2285,6 @@
         mStrongAuth.removeUser(userId);
 
         AndroidKeyStoreMaintenance.onUserRemoved(userId);
-        final KeyStore ks = KeyStore.getInstance();
-        ks.onUserRemoved(userId);
         mManagedProfilePasswordCache.removePassword(userId);
 
         gateKeeperClearSecureUserId(userId);
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index 7950fcf..fa477c8 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -20,10 +20,10 @@
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreSpi;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.UserNotAuthenticatedException;
+import android.security.keystore2.AndroidKeyStoreSpi;
 import android.util.Slog;
 import android.util.SparseArray;
 
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
index bae029c..da29368 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
@@ -16,11 +16,10 @@
 
 package com.android.server.locksettings;
 
-import android.security.keystore.AndroidKeyStoreSpi;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
-import android.security.keystore2.AndroidKeyStoreProvider;
+import android.security.keystore2.AndroidKeyStoreSpi;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -67,9 +66,7 @@
             KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
             KeyStore.LoadStoreParameter loadStoreParameter = null;
             // Load from the specific namespace if keystore2 is enabled.
-            if (AndroidKeyStoreProvider.isInstalled()) {
-                loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
-            }
+            loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
             keyStore.load(loadStoreParameter);
             return (SecretKey) keyStore.getKey(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME,
                     null);
@@ -91,9 +88,7 @@
                 KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
                 KeyStore.LoadStoreParameter loadStoreParameter = null;
                 // Load from the specific namespace if keystore2 is enabled.
-                if (AndroidKeyStoreProvider.isInstalled()) {
-                    loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
-                }
+                loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
                 keyStore.load(loadStoreParameter);
                 keyStore.deleteEntry(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME);
             } catch (IOException | GeneralSecurityException e) {
@@ -119,9 +114,7 @@
                         .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                         .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
                 // Generate the key with the correct namespace if keystore2 is enabled.
-                if (AndroidKeyStoreProvider.isInstalled()) {
-                    parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
-                }
+                parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
                 generator.init(parameterSpecBuilder.build());
                 return generator.generateKey();
             } catch (GeneralSecurityException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 2398f56..8582c67 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -20,8 +20,6 @@
 
 import android.annotation.Nullable;
 import android.os.ServiceSpecificException;
-import android.security.Credentials;
-import android.security.KeyStore;
 import android.security.KeyStore2;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
@@ -75,13 +73,7 @@
     public @Nullable String getGrantAlias(int userId, int uid, String alias) {
         Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
         String keystoreAlias = getInternalAlias(userId, uid, alias);
-        if (useKeyStore2()) {
-            return makeKeystoreEngineGrantString(uid, keystoreAlias);
-        } else {
-            // Aliases used by {@link KeyStore} are different than used by public API.
-            // {@code USER_PRIVATE_KEY} prefix is used secret keys.
-            return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid);
-        }
+        return makeKeystoreEngineGrantString(uid, keystoreAlias);
     }
 
     public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
@@ -148,9 +140,4 @@
         }
         return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace);
     }
-
-    private static boolean useKeyStore2() {
-        return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
-    }
-
 }
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index cc3a002..df1eb6d 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -22,7 +22,6 @@
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
 import android.net.ProxyInfo;
-import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
 import android.util.ArrayMap;
@@ -42,6 +41,8 @@
 import java.io.InputStream;
 import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
 
 public class IpConfigStore {
     private static final String TAG = "IpConfigStore";
@@ -83,25 +84,25 @@
         boolean written = false;
 
         try {
-            switch (config.ipAssignment) {
+            switch (config.getIpAssignment()) {
                 case STATIC:
                     out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.ipAssignment.toString());
-                    StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+                    out.writeUTF(config.getIpAssignment().toString());
+                    StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
                     if (staticIpConfiguration != null) {
-                        if (staticIpConfiguration.ipAddress != null) {
-                            LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+                        if (staticIpConfiguration.getIpAddress() != null) {
+                            LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
                             out.writeUTF(LINK_ADDRESS_KEY);
                             out.writeUTF(ipAddress.getAddress().getHostAddress());
                             out.writeInt(ipAddress.getPrefixLength());
                         }
-                        if (staticIpConfiguration.gateway != null) {
+                        if (staticIpConfiguration.getGateway() != null) {
                             out.writeUTF(GATEWAY_KEY);
                             out.writeInt(0);  // Default route.
                             out.writeInt(1);  // Have a gateway.
-                            out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
+                            out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
                         }
-                        for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+                        for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
                             out.writeUTF(DNS_KEY);
                             out.writeUTF(inetAddr.getHostAddress());
                         }
@@ -110,7 +111,7 @@
                     break;
                 case DHCP:
                     out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.ipAssignment.toString());
+                    out.writeUTF(config.getIpAssignment().toString());
                     written = true;
                     break;
                 case UNASSIGNED:
@@ -121,13 +122,13 @@
                     break;
             }
 
-            switch (config.proxySettings) {
+            switch (config.getProxySettings()) {
                 case STATIC:
-                    ProxyInfo proxyProperties = config.httpProxy;
+                    ProxyInfo proxyProperties = config.getHttpProxy();
                     String exclusionList = ProxyUtils.exclusionListAsString(
                             proxyProperties.getExclusionList());
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     out.writeUTF(PROXY_HOST_KEY);
                     out.writeUTF(proxyProperties.getHost());
                     out.writeUTF(PROXY_PORT_KEY);
@@ -139,16 +140,16 @@
                     written = true;
                     break;
                 case PAC:
-                    ProxyInfo proxyPacProperties = config.httpProxy;
+                    ProxyInfo proxyPacProperties = config.getHttpProxy();
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     out.writeUTF(PROXY_PAC_FILE);
                     out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
                     written = true;
                     break;
                 case NONE:
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     written = true;
                     break;
                 case UNASSIGNED:
@@ -267,11 +268,14 @@
                 IpAssignment ipAssignment = IpAssignment.DHCP;
                 ProxySettings proxySettings = ProxySettings.NONE;
                 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+                LinkAddress linkAddress = null;
+                InetAddress gatewayAddress = null;
                 String proxyHost = null;
                 String pacFileUrl = null;
                 int proxyPort = -1;
                 String exclusionList = null;
                 String key;
+                final List<InetAddress> dnsServers = new ArrayList<>();
 
                 do {
                     key = in.readUTF();
@@ -286,15 +290,15 @@
                         } else if (key.equals(IP_ASSIGNMENT_KEY)) {
                             ipAssignment = IpAssignment.valueOf(in.readUTF());
                         } else if (key.equals(LINK_ADDRESS_KEY)) {
-                            LinkAddress linkAddr =
+                            LinkAddress parsedLinkAddress =
                                     new LinkAddress(
                                             InetAddresses.parseNumericAddress(in.readUTF()),
                                             in.readInt());
-                            if (linkAddr.getAddress() instanceof Inet4Address &&
-                                    staticIpConfiguration.ipAddress == null) {
-                                staticIpConfiguration.ipAddress = linkAddr;
+                            if (parsedLinkAddress.getAddress() instanceof Inet4Address
+                                    && linkAddress == null) {
+                                linkAddress = parsedLinkAddress;
                             } else {
-                                loge("Non-IPv4 or duplicate address: " + linkAddr);
+                                loge("Non-IPv4 or duplicate address: " + parsedLinkAddress);
                             }
                         } else if (key.equals(GATEWAY_KEY)) {
                             LinkAddress dest = null;
@@ -302,8 +306,8 @@
                             if (version == 1) {
                                 // only supported default gateways - leave the dest/prefix empty
                                 gateway = InetAddresses.parseNumericAddress(in.readUTF());
-                                if (staticIpConfiguration.gateway == null) {
-                                    staticIpConfiguration.gateway = gateway;
+                                if (gatewayAddress == null) {
+                                    gatewayAddress = gateway;
                                 } else {
                                     loge("Duplicate gateway: " + gateway.getHostAddress());
                                 }
@@ -317,17 +321,18 @@
                                 if (in.readInt() == 1) {
                                     gateway = InetAddresses.parseNumericAddress(in.readUTF());
                                 }
-                                RouteInfo route = new RouteInfo(dest, gateway);
-                                if (route.isIPv4Default() &&
-                                        staticIpConfiguration.gateway == null) {
-                                    staticIpConfiguration.gateway = gateway;
+                                // If the destination is a default IPv4 route, use the gateway
+                                // address unless already set.
+                                if (dest.getAddress() instanceof Inet4Address
+                                        && dest.getPrefixLength() == 0 && gatewayAddress == null) {
+                                    gatewayAddress = gateway;
                                 } else {
-                                    loge("Non-IPv4 default or duplicate route: " + route);
+                                    loge("Non-IPv4 default or duplicate route: "
+                                            + dest.getAddress());
                                 }
                             }
                         } else if (key.equals(DNS_KEY)) {
-                            staticIpConfiguration.dnsServers.add(
-                                    InetAddresses.parseNumericAddress(in.readUTF()));
+                            dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF()));
                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
                             proxySettings = ProxySettings.valueOf(in.readUTF());
                         } else if (key.equals(PROXY_HOST_KEY)) {
@@ -348,25 +353,31 @@
                     }
                 } while (true);
 
+                staticIpConfiguration = new StaticIpConfiguration.Builder()
+                    .setIpAddress(linkAddress)
+                    .setGateway(gatewayAddress)
+                    .setDnsServers(dnsServers)
+                    .build();
+
                 if (uniqueToken != null) {
                     IpConfiguration config = new IpConfiguration();
                     networks.put(uniqueToken, config);
 
                     switch (ipAssignment) {
                         case STATIC:
-                            config.staticIpConfiguration = staticIpConfiguration;
-                            config.ipAssignment = ipAssignment;
+                            config.setStaticIpConfiguration(staticIpConfiguration);
+                            config.setIpAssignment(ipAssignment);
                             break;
                         case DHCP:
-                            config.ipAssignment = ipAssignment;
+                            config.setIpAssignment(ipAssignment);
                             break;
                         case UNASSIGNED:
                             loge("BUG: Found UNASSIGNED IP on file, use DHCP");
-                            config.ipAssignment = IpAssignment.DHCP;
+                            config.setIpAssignment(IpAssignment.DHCP);
                             break;
                         default:
                             loge("Ignore invalid ip assignment while reading.");
-                            config.ipAssignment = IpAssignment.UNASSIGNED;
+                            config.setIpAssignment(IpAssignment.UNASSIGNED);
                             break;
                     }
 
@@ -374,25 +385,25 @@
                         case STATIC:
                             ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
                                     ProxyUtils.exclusionStringAsList(exclusionList));
-                            config.proxySettings = proxySettings;
-                            config.httpProxy = proxyInfo;
+                            config.setProxySettings(proxySettings);
+                            config.setHttpProxy(proxyInfo);
                             break;
                         case PAC:
                             ProxyInfo proxyPacProperties =
                                     ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
-                            config.proxySettings = proxySettings;
-                            config.httpProxy = proxyPacProperties;
+                            config.setProxySettings(proxySettings);
+                            config.setHttpProxy(proxyPacProperties);
                             break;
                         case NONE:
-                            config.proxySettings = proxySettings;
+                            config.setProxySettings(proxySettings);
                             break;
                         case UNASSIGNED:
                             loge("BUG: Found UNASSIGNED proxy on file, use NONE");
-                            config.proxySettings = ProxySettings.NONE;
+                            config.setProxySettings(ProxySettings.NONE);
                             break;
                         default:
                             loge("Ignore invalid proxy settings while reading");
-                            config.proxySettings = ProxySettings.UNASSIGNED;
+                            config.setProxySettings(ProxySettings.UNASSIGNED);
                             break;
                     }
                 } else {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 39ed7e8..2e4d41c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -96,9 +96,10 @@
 
     /**
      *  Notifies that the specified {@link NetworkStatsProvider} has reached its quota
-     *  which was set through {@link NetworkStatsProvider#onSetLimit(String, long)}.
+     *  which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
+     *  {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
      *
      * @param tag the human readable identifier of the custom network stats provider.
      */
-    public abstract void onStatsProviderLimitReached(@NonNull String tag);
+    public abstract void onStatsProviderWarningOrLimitReached(@NonNull String tag);
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f16496c..319800d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -40,6 +40,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
 import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
 import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
 import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
 import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
@@ -74,7 +75,6 @@
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_MASK;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
@@ -423,15 +423,15 @@
     private static final int MSG_LIMIT_REACHED = 5;
     private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
     private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
-    private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
-    private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
+    private static final int MSG_UPDATE_INTERFACE_QUOTAS = 10;
+    private static final int MSG_REMOVE_INTERFACE_QUOTAS = 11;
     private static final int MSG_POLICIES_CHANGED = 13;
     private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
     private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
     private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17;
     private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
     private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
-    private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20;
+    private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20;
     // TODO: Add similar docs for other messages.
     /**
      * Message to indicate that reasons for why an uid is blocked changed.
@@ -2035,39 +2035,45 @@
 
             final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
             final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
-            if (hasLimit || policy.metered) {
-                final long quotaBytes;
-                if (hasLimit && policy.hasCycle()) {
-                    final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
-                            .cycleIterator(policy).next();
-                    final long start = cycle.first.toInstant().toEpochMilli();
-                    final long end = cycle.second.toInstant().toEpochMilli();
-                    final long totalBytes = getTotalBytes(policy.template, start, end);
+            long limitBytes = Long.MAX_VALUE;
+            long warningBytes = Long.MAX_VALUE;
+            if ((hasLimit || hasWarning) && policy.hasCycle()) {
+                final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+                        .cycleIterator(policy).next();
+                final long start = cycle.first.toInstant().toEpochMilli();
+                final long end = cycle.second.toInstant().toEpochMilli();
+                final long totalBytes = getTotalBytes(policy.template, start, end);
 
-                    if (policy.lastLimitSnooze >= start) {
-                        // snoozing past quota, but we still need to restrict apps,
-                        // so push really high quota.
-                        quotaBytes = Long.MAX_VALUE;
-                    } else {
-                        // remaining "quota" bytes are based on total usage in
-                        // current cycle. kernel doesn't like 0-byte rules, so we
-                        // set 1-byte quota and disable the radio later.
-                        quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
-                    }
-                } else {
-                    // metered network, but no policy limit; we still need to
-                    // restrict apps, so push really high quota.
-                    quotaBytes = Long.MAX_VALUE;
+                // If the limit notification is not snoozed, the limit quota needs to be calculated.
+                if (hasLimit && policy.lastLimitSnooze < start) {
+                    // remaining "quota" bytes are based on total usage in
+                    // current cycle. kernel doesn't like 0-byte rules, so we
+                    // set 1-byte quota and disable the radio later.
+                    limitBytes = Math.max(1, policy.limitBytes - totalBytes);
                 }
 
+                // If the warning notification was snoozed by user, or the service already knows
+                // it is over warning bytes, doesn't need to calculate warning bytes.
+                if (hasWarning && policy.lastWarningSnooze < start
+                        && !policy.isOverWarning(totalBytes)) {
+                    warningBytes = Math.max(1, policy.warningBytes - totalBytes);
+                }
+            }
+
+            if (hasWarning || hasLimit || policy.metered) {
                 if (matchingIfaces.size() > 1) {
                     // TODO: switch to shared quota once NMS supports
                     Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
                 }
 
+                // Set the interface warning and limit. For interfaces which has no cycle,
+                // or metered with no policy quotas, or snoozed notification; we still need to put
+                // iptables rule hooks to restrict apps for data saver, so push really high quota.
+                // TODO: Push NetworkStatsProvider.QUOTA_UNLIMITED instead of Long.MAX_VALUE to
+                //  providers.
                 for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
                     final String iface = matchingIfaces.valueAt(j);
-                    setInterfaceQuotaAsync(iface, quotaBytes);
+                    setInterfaceQuotasAsync(iface, warningBytes, limitBytes);
                     newMeteredIfaces.add(iface);
                 }
             }
@@ -2090,7 +2096,7 @@
                 for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
                     final String iface = matchingIfaces.valueAt(j);
                     if (!newMeteredIfaces.contains(iface)) {
-                        setInterfaceQuotaAsync(iface, Long.MAX_VALUE);
+                        setInterfaceQuotasAsync(iface, Long.MAX_VALUE, Long.MAX_VALUE);
                         newMeteredIfaces.add(iface);
                     }
                 }
@@ -2102,7 +2108,7 @@
             for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
                 final String iface = mMeteredIfaces.valueAt(i);
                 if (!newMeteredIfaces.contains(iface)) {
-                    removeInterfaceQuotaAsync(iface);
+                    removeInterfaceQuotasAsync(iface);
                 }
             }
             mMeteredIfaces = newMeteredIfaces;
@@ -4972,7 +4978,7 @@
                     mListeners.finishBroadcast();
                     return true;
                 }
-                case MSG_STATS_PROVIDER_LIMIT_REACHED: {
+                case MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED: {
                     mNetworkStats.forceUpdate();
 
                     synchronized (mNetworkPoliciesSecondLock) {
@@ -5043,19 +5049,20 @@
                     mNetworkStats.advisePersistThreshold(persistThreshold);
                     return true;
                 }
-                case MSG_UPDATE_INTERFACE_QUOTA: {
-                    final String iface = (String) msg.obj;
-                    // int params need to be stitched back into a long
-                    final long quota = ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL);
-                    removeInterfaceQuota(iface);
-                    setInterfaceQuota(iface, quota);
-                    mNetworkStats.setStatsProviderLimitAsync(iface, quota);
+                case MSG_UPDATE_INTERFACE_QUOTAS: {
+                    final IfaceQuotas val = (IfaceQuotas) msg.obj;
+                    // TODO: Consider set a new limit before removing the original one.
+                    removeInterfaceLimit(val.iface);
+                    setInterfaceLimit(val.iface, val.limit);
+                    mNetworkStats.setStatsProviderWarningAndLimitAsync(val.iface, val.warning,
+                            val.limit);
                     return true;
                 }
-                case MSG_REMOVE_INTERFACE_QUOTA: {
+                case MSG_REMOVE_INTERFACE_QUOTAS: {
                     final String iface = (String) msg.obj;
-                    removeInterfaceQuota(iface);
-                    mNetworkStats.setStatsProviderLimitAsync(iface, QUOTA_UNLIMITED);
+                    removeInterfaceLimit(iface);
+                    mNetworkStats.setStatsProviderWarningAndLimitAsync(iface, QUOTA_UNLIMITED,
+                            QUOTA_UNLIMITED);
                     return true;
                 }
                 case MSG_RESET_FIREWALL_RULES_BY_UID: {
@@ -5203,15 +5210,32 @@
         }
     }
 
-    private void setInterfaceQuotaAsync(String iface, long quotaBytes) {
-        // long quotaBytes split up into two ints to fit in message
-        mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, (int) (quotaBytes >> 32),
-                (int) (quotaBytes & 0xFFFFFFFF), iface).sendToTarget();
+    private static final class IfaceQuotas {
+        @NonNull public final String iface;
+        // Warning and limit bytes of interface qutoas, could be QUOTA_UNLIMITED or Long.MAX_VALUE
+        // if not set. 0 is not acceptable since kernel doesn't like 0-byte rules.
+        public final long warning;
+        public final long limit;
+
+        private IfaceQuotas(@NonNull String iface, long warning, long limit) {
+            this.iface = iface;
+            this.warning = warning;
+            this.limit = limit;
+        }
     }
 
-    private void setInterfaceQuota(String iface, long quotaBytes) {
+    private void setInterfaceQuotasAsync(@NonNull String iface,
+            long warningBytes, long limitBytes) {
+        mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTAS,
+                new IfaceQuotas(iface, warningBytes, limitBytes)).sendToTarget();
+    }
+
+    private void setInterfaceLimit(String iface, long limitBytes) {
         try {
-            mNetworkManager.setInterfaceQuota(iface, quotaBytes);
+            // For legacy design the data warning is covered by global alert, where the
+            // kernel will notify upper layer for a small amount of change of traffic
+            // statistics. Thus, passing warning is not needed.
+            mNetworkManager.setInterfaceQuota(iface, limitBytes);
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem setting interface quota", e);
         } catch (RemoteException e) {
@@ -5219,11 +5243,11 @@
         }
     }
 
-    private void removeInterfaceQuotaAsync(String iface) {
-        mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface).sendToTarget();
+    private void removeInterfaceQuotasAsync(String iface) {
+        mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTAS, iface).sendToTarget();
     }
 
-    private void removeInterfaceQuota(String iface) {
+    private void removeInterfaceLimit(String iface) {
         try {
             mNetworkManager.removeInterfaceQuota(iface);
         } catch (IllegalStateException e) {
@@ -5557,17 +5581,6 @@
     }
 
     @Override
-    public boolean checkUidNetworkingBlocked(int uid, int uidRules,
-            boolean isNetworkMetered, boolean isBackgroundRestricted) {
-        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
-        // Log of invoking this function is disabled because it will be called very frequently. And
-        // metrics are unlikely needed on this method because the callers are external and this
-        // method doesn't take any locks or perform expensive operations.
-        return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
-                isBackgroundRestricted, null);
-    }
-
-    @Override
     public boolean isUidRestrictedOnMeteredNetworks(int uid) {
         mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         final int uidRules;
@@ -5728,9 +5741,9 @@
         }
 
         @Override
-        public void onStatsProviderLimitReached(@NonNull String tag) {
-            Log.v(TAG, "onStatsProviderLimitReached: " + tag);
-            mHandler.obtainMessage(MSG_STATS_PROVIDER_LIMIT_REACHED).sendToTarget();
+        public void onStatsProviderWarningOrLimitReached(@NonNull String tag) {
+            Log.v(TAG, "onStatsProviderWarningOrLimitReached: " + tag);
+            mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget();
         }
     }
 
@@ -5844,7 +5857,8 @@
         return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
     }
 
-    private class UidBlockedState {
+    @VisibleForTesting
+    static final class UidBlockedState {
         public int blockedReasons;
         public int allowedReasons;
         public int effectiveBlockedReasons;
@@ -5856,16 +5870,21 @@
         }
 
         void updateEffectiveBlockedReasons() {
-            effectiveBlockedReasons = blockedReasons;
+            effectiveBlockedReasons = getEffectiveBlockedReasons(blockedReasons, allowedReasons);
+        }
+
+        @VisibleForTesting
+        static int getEffectiveBlockedReasons(int blockedReasons, int allowedReasons) {
+            int effectiveBlockedReasons = blockedReasons;
             // If the uid is not subject to any blocked reasons, then return early
             if (blockedReasons == BLOCKED_REASON_NONE) {
-                return;
+                return effectiveBlockedReasons;
             }
             if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) {
-                effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK);
+                effectiveBlockedReasons &= ALLOWED_METERED_REASON_MASK;
             }
             if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) {
-                effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK);
+                effectiveBlockedReasons &= ~ALLOWED_METERED_REASON_MASK;
             }
             if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) {
                 effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
@@ -5891,6 +5910,7 @@
             if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
                 effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
             }
+            return effectiveBlockedReasons;
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
index 0cb0bc2c..0e9a9da 100644
--- a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
@@ -37,8 +37,9 @@
     public abstract void forceUpdate();
 
     /**
-     * Set the quota limit to all registered custom network stats providers.
+     * Set the warning and limit to all registered custom network stats providers.
      * Note that invocation of any interface will be sent to all providers.
      */
-    public abstract void setStatsProviderLimitAsync(@NonNull String iface, long quota);
+    public abstract void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
+            long limit);
 }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index fe43c31..19f5e3c 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,6 +24,7 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
 import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -65,6 +66,7 @@
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -100,7 +102,9 @@
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
+import android.net.NetworkSpecifier;
 import android.net.NetworkTemplate;
+import android.net.TelephonyNetworkSpecifier;
 import android.net.TrafficStats;
 import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
@@ -1320,8 +1324,9 @@
                             ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
                             ident.getRoaming(), true /* metered */,
                             true /* onDefaultNetwork */, ident.getOemManaged());
-                    findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
-                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
+                    final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot);
+                    findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent);
+                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent);
                 }
 
                 if (isMobile) {
@@ -1377,6 +1382,20 @@
         mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
     }
 
+    private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
+        if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+            throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR");
+        }
+
+        final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+        if (spec instanceof TelephonyNetworkSpecifier) {
+             return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
+        } else {
+            Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+            return INVALID_SUBSCRIPTION_ID;
+        }
+    }
+
     /**
      * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through
      * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
@@ -1674,9 +1693,14 @@
         }
 
         @Override
-        public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
-            if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
-            invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
+        public void setStatsProviderWarningAndLimitAsync(
+                @NonNull String iface, long warning, long limit) {
+            if (LOGV) {
+                Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+                        + iface + "," + warning + "," + limit + ")");
+            }
+            invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
+                    warning, limit));
         }
     }
 
@@ -2071,10 +2095,10 @@
         }
 
         @Override
-        public void notifyLimitReached() {
-            Log.d(TAG, mTag + ": onLimitReached");
+        public void notifyWarningOrLimitReached() {
+            Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
             LocalServices.getService(NetworkPolicyManagerInternal.class)
-                    .onStatsProviderLimitReached(mTag);
+                    .onStatsProviderWarningOrLimitReached(mTag);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index cc6a824..ed1f5f5 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -392,7 +392,7 @@
 
             int pid = 0;
             int uid = 0;
-            String processName = "";
+            String processName = null;
             String crashReason = "";
             String selinuxLabel = "";
 
@@ -407,8 +407,10 @@
                             uid = stream.readInt(Tombstone.UID);
                             break;
 
-                        case (int) Tombstone.PROCESS_NAME:
-                            processName = stream.readString(Tombstone.PROCESS_NAME);
+                        case (int) Tombstone.COMMAND_LINE:
+                            if (processName == null) {
+                                processName = stream.readString(Tombstone.COMMAND_LINE);
+                            }
                             break;
 
                         case (int) Tombstone.CAUSES:
@@ -472,7 +474,7 @@
             result.mAppId = appId;
             result.mPid = pid;
             result.mUid = uid;
-            result.mProcessName = processName;
+            result.mProcessName = processName == null ? "" : processName;
             result.mTimestampMs = timestampMs;
             result.mCrashReason = crashReason;
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 6ad43ce..ca9c75f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -258,23 +258,23 @@
                         packageStats, options.isDowngrade(), profileName, dexMetadataPath,
                         options.getCompilationReason());
 
-                // Only report metrics for base apk for now.
-                // TODO: add ISA and APK type to metrics.
                 // OTAPreopt doesn't have stats so don't report in that case.
-                if (pkg.getBaseCodePath().equals(path) && packageStats != null) {
+                if (packageStats != null) {
                     Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
                     try {
                         long sessionId = Math.randomLongInternal();
                         ArtStatsLogUtils.writeStatsLog(
                                 mArtStatsLogger,
                                 sessionId,
-                                path,
                                 compilerFilter,
-                                sharedGid,
+                                pkg.getUid(),
                                 packageStats.getCompileTime(path),
                                 dexMetadataPath,
                                 options.getCompilationReason(),
-                                newResult);
+                                newResult,
+                                ArtStatsLogUtils.getApkType(path),
+                                dexCodeIsa,
+                                path);
                     } finally {
                         Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
                     }
@@ -489,9 +489,9 @@
         String classLoaderContext = null;
         if (dexUseInfo.isUnsupportedClassLoaderContext()
                 || dexUseInfo.isVariableClassLoaderContext()) {
-            // If we have an unknown (not yet set), or a variable class loader chain. Just extract
+            // If we have an unknown (not yet set), or a variable class loader chain. Just verify
             // the dex file.
-            compilerFilter = "extract";
+            compilerFilter = "verify";
         } else {
             classLoaderContext = dexUseInfo.getClassLoaderContext();
         }
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index c8dc1b1..d67796b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -32,6 +32,8 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
 
 /** Utils class to report ART metrics to statsd. */
@@ -39,6 +41,7 @@
     private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
     private static final String PROFILE_DEX_METADATA = "primary.prof";
     private static final String VDEX_DEX_METADATA = "primary.vdex";
+    private static final String BASE_APK= "base.apk";
 
 
     private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
@@ -122,16 +125,29 @@
                 ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
     }
 
+    private static final Map<String, Integer> ISA_MAP = new HashMap();
+
+    static {
+        ISA_MAP.put("arm", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
+        ISA_MAP.put("arm64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
+        ISA_MAP.put("x86", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86);
+        ISA_MAP.put("x86_64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
+        ISA_MAP.put("mips", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
+        ISA_MAP.put("mips64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
+    }
+
     public static void writeStatsLog(
             ArtStatsLogger logger,
             long sessionId,
-            String path,
             String compilerFilter,
             int uid,
             long compileTime,
             String dexMetadataPath,
             int compilationReason,
-            int result) {
+            int result,
+            int apkType,
+            String isa,
+            String apkPath) {
         int dexMetadataType = getDexMetadataType(dexMetadataPath);
         logger.write(
                 sessionId,
@@ -140,7 +156,19 @@
                 compilerFilter,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
                 result,
-                dexMetadataType);
+                dexMetadataType,
+                apkType,
+                isa);
+        logger.write(
+                sessionId,
+                uid,
+                compilationReason,
+                compilerFilter,
+                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+                getDexBytes(apkPath),
+                dexMetadataType,
+                apkType,
+                isa);
         logger.write(
                 sessionId,
                 uid,
@@ -148,7 +176,47 @@
                 compilerFilter,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
                 compileTime,
-                dexMetadataType);
+                dexMetadataType,
+                apkType,
+                isa);
+    }
+
+    public static int getApkType(String path) {
+        if (path.equals(BASE_APK)) {
+            return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE;
+        }
+        return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT;
+    }
+
+    private static long getDexBytes(String apkPath) {
+        StrictJarFile jarFile = null;
+        long dexBytes = 0;
+        try {
+            jarFile = new StrictJarFile(apkPath,
+                    /*verify=*/ false,
+                    /*signatureSchemeRollbackProtectionsEnforced=*/ false);
+            Iterator<ZipEntry> it = jarFile.iterator();
+            Pattern p = Pattern.compile("classes(\\d)*[.]dex");
+            Matcher m = p.matcher("");
+            while (it.hasNext()) {
+                ZipEntry entry = it.next();
+                m.reset(entry.getName());
+                if (m.matches()) {
+                    dexBytes += entry.getSize();
+                }
+            }
+            return dexBytes;
+        } catch (IOException ignore) {
+            Slog.e(TAG, "Error when parsing APK " + apkPath);
+            return -1L;
+        } finally {
+            try {
+                if (jarFile != null) {
+                    jarFile.close();
+                }
+            } catch (IOException ignore) {
+            }
+        }
     }
 
     private static int getDexMetadataType(String dexMetadataPath) {
@@ -207,7 +275,9 @@
                 String compilerFilter,
                 int kind,
                 long value,
-                int dexMetadataType) {
+                int dexMetadataType,
+                int apkType,
+                String isa) {
             ArtStatsLog.write(
                     ArtStatsLog.ART_DATUM_REPORTED,
                     sessionId,
@@ -220,7 +290,10 @@
                     ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
                     kind,
                     value,
-                    dexMetadataType);
+                    dexMetadataType,
+                    apkType,
+                    ISA_MAP.getOrDefault(isa,
+                            ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
         }
     }
 }
diff --git a/services/core/java/com/android/server/speech/OWNERS b/services/core/java/com/android/server/speech/OWNERS
new file mode 100644
index 0000000..b187b87
--- /dev/null
+++ b/services/core/java/com/android/server/speech/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/speech/OWNERS
diff --git a/services/core/java/com/android/server/stats/StatsHelper.java b/services/core/java/com/android/server/stats/StatsHelper.java
new file mode 100644
index 0000000..9b9f6b50
--- /dev/null
+++ b/services/core/java/com/android/server/stats/StatsHelper.java
@@ -0,0 +1,45 @@
+/*
+ * 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.stats;
+
+import static android.app.StatsManager.ACTION_STATSD_STARTED;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+/**
+ * Provides helper methods for the Statsd APEX
+ *
+ * @hide
+ **/
+@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public final class StatsHelper {
+    private StatsHelper() {}
+
+    /**
+     * Send statsd ready broadcast
+     *
+     **/
+    public static void sendStatsdReadyBroadcast(@NonNull final Context context) {
+        context.sendBroadcastAsUser(
+                new Intent(ACTION_STATSD_STARTED).addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
+                UserHandle.SYSTEM, android.Manifest.permission.DUMP);
+    }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index afcf81f..ff763fc 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -54,7 +54,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Authorization;
-import android.security.KeyStore;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -701,13 +700,11 @@
             dispatchDeviceLocked(userId, locked);
 
             Authorization.onLockScreenEvent(locked, userId, null);
-            KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
             // Also update the user's profiles who have unified challenge, since they
             // share the same unlocked state (see {@link #isDeviceLocked(int)})
             for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
                 if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
                     mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
-                    KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
                 }
             }
         }
@@ -1259,7 +1256,6 @@
                     }
 
                     Authorization.onLockScreenEvent(locked, userId, null);
-                    KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
 
                     if (locked) {
                         try {
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 8dcc547..ab9de77 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -27,15 +27,14 @@
 import android.net.TelephonyNetworkSpecifier;
 import android.os.Handler;
 import android.os.ParcelUuid;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -59,9 +58,9 @@
     @NonNull private final Handler mHandler;
     @NonNull private final ConnectivityManager mConnectivityManager;
 
-    @NonNull private final Map<Integer, NetworkCallback> mCellBringupCallbacks = new ArrayMap<>();
-    @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback();
-    @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
+    @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>();
+    @Nullable private NetworkCallback mWifiBringupCallback;
+    @Nullable private NetworkCallback mRouteSelectionCallback;
 
     @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
     private boolean mIsQuitting = false;
@@ -105,36 +104,95 @@
 
         mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
 
-        registerNetworkRequests();
+        registerOrUpdateNetworkRequests();
     }
 
-    private void registerNetworkRequests() {
-        // register bringup requests for underlying Networks
-        mConnectivityManager.requestBackgroundNetwork(
-                getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
-        updateSubIdsAndCellularRequests();
+    private void registerOrUpdateNetworkRequests() {
+        NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
+        NetworkCallback oldWifiCallback = mWifiBringupCallback;
+        List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
+        mCellBringupCallbacks.clear();
 
-        // Register Network-selection request used to decide selected underlying Network. All
-        // underlying networks must be VCN managed in order to be used.
-        mConnectivityManager.requestBackgroundNetwork(
-                getBaseNetworkRequest(true /* requireVcnManaged */).build(),
-                mHandler,
-                mRouteSelectionCallback);
+        // Register new callbacks. Make-before-break; always register new callbacks before removal
+        // of old callbacks
+        if (!mIsQuitting) {
+            mRouteSelectionCallback = new RouteSelectionCallback();
+            mConnectivityManager.requestBackgroundNetwork(
+                    getRouteSelectionRequest(), mHandler, mRouteSelectionCallback);
+
+            mWifiBringupCallback = new NetworkBringupCallback();
+            mConnectivityManager.requestBackgroundNetwork(
+                    getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
+
+            for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
+                final NetworkBringupCallback cb = new NetworkBringupCallback();
+                mCellBringupCallbacks.add(cb);
+
+                mConnectivityManager.requestBackgroundNetwork(
+                        getCellNetworkRequestForSubId(subId), mHandler, cb);
+            }
+        } else {
+            mRouteSelectionCallback = null;
+            mWifiBringupCallback = null;
+            // mCellBringupCallbacks already cleared above.
+        }
+
+        // Unregister old callbacks (as necessary)
+        if (oldRouteSelectionCallback != null) {
+            mConnectivityManager.unregisterNetworkCallback(oldRouteSelectionCallback);
+        }
+        if (oldWifiCallback != null) {
+            mConnectivityManager.unregisterNetworkCallback(oldWifiCallback);
+        }
+        for (NetworkCallback cellBringupCallback : oldCellCallbacks) {
+            mConnectivityManager.unregisterNetworkCallback(cellBringupCallback);
+        }
     }
 
-    private NetworkRequest getWifiNetworkRequest() {
-        // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi
-        // alive.
-        return getBaseNetworkRequest(true /* requireVcnManaged */)
-                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+    /**
+     * Builds the Route selection request
+     *
+     * <p>This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue
+     * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier
+     * owned networks may be selected, as the request specifies only subIds in the VCN's
+     * subscription group, while the VCN networks are excluded by virtue of not having subIds set on
+     * the VCN-exposed networks.
+     */
+    private NetworkRequest getRouteSelectionRequest() {
+        return getBaseNetworkRequestBuilder()
+                .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
                 .build();
     }
 
+    /**
+     * Builds the WiFi bringup request
+     *
+     * <p>This request is built specifically to match only carrier-owned WiFi networks, but is also
+     * built to ONLY keep Carrier WiFi Networks alive (but never bring them up). This is a result of
+     * the WifiNetworkFactory not advertising a list of subIds, and therefore not accepting this
+     * request. As such, it will bind to a Carrier WiFi Network that has already been brought up,
+     * but will NEVER bring up a Carrier WiFi network itself.
+     */
+    private NetworkRequest getWifiNetworkRequest() {
+        return getBaseNetworkRequestBuilder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+                .build();
+    }
+
+    /**
+     * Builds a Cellular bringup request for a given subId
+     *
+     * <p>This request is filed in order to ensure that the Telephony stack always has a
+     * NetworkRequest to bring up a VCN underlying cellular network. It is required in order to
+     * ensure that even when a VCN (appears as Cellular) satisfies the default request, Telephony
+     * will bring up additional underlying Cellular networks.
+     *
+     * <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
+     * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
+     */
     private NetworkRequest getCellNetworkRequestForSubId(int subId) {
-        // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a
-        // fulfillable request to bring up underlying cellular Networks even if the VCN is already
-        // connected.
-        return getBaseNetworkRequest(false /* requireVcnManaged */)
+        return getBaseNetworkRequestBuilder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
                 .build();
@@ -142,68 +200,13 @@
 
     /**
      * Builds and returns a NetworkRequest builder common to all Underlying Network requests
-     *
-     * <p>A NetworkRequest may either (1) Require the presence of a capability by using
-     * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3)
-     * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED
-     * capability, and only cases (2) and (3) are used.
-     *
-     * @param requireVcnManaged whether the underlying network is required to be VCN managed to
-     *     match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as
-     *     unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is
-     *     acceptable.
      */
-    private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) {
-        NetworkRequest.Builder requestBase =
-                new NetworkRequest.Builder()
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-
-        for (int capability : mRequiredUnderlyingNetworkCapabilities) {
-            requestBase.addCapability(capability);
-        }
-
-        if (requireVcnManaged) {
-            requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-        }
-
-        return requestBase;
-    }
-
-    /**
-     * Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker.
-     */
-    private void updateSubIdsAndCellularRequests() {
-        mVcnContext.ensureRunningOnLooperThread();
-
-        // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
-        if (mIsQuitting) {
-            return;
-        }
-
-        final Set<Integer> subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup);
-
-        // new subIds to track = (updated list of subIds) - (currently tracked subIds)
-        final Set<Integer> subIdsToRegister = new ArraySet<>(subIdsInSubGroup);
-        subIdsToRegister.removeAll(mCellBringupCallbacks.keySet());
-
-        // subIds to stop tracking = (currently tracked subIds) - (updated list of subIds)
-        final Set<Integer> subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet());
-        subIdsToUnregister.removeAll(subIdsInSubGroup);
-
-        for (final int subId : subIdsToRegister) {
-            final NetworkBringupCallback cb = new NetworkBringupCallback();
-            mCellBringupCallbacks.put(subId, cb);
-
-            mConnectivityManager.requestBackgroundNetwork(
-                    getCellNetworkRequestForSubId(subId), mHandler, cb);
-        }
-
-        for (final int subId : subIdsToUnregister) {
-            final NetworkCallback cb = mCellBringupCallbacks.remove(subId);
-            mConnectivityManager.unregisterNetworkCallback(cb);
-        }
+    private NetworkRequest.Builder getBaseNetworkRequestBuilder() {
+        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);
     }
 
     /**
@@ -217,22 +220,16 @@
         Objects.requireNonNull(snapshot, "Missing snapshot");
 
         mLastSnapshot = snapshot;
-        updateSubIdsAndCellularRequests();
+        registerOrUpdateNetworkRequests();
     }
 
     /** Tears down this Tracker, and releases all underlying network requests. */
     public void teardown() {
         mVcnContext.ensureRunningOnLooperThread();
-
-        mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback);
-        mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback);
-
-        for (final NetworkCallback cb : mCellBringupCallbacks.values()) {
-            mConnectivityManager.unregisterNetworkCallback(cb);
-        }
-        mCellBringupCallbacks.clear();
-
         mIsQuitting = true;
+
+        // Will unregister all existing callbacks, but not register new ones due to quitting flag.
+        registerOrUpdateNetworkRequests();
     }
 
     /** Returns whether the currently selected Network matches the given network. */
@@ -290,25 +287,6 @@
         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();
@@ -366,20 +344,11 @@
         @Override
         public void onCapabilitiesChanged(
                 @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+            if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return;
             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);
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 89ed956..ae806aa 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -17,6 +17,10 @@
 package com.android.server.vcn;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
 import static com.android.server.VcnManagementService.VDBG;
 
@@ -44,7 +48,6 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Represents an single instance of a VCN.
@@ -94,17 +97,21 @@
      */
     private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
 
+    /**
+     * Triggers reevaluation of safe mode conditions.
+     *
+     * <p>Upon entering safe mode, the VCN will only provide gateway connections opportunistically,
+     * leaving the underlying networks marked as NOT_VCN_MANAGED.
+     *
+     * <p>Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put
+     * into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to
+     * determine if any are in safe mode.
+     */
+    private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
+
     /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
     private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
 
-    /**
-     * Causes this VCN to immediately enter safe mode.
-     *
-     * <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
-     * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
-     */
-    private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
-
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @NonNull private final Dependencies mDeps;
@@ -137,17 +144,14 @@
     @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
 
     /**
-     * Whether this Vcn instance is active and running.
+     * The current status of this Vcn instance
      *
-     * <p>The value will be {@code true} while running. It will be {@code false} if the VCN has been
-     * shut down or has entered safe mode.
-     *
-     * <p>This AtomicBoolean is required in order to ensure consistency and correctness across
-     * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads
-     * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN
-     * Looper.
+     * <p>The value will be {@link VCN_STATUS_CODE_ACTIVE} while all VcnGatewayConnections are in
+     * good standing, {@link VCN_STATUS_CODE_SAFE_MODE} if any VcnGatewayConnections are in safe
+     * mode, and {@link VCN_STATUS_CODE_INACTIVE} once a teardown has been commanded.
      */
-    private final AtomicBoolean mIsActive = new AtomicBoolean(true);
+    // Accessed from different threads, but always under lock in VcnManagementService
+    private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
 
     public Vcn(
             @NonNull VcnContext vcnContext,
@@ -199,9 +203,15 @@
         sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN));
     }
 
-    /** Synchronously checks whether this Vcn is active. */
-    public boolean isActive() {
-        return mIsActive.get();
+    /** Synchronously retrieves the current status code. */
+    public int getStatus() {
+        return mCurrentStatus;
+    }
+
+    /** Sets the status of this VCN */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public void setStatus(int status) {
+        mCurrentStatus = status;
     }
 
     /** Get current Gateways for testing purposes */
@@ -217,12 +227,6 @@
         return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections));
     }
 
-    /** Set whether this Vcn is active for testing purposes */
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
-    public void setIsActive(boolean isActive) {
-        mIsActive.set(isActive);
-    }
-
     private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
         @Override
         public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -234,6 +238,11 @@
 
     @Override
     public void handleMessage(@NonNull Message msg) {
+        if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE
+                && mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) {
+            return;
+        }
+
         switch (msg.what) {
             case MSG_EVENT_CONFIG_UPDATED:
                 handleConfigUpdated((VcnConfig) msg.obj);
@@ -247,12 +256,12 @@
             case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
                 handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
                 break;
+            case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
+                handleSafeModeStatusChanged();
+                break;
             case MSG_CMD_TEARDOWN:
                 handleTeardown();
                 break;
-            case MSG_CMD_ENTER_SAFE_MODE:
-                handleEnterSafeMode();
-                break;
             default:
                 Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
         }
@@ -264,35 +273,28 @@
 
         mConfig = config;
 
-        if (mIsActive.getAndSet(true)) {
-            // VCN is already active - teardown any GatewayConnections whose configs have been
-            // removed and get all current requests
-            for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
-                    mVcnGatewayConnections.entrySet()) {
-                final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
-                final VcnGatewayConnection gatewayConnection = entry.getValue();
+        // Teardown any GatewayConnections whose configs have been removed and get all current
+        // requests
+        for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+                mVcnGatewayConnections.entrySet()) {
+            final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+            final VcnGatewayConnection gatewayConnection = entry.getValue();
 
-                // GatewayConnectionConfigs must match exactly (otherwise authentication or
-                // connection details may have changed).
-                if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
-                    if (gatewayConnection == null) {
-                        Slog.wtf(
-                                getLogTag(),
-                                "Found gatewayConnectionConfig without GatewayConnection");
-                    } else {
-                        gatewayConnection.teardownAsynchronously();
-                    }
+            // GatewayConnectionConfigs must match exactly (otherwise authentication or
+            // connection details may have changed).
+            if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
+                if (gatewayConnection == null) {
+                    Slog.wtf(
+                            getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
+                } else {
+                    gatewayConnection.teardownAsynchronously();
                 }
             }
-
-            // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
-            // satisfied start a new GatewayConnection)
-            mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
-        } else {
-            // If this VCN was not previously active, it is exiting Safe Mode. Re-register the
-            // request listener to get NetworkRequests again (and all cached requests).
-            mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
         }
+
+        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
+        // satisfied start a new GatewayConnection)
+        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
     }
 
     private void handleTeardown() {
@@ -302,22 +304,30 @@
             gatewayConnection.teardownAsynchronously();
         }
 
-        mIsActive.set(false);
+        mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
     }
 
-    private void handleEnterSafeMode() {
-        handleTeardown();
+    private void handleSafeModeStatusChanged() {
+        boolean hasSafeModeGatewayConnection = false;
 
-        mVcnCallback.onEnteredSafeMode();
+        // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
+        for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+            if (gatewayConnection.isInSafeMode()) {
+                hasSafeModeGatewayConnection = true;
+                break;
+            }
+        }
+
+        final int oldStatus = mCurrentStatus;
+        mCurrentStatus =
+                hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+        if (oldStatus != mCurrentStatus) {
+            mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
+        }
     }
 
     private void handleNetworkRequested(
             @NonNull NetworkRequest request, int score, int providerId) {
-        if (!isActive()) {
-            Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
-            return;
-        }
-
         if (score > getNetworkScore()) {
             if (VDBG) {
                 Slog.v(
@@ -370,25 +380,23 @@
         mVcnGatewayConnections.remove(config);
 
         // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
-        // start a new GatewayConnection), but only if the Vcn is still active
-        if (isActive()) {
-            mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
-        }
+        // start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check
+        // in handleMessage()
+        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
     }
 
     private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
         mLastSnapshot = snapshot;
 
-        if (isActive()) {
-            for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
-                gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
-            }
+        for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+            gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
         }
     }
 
     private boolean isRequestSatisfiedByGatewayConnectionConfig(
             @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+        builder.addTransportType(TRANSPORT_CELLULAR);
         builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         for (int cap : config.getAllExposedCapabilities()) {
             builder.addCapability(cap);
@@ -412,12 +420,12 @@
     /** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
     @VisibleForTesting(visibility = Visibility.PACKAGE)
     public interface VcnGatewayStatusCallback {
-        /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
-        void onEnteredSafeMode();
+        /** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */
+        void onSafeModeStatusChanged();
 
         /** Callback by a VcnGatewayConnection to indicate that an error occurred. */
         void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
@@ -439,18 +447,18 @@
         }
 
         @Override
-        public void onEnteredSafeMode() {
-            sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
+        public void onSafeModeStatusChanged() {
+            sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED));
         }
 
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
             mVcnCallback.onGatewayConnectionError(
-                    networkCapabilities, errorCode, exceptionClass, exceptionMessage);
+                    gatewayConnectionName, errorCode, exceptionClass, exceptionMessage);
         }
     }
 
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9589505..20c08eb 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -32,6 +32,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
@@ -44,6 +45,7 @@
 import android.net.NetworkAgent;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
 import android.net.RouteInfo;
 import android.net.TelephonyNetworkSpecifier;
 import android.net.Uri;
@@ -92,6 +94,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * A single VCN Gateway Connection, providing a single public-facing VCN network.
@@ -504,6 +507,15 @@
     private boolean mIsQuitting = false;
 
     /**
+     * Whether the VcnGatewayConnection is in safe mode.
+     *
+     * <p>Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this
+     * VcnGatewayConnection will continue attempting to connect, and if a successful connection is
+     * made, safe mode will be exited.
+     */
+    private boolean mIsInSafeMode = false;
+
+    /**
      * The token used by the primary/current/active session.
      *
      * <p>This token MUST be updated when a new stateful/async session becomes the
@@ -562,8 +574,7 @@
      * <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
      * otherwise.
      */
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
-    NetworkAgent mNetworkAgent;
+    private NetworkAgent mNetworkAgent;
 
     @Nullable private WakeupMessage mTeardownTimeoutAlarm;
     @Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -628,6 +639,14 @@
         start();
     }
 
+    /** Queries whether this VcnGatewayConnection is in safe mode. */
+    public boolean isInSafeMode() {
+        // Accessing internal state; must only be done on looper thread.
+        mVcnContext.ensureRunningOnLooperThread();
+
+        return mIsInSafeMode;
+    }
+
     /**
      * Asynchronously tears down this GatewayConnection, and any resources used.
      *
@@ -980,7 +999,7 @@
         // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed()
         if (exception != null) {
             mGatewayStatusCallback.onGatewayConnectionError(
-                    mConnectionConfig.getExposedCapabilities(),
+                    mConnectionConfig.getGatewayConnectionName(),
                     VCN_ERROR_CODE_INTERNAL_ERROR,
                     RuntimeException.class.getName(),
                     "Received "
@@ -1017,7 +1036,7 @@
         }
 
         mGatewayStatusCallback.onGatewayConnectionError(
-                mConnectionConfig.getExposedCapabilities(),
+                mConnectionConfig.getGatewayConnectionName(),
                 errorCode,
                 exceptionClass,
                 exceptionMessage);
@@ -1162,6 +1181,15 @@
             }
         }
 
+        protected void handleSafeModeTimeoutExceeded() {
+            mSafeModeTimeoutAlarm = null;
+
+            // Connectivity for this GatewayConnection is broken; tear down the Network.
+            teardownNetwork();
+            mIsInSafeMode = true;
+            mGatewayStatusCallback.onSafeModeStatusChanged();
+        }
+
         protected void logUnexpectedEvent(int what) {
             Slog.d(TAG, String.format(
                     "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
@@ -1315,8 +1343,7 @@
                     }
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
-                    mGatewayStatusCallback.onEnteredSafeMode();
-                    mSafeModeTimeoutAlarm = null;
+                    handleSafeModeTimeoutExceeded();
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1401,8 +1428,7 @@
                     handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
-                    mGatewayStatusCallback.onEnteredSafeMode();
-                    mSafeModeTimeoutAlarm = null;
+                    handleSafeModeTimeoutExceeded();
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1432,30 +1458,35 @@
                     buildNetworkCapabilities(mConnectionConfig, mUnderlying);
             final LinkProperties lp =
                     buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+            final NetworkAgentConfig nac =
+                    new NetworkAgentConfig.Builder()
+                            .setLegacyType(ConnectivityManager.TYPE_MOBILE)
+                            .build();
 
             final NetworkAgent agent =
-                    new NetworkAgent(
-                            mVcnContext.getContext(),
-                            mVcnContext.getLooper(),
+                    mDeps.newNetworkAgent(
+                            mVcnContext,
                             TAG,
                             caps,
                             lp,
                             Vcn.getNetworkScore(),
-                            new NetworkAgentConfig.Builder().build(),
-                            mVcnContext.getVcnNetworkProvider()) {
-                        @Override
-                        public void onNetworkUnwanted() {
-                            Slog.d(TAG, "NetworkAgent was unwanted");
-                            teardownAsynchronously();
-                        }
-
-                        @Override
-                        public void onValidationStatus(int status, @Nullable Uri redirectUri) {
-                            if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
-                                clearFailedAttemptCounterAndSafeModeAlarm();
-                            }
-                        }
-                    };
+                            nac,
+                            mVcnContext.getVcnNetworkProvider(),
+                            () -> {
+                                Slog.d(TAG, "NetworkAgent was unwanted");
+                                // If network agent has already been torn down, skip sending the
+                                // disconnect. Unwanted() is always called, even when networkAgents
+                                // are unregistered in teardownNetwork(), so prevent duplicate
+                                // notifications.
+                                if (mNetworkAgent != null) {
+                                    teardownAsynchronously();
+                                }
+                            } /* networkUnwantedCallback */,
+                            (status) -> {
+                                if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+                                    clearFailedAttemptCounterAndSafeModeAlarm();
+                                }
+                            } /* validationStatusCallback */);
 
             agent.register();
             agent.markConnected();
@@ -1469,6 +1500,11 @@
             // Validated connection, clear failed attempt counter
             mFailedAttempts = 0;
             cancelSafeModeAlarm();
+
+            if (mIsInSafeMode) {
+                mIsInSafeMode = false;
+                mGatewayStatusCallback.onSafeModeStatusChanged();
+            }
         }
 
         protected void applyTransform(
@@ -1491,13 +1527,6 @@
         protected void setupInterface(
                 int token,
                 @NonNull IpSecTunnelInterface tunnelIface,
-                @NonNull VcnChildSessionConfiguration childConfig) {
-            setupInterface(token, tunnelIface, childConfig, null);
-        }
-
-        protected void setupInterface(
-                int token,
-                @NonNull IpSecTunnelInterface tunnelIface,
                 @NonNull VcnChildSessionConfiguration childConfig,
                 @Nullable VcnChildSessionConfiguration oldChildConfig) {
             try {
@@ -1579,16 +1608,17 @@
                             transformCreatedInfo.direction);
                     break;
                 case EVENT_SETUP_COMPLETED:
+                    final VcnChildSessionConfiguration oldChildConfig = mChildConfig;
                     mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
 
-                    setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
+                    setupInterfaceAndNetworkAgent(
+                            mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
                     handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
-                    mGatewayStatusCallback.onEnteredSafeMode();
-                    mSafeModeTimeoutAlarm = null;
+                    handleSafeModeTimeoutExceeded();
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1626,8 +1656,9 @@
         protected void setupInterfaceAndNetworkAgent(
                 int token,
                 @NonNull IpSecTunnelInterface tunnelIface,
-                @NonNull VcnChildSessionConfiguration childConfig) {
-            setupInterface(token, tunnelIface, childConfig);
+                @NonNull VcnChildSessionConfiguration childConfig,
+                @NonNull VcnChildSessionConfiguration oldChildConfig) {
+            setupInterface(token, tunnelIface, childConfig, oldChildConfig);
 
             if (mNetworkAgent == null) {
                 mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
@@ -1692,8 +1723,7 @@
                     handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
-                    mGatewayStatusCallback.onEnteredSafeMode();
-                    mSafeModeTimeoutAlarm = null;
+                    handleSafeModeTimeoutExceeded();
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1935,6 +1965,16 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
+    NetworkAgent getNetworkAgent() {
+        return mNetworkAgent;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
+        mNetworkAgent = networkAgent;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
     void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
         sendMessageAndAcquireWakeLock(
                 EVENT_DISCONNECT_REQUESTED,
@@ -2018,6 +2058,38 @@
             return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
         }
 
+        /** Builds a new NetworkAgent. */
+        public NetworkAgent newNetworkAgent(
+                @NonNull VcnContext vcnContext,
+                @NonNull String tag,
+                @NonNull NetworkCapabilities caps,
+                @NonNull LinkProperties lp,
+                @NonNull int score,
+                @NonNull NetworkAgentConfig nac,
+                @NonNull NetworkProvider provider,
+                @NonNull Runnable networkUnwantedCallback,
+                @NonNull Consumer<Integer> validationStatusCallback) {
+            return new NetworkAgent(
+                    vcnContext.getContext(),
+                    vcnContext.getLooper(),
+                    tag,
+                    caps,
+                    lp,
+                    score,
+                    nac,
+                    provider) {
+                @Override
+                public void onNetworkUnwanted() {
+                    networkUnwantedCallback.run();
+                }
+
+                @Override
+                public void onValidationStatus(int status, @Nullable Uri redirectUri) {
+                    validationStatusCallback.accept(status);
+                }
+            };
+        }
+
         /** Gets the elapsed real time since boot, in millis. */
         public long getElapsedRealTime() {
             return SystemClock.elapsedRealtime();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index ea47a27..d0bd8b3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -102,6 +102,7 @@
         "libaudioclient",
         "libbase",
         "libappfuse",
+        "libbinder_ndk",
         "libbinder",
         "libcutils",
         "libcrypto",
@@ -110,7 +111,7 @@
         "libhardware",
         "libhardware_legacy",
         "libhidlbase",
-        "libkeystore_binder",
+        "libmemtrackproxy",
         "libmtp",
         "libnativehelper",
         "libprocessgroup",
@@ -155,6 +156,7 @@
         "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
         "android.hardware.light@2.0",
+        "android.hardware.memtrack-V1-ndk_platform",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
         "android.hardware.power-V1-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index d18043f..b93b8ab 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -23,11 +23,14 @@
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
 
+#include <android/binder_manager.h>
+#include <android/binder_stability.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <binder/IServiceManager.h>
 #include <hidl/HidlTransportSupport.h>
 #include <incremental_service.h>
 
+#include <memtrackproxy/MemtrackProxy.h>
 #include <schedulerservice/SchedulingPolicyService.h>
 #include <sensorservice/SensorService.h>
 #include <sensorservicehidl/SensorManager.h>
@@ -57,6 +60,21 @@
 
 }
 
+static void android_server_SystemServer_startMemtrackProxyService(JNIEnv* env,
+                                                                  jobject /* clazz */) {
+    using aidl::android::hardware::memtrack::MemtrackProxy;
+
+    const char* memtrackProxyService = "memtrack.proxy";
+
+    std::shared_ptr<MemtrackProxy> memtrack_proxy = ndk::SharedRefBase::make<MemtrackProxy>();
+    auto binder = memtrack_proxy->asBinder();
+
+    AIBinder_forceDowngradeToLocalStability(binder.get());
+
+    const binder_exception_t err = AServiceManager_addService(binder.get(), memtrackProxyService);
+    LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", memtrackProxyService, err);
+}
+
 static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
     using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
     using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
@@ -121,6 +139,8 @@
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         {"startSensorService", "()V", (void*)android_server_SystemServer_startSensorService},
+        {"startMemtrackProxyService", "()V",
+         (void*)android_server_SystemServer_startMemtrackProxyService},
         {"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
         {"initZygoteChildHeapProfiling", "()V",
          (void*)android_server_SystemServer_initZygoteChildHeapProfiling},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 46ec65d..81ec8f4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -96,6 +96,7 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
+import com.android.server.art.ArtManagerLocal;
 import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.AuthService;
@@ -392,6 +393,11 @@
     private static native void startSensorService();
 
     /**
+     * Start the memtrack proxy service.
+     */
+    private static native void startMemtrackProxyService();
+
+    /**
      * Start all HIDL services that are run inside the system server. This may take some time.
      */
     private static native void startHidlServices();
@@ -829,6 +835,12 @@
         mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
         t.traceEnd();
 
+        // Start MemtrackProxyService before ActivityManager, so that early calls
+        // to Memtrack::getMemory() don't fail.
+        t.traceBegin("MemtrackProxyService");
+        startMemtrackProxyService();
+        t.traceEnd();
+
         // Activity manager runs the show.
         t.traceBegin("StartActivityManager");
         // TODO: Might need to move after migration to WM.
@@ -2330,6 +2342,10 @@
         }
         t.traceEnd();
 
+        t.traceBegin("ArtManagerLocal");
+        LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
+        t.traceEnd();
+
         t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
         mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
         t.traceEnd();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 29aedce..1208ecc 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -30,6 +30,8 @@
 import android.os.ServiceManager;
 import android.os.UpdateEngine;
 import android.os.UpdateEngineCallback;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.util.Log;
 
@@ -301,10 +303,18 @@
 
         new Thread(() -> {
             try {
-                String reportPath = mIProfcollect.report();
+                String reportUuid = mIProfcollect.report();
+
                 if (!uploadReport) {
                     return;
                 }
+
+                final int profileId = getBBProfileId();
+                mIProfcollect.copy_report_to_bb(profileId, reportUuid);
+                String reportPath =
+                        "/data/user/" + profileId
+                        + "/com.google.android.apps.internal.betterbug/cache/"
+                        + reportUuid + ".zip";
                 Intent uploadIntent =
                         new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE")
                         .setPackage("com.google.android.apps.internal.betterbug")
@@ -316,9 +326,27 @@
                 if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) {
                     context.sendBroadcast(uploadIntent);
                 }
+                mIProfcollect.delete_report(reportUuid);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, e.getMessage());
             }
         }).start();
     }
+
+    /**
+     * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system
+     * user ID.
+     *
+     * @return BetterBug's profile ID.
+     */
+    private int getBBProfileId() {
+        UserManager userManager = UserManager.get(getContext());
+        int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false);
+        for (int p : profiles) {
+            if (userManager.getUserInfo(p).isManagedProfile()) {
+                return p;
+            }
+        }
+        return UserHandle.USER_SYSTEM;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index fb01ff6..e9e2486 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,12 @@
 
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
@@ -29,16 +35,17 @@
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.uidPoliciesToString;
 import static android.net.NetworkPolicyManager.uidRulesToString;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
@@ -49,7 +56,6 @@
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.Process.SYSTEM_UID;
 import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
 import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
 import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -66,6 +72,7 @@
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -144,6 +151,7 @@
 import android.util.Pair;
 import android.util.Range;
 import android.util.RecurrenceRule;
+import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
@@ -1773,119 +1781,75 @@
                 true);
     }
 
-    /**
-     * Test that when StatsProvider triggers limit reached, new limit will be calculated and
-     * re-armed.
-     */
-    @Test
-    public void testStatsProviderLimitReached() throws Exception {
-        final int CYCLE_DAY = 15;
-
-        final NetworkStats stats = new NetworkStats(0L, 1);
+    private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
         stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
-                2999, 1, 2000, 1, 0);
+                rxBytes, 1, txBytes, 1, 0);
         when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
                 .thenReturn(stats.getTotalBytes());
         when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
                 .thenReturn(stats);
+    }
+
+    private void triggerOnStatsProviderWarningOrLimitReached() throws InterruptedException {
+        final NetworkPolicyManagerInternal npmi = LocalServices
+                .getService(NetworkPolicyManagerInternal.class);
+        npmi.onStatsProviderWarningOrLimitReached("TEST");
+        // Wait for processing of MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED.
+        postMsgAndWaitForCompletion();
+        verify(mStatsService).forceUpdate();
+        // Wait for processing of MSG_*_INTERFACE_QUOTAS.
+        postMsgAndWaitForCompletion();
+    }
+
+    /**
+     * Test that when StatsProvider triggers warning and limit reached, new quotas will be
+     * calculated and re-armed.
+     */
+    @Test
+    public void testStatsProviderWarningAndLimitReached() throws Exception {
+        final int CYCLE_DAY = 15;
+
+        final NetworkStats stats = new NetworkStats(0L, 1);
+        increaseMockedTotalBytes(stats, 2999, 2000);
 
         // Get active mobile network in place
         expectMobileDefaults();
         mService.updateNetworks();
-        verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, Long.MAX_VALUE);
+        verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
+                Long.MAX_VALUE);
 
-        // Set limit to 10KB.
+        // Set warning to 7KB and limit to 10KB.
         setNetworkPolicies(new NetworkPolicy(
-                sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, 10000L,
-                true));
+                sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L, true));
         postMsgAndWaitForCompletion();
 
-        // Verifies that remaining quota is set to providers.
-        verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L);
-
+        // Verifies that remaining quotas are set to providers.
+        verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
         reset(mStatsService);
 
-        // Increase the usage.
-        stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
-                1000, 1, 999, 1, 0);
-        when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
-                .thenReturn(stats.getTotalBytes());
-        when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
-                .thenReturn(stats);
+        // Increase the usage and simulates that limit reached fires earlier by provider,
+        // but actually the quota is not yet reached. Verifies that the limit reached leads to
+        // a force update and new quotas should be set.
+        increaseMockedTotalBytes(stats, 1000, 999);
+        triggerOnStatsProviderWarningOrLimitReached();
+        verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
+        reset(mStatsService);
 
-        // Simulates that limit reached fires earlier by provider, but actually the quota is not
-        // yet reached.
-        final NetworkPolicyManagerInternal npmi = LocalServices
-                .getService(NetworkPolicyManagerInternal.class);
-        npmi.onStatsProviderLimitReached("TEST");
+        // Increase the usage and simulate warning reached, the new warning should be unlimited
+        // since service will disable warning quota to stop lower layer from keep triggering
+        // warning reached event.
+        increaseMockedTotalBytes(stats, 1000L, 1000);
+        triggerOnStatsProviderWarningOrLimitReached();
+        verify(mStatsService).setStatsProviderWarningAndLimitAsync(
+                TEST_IFACE, Long.MAX_VALUE, 1002L);
+        reset(mStatsService);
 
-        // Verifies that the limit reached leads to a force update and new limit should be set.
-        postMsgAndWaitForCompletion();
-        verify(mStatsService).forceUpdate();
-        postMsgAndWaitForCompletion();
-        verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L - 1999L);
-    }
-
-    /**
-     * Exhaustively test checkUidNetworkingBlocked to output the expected results based on external
-     * conditions.
-     */
-    @Test
-    public void testCheckUidNetworkingBlocked() {
-        final ArrayList<Pair<Boolean, Integer>> expectedBlockedStates = new ArrayList<>();
-
-        // Metered network. Data saver on.
-        expectedBlockedStates.add(new Pair<>(true, RULE_NONE));
-        expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
-        expectedBlockedStates.add(new Pair<>(true, RULE_ALLOW_ALL));
-        expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
-        verifyNetworkBlockedState(
-                true /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
-        expectedBlockedStates.clear();
-
-        // Metered network. Data saver off.
-        expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
-        expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
-        expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
-        verifyNetworkBlockedState(
-                true /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
-        expectedBlockedStates.clear();
-
-        // Non-metered network. Data saver on.
-        expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
-        expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_REJECT_METERED));
-        expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
-        expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
-        verifyNetworkBlockedState(
-                false /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
-
-        // Non-metered network. Data saver off. The result is the same as previous case since
-        // the network is blocked only for RULE_REJECT_ALL regardless of data saver.
-        verifyNetworkBlockedState(
-                false /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
-        expectedBlockedStates.clear();
-    }
-
-    private void verifyNetworkBlockedState(boolean metered, boolean backgroundRestricted,
-            ArrayList<Pair<Boolean, Integer>> expectedBlockedStateForRules) {
-
-        for (Pair<Boolean, Integer> pair : expectedBlockedStateForRules) {
-            final boolean expectedResult = pair.first;
-            final int rule = pair.second;
-            assertEquals(formatBlockedStateError(UID_A, rule, metered, backgroundRestricted),
-                    expectedResult, mService.checkUidNetworkingBlocked(UID_A, rule,
-                            metered, backgroundRestricted));
-            assertFalse(formatBlockedStateError(SYSTEM_UID, rule, metered, backgroundRestricted),
-                    mService.checkUidNetworkingBlocked(SYSTEM_UID, rule, metered,
-                            backgroundRestricted));
-        }
+        // Increase the usage that over the warning and limit, the new limit should set to 1 to
+        // block the network traffic.
+        increaseMockedTotalBytes(stats, 1000L, 1000);
+        triggerOnStatsProviderWarningOrLimitReached();
+        verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
+        reset(mStatsService);
     }
 
     private void enableRestrictedMode(boolean enable) throws Exception {
@@ -1948,6 +1912,65 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
     }
 
+    @Test
+    public void testUpdateEffectiveBlockedReasons() {
+        final SparseArray<Pair<Integer, Integer>> effectiveBlockedReasons = new SparseArray<>();
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE));
+
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+                        ALLOWED_REASON_SYSTEM));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_METERED_REASON_DATA_SAVER,
+                        ALLOWED_METERED_REASON_SYSTEM));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+                                | BLOCKED_METERED_REASON_USER_RESTRICTED,
+                        ALLOWED_METERED_REASON_SYSTEM));
+
+        effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+                        ALLOWED_REASON_SYSTEM));
+        effectiveBlockedReasons.put(BLOCKED_REASON_APP_STANDBY,
+                Pair.create(BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED,
+                        ALLOWED_METERED_REASON_SYSTEM));
+
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+                        ALLOWED_REASON_FOREGROUND));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND));
+        effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+                Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+                                | BLOCKED_METERED_REASON_USER_RESTRICTED,
+                        ALLOWED_METERED_REASON_FOREGROUND));
+        effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+                        ALLOWED_REASON_FOREGROUND));
+        effectiveBlockedReasons.put(BLOCKED_REASON_BATTERY_SAVER,
+                Pair.create(BLOCKED_REASON_BATTERY_SAVER
+                                | BLOCKED_METERED_REASON_USER_RESTRICTED,
+                        ALLOWED_METERED_REASON_FOREGROUND));
+        // TODO: test more combinations of blocked reasons.
+
+        for (int i = 0; i < effectiveBlockedReasons.size(); ++i) {
+            final int expectedEffectiveBlockedReasons = effectiveBlockedReasons.keyAt(i);
+            final int blockedReasons = effectiveBlockedReasons.valueAt(i).first;
+            final int allowedReasons = effectiveBlockedReasons.valueAt(i).second;
+            final String errorMsg = "Expected="
+                    + blockedReasonsToString(expectedEffectiveBlockedReasons)
+                    + "; blockedReasons=" + blockedReasonsToString(blockedReasons)
+                    + ", allowedReasons=" + allowedReasonsToString(allowedReasons);
+            assertEquals(errorMsg, expectedEffectiveBlockedReasons,
+                    getEffectiveBlockedReasons(blockedReasons, allowedReasons));
+        }
+    }
+
     private String formatBlockedStateError(int uid, int rule, boolean metered,
             boolean backgroundRestricted) {
         return String.format(
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
index 13d75a7..7d6f4ac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -22,6 +22,7 @@
 import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
 
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -49,6 +50,9 @@
     private static final String COMPILER_FILTER = "space-profile";
     private static final String PROFILE_DEX_METADATA = "primary.prof";
     private static final String VDEX_DEX_METADATA = "primary.vdex";
+    private static final String INSTRUCTION_SET = "arm64";
+    private static final String BASE_APK = "base.apk";
+    private static final String SPLIT_APK = "split.apk";
     private static final byte[] DEX_CONTENT = "dexData".getBytes();
     private static final int COMPILATION_REASON = 1;
     private static final int RESULT_CODE = 222;
@@ -97,17 +101,19 @@
             ArtStatsLogUtils.writeStatsLog(
                     mockLogger,
                     SESSION_ID,
-                    apk.toString(),
                     COMPILER_FILTER,
                     UID,
                     COMPILE_TIME,
                     dexMetadataPath.toString(),
                     COMPILATION_REASON,
-                    RESULT_CODE);
+                    RESULT_CODE,
+                    ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                    INSTRUCTION_SET,
+                    apk.toString());
 
             // Assert
             verifyWrites(ArtStatsLog.
-                ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX);
+                    ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX);
         } finally {
             deleteSliently(dexMetadataPath);
             deleteSliently(apk);
@@ -127,17 +133,19 @@
             ArtStatsLogUtils.writeStatsLog(
                     mockLogger,
                     SESSION_ID,
-                    apk.toString(),
                     COMPILER_FILTER,
                     UID,
                     COMPILE_TIME,
                     dexMetadataPath.toString(),
                     COMPILATION_REASON,
-                    RESULT_CODE);
+                    RESULT_CODE,
+                    ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                    INSTRUCTION_SET,
+                    apk.toString());
 
             // Assert
             verifyWrites(ArtStatsLog.
-                ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE);
+                    ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE);
         } finally {
             deleteSliently(dexMetadataPath);
             deleteSliently(apk);
@@ -157,17 +165,19 @@
             ArtStatsLogUtils.writeStatsLog(
                     mockLogger,
                     SESSION_ID,
-                    apk.toString(),
                     COMPILER_FILTER,
                     UID,
                     COMPILE_TIME,
                     dexMetadataPath.toString(),
                     COMPILATION_REASON,
-                    RESULT_CODE);
+                    RESULT_CODE,
+                    ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                    INSTRUCTION_SET,
+                    apk.toString());
 
             // Assert
             verifyWrites(ArtStatsLog.
-                ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX);
+                    ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX);
         } finally {
             deleteSliently(dexMetadataPath);
             deleteSliently(apk);
@@ -185,17 +195,19 @@
             ArtStatsLogUtils.writeStatsLog(
                     mockLogger,
                     SESSION_ID,
-                    apk.toString(),
                     COMPILER_FILTER,
                     UID,
                     COMPILE_TIME,
                     /*dexMetadataPath=*/ null,
                     COMPILATION_REASON,
-                    RESULT_CODE);
+                    RESULT_CODE,
+                    ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                    INSTRUCTION_SET,
+                    apk.toString());
 
             // Assert
             verifyWrites(ArtStatsLog.
-                ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE);
+                    ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE);
         } finally {
             deleteSliently(apk);
         }
@@ -214,23 +226,36 @@
             ArtStatsLogUtils.writeStatsLog(
                     mockLogger,
                     SESSION_ID,
-                    apk.toString(),
                     COMPILER_FILTER,
                     UID,
                     COMPILE_TIME,
                     dexMetadataPath.toString(),
                     COMPILATION_REASON,
-                    RESULT_CODE);
+                    RESULT_CODE,
+                    ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                    INSTRUCTION_SET,
+                    apk.toString());
 
             // Assert
             verifyWrites(ArtStatsLog.
-                ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN);
+                    ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN);
         } finally {
             deleteSliently(dexMetadataPath);
             deleteSliently(apk);
         }
     }
 
+    @Test
+    public void testGetApkType() {
+        // Act
+        int result1 = ArtStatsLogUtils.getApkType(BASE_APK);
+        int result2 = ArtStatsLogUtils.getApkType(SPLIT_APK);
+
+        // Assert
+        Assert.assertEquals(result1, ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE);
+        Assert.assertEquals(result2, ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT);
+    }
+
     private void verifyWrites(int dexMetadataType) {
         InOrder inorder = inOrder(mockLogger);
         inorder.verify(mockLogger).write(
@@ -239,7 +264,19 @@
                 COMPILER_FILTER,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
                 RESULT_CODE,
-                dexMetadataType);
+                dexMetadataType,
+                ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                INSTRUCTION_SET);
+        inorder.verify(mockLogger).write(
+                SESSION_ID,
+                UID,
+                COMPILATION_REASON,
+                COMPILER_FILTER,
+                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+                DEX_CONTENT.length,
+                dexMetadataType,
+                ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                INSTRUCTION_SET);
         inorder.verify(mockLogger).write(
                 SESSION_ID,
                 UID,
@@ -247,7 +284,9 @@
                 COMPILER_FILTER,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
                 COMPILE_TIME,
-                dexMetadataType);
+                dexMetadataType,
+                ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+                INSTRUCTION_SET);
     }
 
     private Path zipFiles(String suffix, Path... files) throws IOException {
diff --git a/telecomm/java/Android.bp b/telecomm/java/Android.bp
new file mode 100644
index 0000000..3bd5953
--- /dev/null
+++ b/telecomm/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-telecomm-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 973b20a..ae5db3d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1153,6 +1153,10 @@
             builder.append(isLong ? " PROPERTY_IS_ADHOC_CONFERENCE" : " adhoc_conf");
         }
 
+        if ((properties & PROPERTY_IS_DOWNGRADED_CONFERENCE) == PROPERTY_IS_DOWNGRADED_CONFERENCE) {
+            builder.append(isLong ? " PROPERTY_IS_DOWNGRADED_CONFERENCE" : " dngrd_conf");
+        }
+
         builder.append("]");
         return builder.toString();
     }
diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp
new file mode 100644
index 0000000..201ab53
--- /dev/null
+++ b/telephony/common/Android.bp
@@ -0,0 +1,29 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-telephony-common-sources",
+    srcs: [
+        "**/*.java",
+        ":statslog-telephony-common-java-gen",
+    ],
+    visibility: [
+        "//frameworks/base",
+        "//frameworks/base/tests/TelephonyCommonTests",
+    ],
+}
+
+genrule {
+    name: "statslog-telephony-common-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
+        " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
+    out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
+    visibility: ["//visibility:private"],
+}
diff --git a/telephony/java/Android.bp b/telephony/java/Android.bp
new file mode 100644
index 0000000..3941b30
--- /dev/null
+++ b/telephony/java/Android.bp
@@ -0,0 +1,18 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-BSD
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-telephony-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0ba96a9..f027cd1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -17,7 +17,6 @@
 package android.telephony;
 
 import android.Manifest;
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -32,10 +31,11 @@
 import android.os.RemoteException;
 import android.service.carrier.CarrierService;
 import android.telecom.TelecomManager;
+import android.telephony.gba.TlsParams;
+import android.telephony.gba.UaSecurityProtocolIdentifier;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsRegistrationAttributes;
 import android.telephony.ims.ImsSsData;
-import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature;
 
@@ -3616,6 +3616,71 @@
     public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
 
     /**
+     * Indicates that GBA_ME should be used for GBA authentication, as defined in 3GPP TS 33.220.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_ME = 1;
+
+    /**
+     * Indicates that GBA_U should be used for GBA authentication, as defined in 3GPP TS 33.220.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_U = 2;
+
+    /**
+     * Indicates that GBA_Digest should be used for GBA authentication, as defined
+     * in 3GPP TS 33.220.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_DIGEST = 3;
+
+    /**
+     * An integer representing the GBA mode to use for requesting credentials
+     * via {@link TelephonyManager#bootstrapAuthenticationRequest}.
+     *
+     * One of {@link #GBA_ME}, {@link #GBA_U}, or {@link #GBA_DIGEST}.
+     * @hide
+     */
+    @SystemApi
+    public static final String KEY_GBA_MODE_INT = "gba_mode_int";
+
+    /**
+     * An integer representing the organization code to be used when building the
+     * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+     *
+     * See the {@code ORG_} constants in {@link UaSecurityProtocolIdentifier}.
+     * @hide
+     */
+    @SystemApi
+    public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT =
+            "gba_ua_security_organization_int";
+
+    /**
+     * An integer representing the security protocol to be used when building the
+     * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+     *
+     * See the {@code UA_SECURITY_PROTOCOL_} constants in {@link UaSecurityProtocolIdentifier}.
+     * @hide
+     */
+    @SystemApi
+    public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT =
+            "gba_ua_security_protocol_int";
+
+    /**
+     * An integer representing the cipher suite to be used when building the
+     * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+     *
+     * See the {@code TLS_} constants in {@link android.telephony.gba.TlsParams}.
+     * @hide
+     */
+    @SystemApi
+    public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT =
+            "gba_ua_tls_cipher_suite_int";
+
+    /**
      * GPS configs. See the GNSS HAL documentation for more details.
      */
     public static final class Gps {
@@ -4286,6 +4351,15 @@
      */
     public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
 
+    /**
+     * Determine whether or not to display no data notification when data setup is permanently
+     * failed.
+     *
+     * @hide
+     */
+    public static final String KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL =
+            "display_no_data_notification_on_permanent_failure_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -4823,6 +4897,13 @@
         // Default wifi configurations.
         sDefaults.putAll(Wifi.getDefaults());
         sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
+        sDefaults.putInt(KEY_GBA_MODE_INT, GBA_ME);
+        sDefaults.putInt(KEY_GBA_UA_SECURITY_ORGANIZATION_INT,
+                UaSecurityProtocolIdentifier.ORG_3GPP);
+        sDefaults.putInt(KEY_GBA_UA_SECURITY_PROTOCOL_INT,
+                UaSecurityProtocolIdentifier.UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT);
+        sDefaults.putInt(KEY_GBA_UA_TLS_CIPHER_SUITE_INT, TlsParams.TLS_NULL_WITH_NULL_NULL);
+
         sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
         sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1));
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY,
@@ -4844,6 +4925,7 @@
                 new String[]{"ia", "default", "ims", "mms", "dun", "emergency"});
         sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false);
+        sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 9ea624b..ce2f3f9 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -166,14 +166,12 @@
     /**
      * @return The unique id of the data connection
      *
-     * Note this is the id assigned in {@link DataCallResponse}.
+     * Note this is the id assigned by the data service.
      * The id remains the same for data connection handover between
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN} and
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}
      *
-     * @hide
      */
-    @SystemApi
     public int getId() {
         return mId;
     }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 85fe14e..47a802f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2465,7 +2465,10 @@
         if (subInfo != null) {
             overrideConfig.mcc = subInfo.getMcc();
             overrideConfig.mnc = subInfo.getMnc();
-            if (overrideConfig.mnc == 0) overrideConfig.mnc = Configuration.MNC_ZERO;
+            if (overrideConfig.mnc == 0) {
+                overrideConfig.mnc = Configuration.MNC_ZERO;
+                cacheKey = null;
+            }
         }
 
         if (useRootLocale) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7c39cf0..a2467f2 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -99,6 +99,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.IBooleanConsumer;
 import com.android.internal.telephony.ICallForwardingInfoCallback;
@@ -128,6 +129,7 @@
 import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -417,6 +419,27 @@
     }
 
     /**
+     * Post a runnable to the BackgroundThread.
+     *
+     * Used to invoke user callbacks without calling into the caller's executor from the caller's
+     * calling thread context, for example to provide asynchronous error information that is
+     * generated locally (not over a binder thread).
+     *
+     * <p>This is not necessary unless you are invoking caller's code asynchronously from within
+     * the caller's thread context.
+     *
+     * @param r a runnable.
+     */
+    private static void runOnBackgroundThread(@NonNull Runnable r) {
+        try {
+            BackgroundThread.getExecutor().execute(r);
+        } catch (RejectedExecutionException e) {
+            throw new IllegalStateException(
+                    "Failed to post a callback from the caller's thread context.", e);
+        }
+    }
+
+    /**
      * Returns the multi SIM variant
      * Returns DSDS for Dual SIM Dual Standby
      * Returns DSDA for Dual SIM Dual Active
@@ -5875,7 +5898,7 @@
 
         /**
          * Error response to
-         * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
+         * {@link TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
          *
          * Invoked when an error condition prevents updated {@link CellInfo} from being fetched
          * and returned from the modem. Callers of requestCellInfoUpdate() should override this
@@ -5893,6 +5916,20 @@
     };
 
     /**
+     * Used for checking if the target SDK version for the current process is S or above.
+     *
+     * <p> Applies to the following methods:
+     * {@link #requestCellInfoUpdate},
+     * {@link #setPreferredOpportunisticDataSubscription},
+     * {@link #updateAvailableNetworks},
+     * requestNumberVerification(),
+     * setSimPowerStateForSlot(),
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+    private static final long NULL_TELEPHONY_THROW_NO_CB = 182185642L;
+
+    /**
      * Requests all available cell information from the current subscription for observed
      * camped/registered, serving, and neighboring cells.
      *
@@ -5912,7 +5949,14 @@
             @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) return;
+            if (telephony == null) {
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Telephony is null");
+                } else {
+                    return;
+                }
+            }
+
             telephony.requestCellInfoUpdate(
                     getSubId(),
                     new ICellInfoCallback.Stub() {
@@ -5939,6 +5983,8 @@
                         }
                     }, getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
+            runOnBackgroundThread(() -> executor.execute(
+                    () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
         }
     }
 
@@ -5966,7 +6012,14 @@
             @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) return;
+            if (telephony == null) {
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Telephony is null");
+                } else {
+                    return;
+                }
+            }
+
             telephony.requestCellInfoUpdateWithWorkSource(
                     getSubId(),
                     new ICellInfoCallback.Stub() {
@@ -5994,6 +6047,8 @@
                         }
                     }, getOpPackageName(), getAttributionTag(), workSource);
         } catch (RemoteException ex) {
+            runOnBackgroundThread(() -> executor.execute(
+                    () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
         }
     }
 
@@ -6960,14 +7015,21 @@
 
         try {
             ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
-                        getOpPackageName());
+            if (telephony == null) {
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Telephony is null");
+                } else {
+                    return;
+                }
             }
+
+            telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
+                    getOpPackageName());
         } catch (RemoteException ex) {
             Rlog.e(TAG, "requestNumberVerification RemoteException", ex);
-            executor.execute(() ->
-                    callback.onVerificationFailed(NumberVerificationCallback.REASON_UNSPECIFIED));
+            runOnBackgroundThread(() -> executor.execute(
+                    () -> callback.onVerificationFailed(
+                            NumberVerificationCallback.REASON_UNSPECIFIED)));
         }
     }
 
@@ -10333,6 +10395,8 @@
         }
         try {
             ITelephony telephony = getITelephony();
+            if (telephony == null) throw new IllegalStateException("Telephony is null.");
+
             IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
                 @Override
                 public void accept(int result) {
@@ -10340,11 +10404,18 @@
                             Binder.withCleanCallingIdentity(() -> callback.accept(result)));
                 }
             };
-            if (telephony != null) {
-                telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
+            if (telephony == null) {
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Telephony is null");
+                } else {
+                    return;
+                }
             }
+            telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+            runOnBackgroundThread(() -> executor.execute(
+                    () -> callback.accept(SET_SIM_POWER_STATE_MODEM_ERROR)));
         } catch (SecurityException e) {
             Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot",
                     e);
@@ -12774,22 +12845,12 @@
         try {
             IOns iOpportunisticNetworkService = getIOns();
             if (iOpportunisticNetworkService == null) {
-                if (executor == null || callback == null) {
-                    return;
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Opportunistic Network Service is null");
+                } else {
+                    // Let the general remote exception handling catch this.
+                    throw new RemoteException("Null Opportunistic Network Service!");
                 }
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(() -> {
-                        if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
-                            callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
-                        } else {
-                            callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
-                        }
-                    });
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-                return;
             }
             ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
                 @Override
@@ -12812,9 +12873,18 @@
                     .setPreferredDataSubscriptionId(subId, needValidation, callbackStub,
                             pkgForDebug);
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "setPreferredDataSubscriptionId RemoteException", ex);
+            Rlog.e(TAG, "setPreferredOpportunisticDataSubscription RemoteException", ex);
+            if (executor == null || callback == null) {
+                return;
+            }
+            runOnBackgroundThread(() -> executor.execute(() -> {
+                if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+                    callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+                } else {
+                    callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+                }
+            }));
         }
-        return;
     }
 
     /**
@@ -12871,37 +12941,18 @@
             @Nullable @CallbackExecutor Executor executor,
             @UpdateAvailableNetworksResult @Nullable Consumer<Integer> callback) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        Objects.requireNonNull(availableNetworks, "availableNetworks must not be null.");
         try {
             IOns iOpportunisticNetworkService = getIOns();
-            if (iOpportunisticNetworkService == null || availableNetworks == null) {
-                if (executor == null || callback == null) {
-                    return;
-                }
-                if (iOpportunisticNetworkService == null) {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        executor.execute(() -> {
-                            if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
-                                callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
-                            } else {
-                                callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
-                            }
-                        });
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
+            if (iOpportunisticNetworkService == null) {
+                if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+                    throw new IllegalStateException("Opportunistic Network Service is null");
                 } else {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        executor.execute(() -> {
-                            callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
-                        });
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
+                    // Let the general remote exception handling catch this.
+                    throw new RemoteException("Null Opportunistic Network Service!");
                 }
-                return;
             }
+
             IUpdateAvailableNetworksCallback callbackStub =
                     new IUpdateAvailableNetworksCallback.Stub() {
                         @Override
@@ -12909,20 +12960,25 @@
                             if (executor == null || callback == null) {
                                 return;
                             }
-                            final long identity = Binder.clearCallingIdentity();
-                            try {
-                                executor.execute(() -> {
-                                    callback.accept(result);
-                                });
-                            } finally {
-                                Binder.restoreCallingIdentity(identity);
-                            }
+                            Binder.withCleanCallingIdentity(() -> {
+                                executor.execute(() -> callback.accept(result));
+                            });
                         }
                     };
-            iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks, callbackStub,
-                    pkgForDebug);
+            iOpportunisticNetworkService
+                    .updateAvailableNetworks(availableNetworks, callbackStub, pkgForDebug);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "updateAvailableNetworks RemoteException", ex);
+            if (executor == null || callback == null) {
+                return;
+            }
+            runOnBackgroundThread(() -> executor.execute(() -> {
+                if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+                    callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+                } else {
+                    callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+                }
+            }));
         }
     }
 
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index b503733..08f5613 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -114,11 +114,15 @@
     public static final int TYPE_MCX = ApnTypes.MCX;
     /** APN type for XCAP. */
     public static final int TYPE_XCAP = ApnTypes.XCAP;
+    /** APN type for VSIM. */
+    public static final int TYPE_VSIM = 1 << 12;  // TODO: Refer to ApnTypes.VSIM
+    /** APN type for BIP. */
+    public static final int TYPE_BIP = 1 << 13;   // TODO: Refer to ApnTypes.BIP
     /**
      * APN type for ENTERPRISE.
      * @hide
      */
-    public static final int TYPE_ENTERPRISE = TYPE_XCAP << 1;
+    public static final int TYPE_ENTERPRISE = TYPE_BIP << 1;
 
     /** @hide */
     @IntDef(flag = true, prefix = {"TYPE_"}, value = {
@@ -134,6 +138,8 @@
             TYPE_EMERGENCY,
             TYPE_MCX,
             TYPE_XCAP,
+            TYPE_BIP,
+            TYPE_VSIM,
             TYPE_ENTERPRISE,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -174,6 +180,8 @@
             TYPE_MMS_STRING,
             TYPE_SUPL_STRING,
             TYPE_XCAP_STRING,
+            TYPE_VSIM_STRING,
+            TYPE_BIP_STRING,
             TYPE_ENTERPRISE_STRING,
     }, prefix = "TYPE_", suffix = "_STRING")
     @Retention(RetentionPolicy.SOURCE)
@@ -315,8 +323,33 @@
     @SystemApi
     public static final String TYPE_XCAP_STRING = "xcap";
 
+
+
+    /**
+     * APN type for Virtual SIM service.
+     *
+     * Note: String representations of APN types are intended for system apps to communicate with
+     * modem components or carriers. Non-system apps should use the integer variants instead.
+     * @hide
+     */
+    @SystemApi
+    public static final String TYPE_VSIM_STRING = "vsim";
+
+    /**
+     * APN type for Bearer Independent Protocol.
+     *
+     * Note: String representations of APN types are intended for system apps to communicate with
+     * modem components or carriers. Non-system apps should use the integer variants instead.
+     * @hide
+     */
+    @SystemApi
+    public static final String TYPE_BIP_STRING = "bip";
+
     /**
      * APN type for ENTERPRISE traffic.
+     *
+     * Note: String representations of APN types are intended for system apps to communicate with
+     * modem components or carriers. Non-system apps should use the integer variants instead.
      * @hide
      */
     public static final String TYPE_ENTERPRISE_STRING = "enterprise";
@@ -401,6 +434,8 @@
         APN_TYPE_STRING_MAP.put(TYPE_MCX_STRING, TYPE_MCX);
         APN_TYPE_STRING_MAP.put(TYPE_XCAP_STRING, TYPE_XCAP);
         APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE);
+        APN_TYPE_STRING_MAP.put(TYPE_VSIM_STRING, TYPE_VSIM);
+        APN_TYPE_STRING_MAP.put(TYPE_BIP_STRING, TYPE_BIP);
 
         APN_TYPE_INT_MAP = new ArrayMap<>();
         APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING);
@@ -416,6 +451,8 @@
         APN_TYPE_INT_MAP.put(TYPE_MCX, TYPE_MCX_STRING);
         APN_TYPE_INT_MAP.put(TYPE_XCAP, TYPE_XCAP_STRING);
         APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING);
+        APN_TYPE_INT_MAP.put(TYPE_VSIM, TYPE_VSIM_STRING);
+        APN_TYPE_INT_MAP.put(TYPE_BIP, TYPE_BIP_STRING);
 
         PROTOCOL_STRING_MAP = new ArrayMap<>();
         PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
@@ -2194,7 +2231,7 @@
         public ApnSetting build() {
             if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI
                     | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
-                    | TYPE_XCAP | TYPE_ENTERPRISE)) == 0
+                    | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0
                 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
                 return null;
             }
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index a5e5ab01..ad57b91 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -70,6 +70,7 @@
 
     /** {@hide} */
     @IntDef(prefix = "HANDOVER_FAILURE_MODE_", value = {
+            HANDOVER_FAILURE_MODE_UNKNOWN,
             HANDOVER_FAILURE_MODE_LEGACY,
             HANDOVER_FAILURE_MODE_DO_FALLBACK,
             HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER,
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index 07e95cc..8a31211 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -48,6 +48,9 @@
     private static final String LOG_TAG = "RcsConfig";
     private static final boolean DBG = Build.IS_ENG;
 
+    // Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2
+    private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
+
     private final HashMap<String, String> mValues = new HashMap<>();
 
     private RcsConfig(HashMap<String, String> values) {
@@ -145,6 +148,14 @@
         return mValues.containsKey(tag);
     }
 
+    /**
+     * Check whether Rcs Volte single registration is supported by the config.
+     */
+    public boolean isRcsVolteSingleRegistrationSupported() {
+        return getBoolean(TAG_SINGLE_REGISTRATION, false)
+                || getInteger(TAG_SINGLE_REGISTRATION, 0) != 0;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index a133ead..acfa133 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -282,20 +282,6 @@
      * <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) {
-            return Collections.emptyList();
-        }
-        return Collections.unmodifiableList(new ArrayList<>(mFeatureTags));
-    }
-
-    /**
-     * @return The feature tags present in the OPTIONS response from the network.
-     * <p>
-     * Note: this is only populated if {@link #getCapabilityMechanism} is
-     * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
      */
     public @NonNull Set<String> getFeatureTags() {
         if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index ad6d73c..d21fcab 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -24,6 +24,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.SipMessageParsingUtils;
 
@@ -60,14 +61,19 @@
      */
     public SipMessage(@NonNull String startLine, @NonNull String headerSection,
             @NonNull byte[] content) {
-        if (startLine == null || headerSection == null || content == null) {
-            throw new IllegalArgumentException("One or more null parameters entered");
-        }
+        Objects.requireNonNull(startLine, "Required parameter is null: startLine");
+        Objects.requireNonNull(headerSection, "Required parameter is null: headerSection");
+        Objects.requireNonNull(content, "Required parameter is null: content");
+
         mStartLine = startLine;
         mHeaderSection = headerSection;
         mContent = content;
 
         mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection);
+        if (TextUtils.isEmpty(mViaBranchParam)) {
+            throw new IllegalArgumentException("header section MUST contain a branch parameter "
+                    + "inside of the Via header.");
+        }
         mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection);
     }
 
@@ -107,11 +113,9 @@
 
     /**
      * @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section
-     * 20.42 for more information on the Via header. If {@code null}, then there was either no
-     * Via parameter found in this SIP message's headers or no branch parameter found in the
-     * Via header.
+     * 20.42 for more information on the Via header.
      */
-    public @Nullable String getViaBranchParameter() {
+    public @NonNull String getViaBranchParameter() {
         return mViaBranchParam;
     }
 
@@ -200,7 +204,9 @@
 
     /**
      * @return the UTF-8 encoded SIP message.
+     * @deprecated Use {@link #toEncodedMessage} instead
      */
+    @Deprecated
     public @NonNull byte[] getEncodedMessage() {
         byte[] header = new StringBuilder()
                 .append(mStartLine)
@@ -212,4 +218,26 @@
         System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
         return sipMessage;
     }
+
+    /**
+     * According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
+     * consists of a start-line, one or more header fields, an empty line indicating the end of the
+     * header fields, and an optional message-body.
+     *
+     * <p>
+     * Returns a byte array with UTF-8 format representation of the encoded SipMessage.
+     *
+     * @return byte array with UTF-8 format representation of the encoded SipMessage.
+     */
+    public @NonNull byte[] toEncodedMessage() {
+        byte[] header = new StringBuilder()
+                .append(mStartLine)
+                .append(mHeaderSection)
+                .append(CRLF)
+                .toString().getBytes(UTF_8);
+        byte[] sipMessage = new byte[header.length + mContent.length];
+        System.arraycopy(header, 0, sipMessage, 0, header.length);
+        System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+        return sipMessage;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 739946b..5c9ec53 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,8 +28,6 @@
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.SipMessage;
 import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
-import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Set;
@@ -187,11 +185,6 @@
 
     private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
         String transactionId = m.getViaBranchParameter();
-        if (TextUtils.isEmpty(transactionId)) {
-            Log.w(LOG_TAG, "failure to parse SipMessage.");
-            throw new IllegalArgumentException("Malformed SipMessage, can not determine "
-                    + "transaction ID.");
-        }
         SipDelegate d = mDelegate;
         if (d != null) {
             mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3cd2726..ad02fe5 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,7 +28,6 @@
 import android.telephony.ims.stub.DelegateConnectionMessageCallback;
 import android.telephony.ims.stub.DelegateConnectionStateCallback;
 import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -267,12 +266,6 @@
 
     private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
         String transactionId = m.getViaBranchParameter();
-        if (TextUtils.isEmpty(transactionId)) {
-            Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
-                    + "transaction ID.");
-            throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
-        }
-        mExecutor.execute(() ->
-                mMessageCallback.onMessageSendFailure(transactionId, reason));
+        mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason));
     }
 }
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 6315b24..b384e50 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -391,6 +391,7 @@
      * event to the framework.
      * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
      * exchange if it is supported by the device.
+     * @hide
      */
     public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
             @NonNull Executor executor, @NonNull CapabilityExchangeEventListener listener) {
@@ -399,14 +400,45 @@
     }
 
     /**
+     * Retrieve the implementation of UCE for this {@link RcsFeature}, which can use either
+     * presence or OPTIONS for capability exchange.
+     *
+     * Will only be requested by the framework if capability exchange is configured
+     * as capable during a
+     * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+     * operation and the RcsFeature sets the status of the capability to true using
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+     *
+     * @param listener A {@link CapabilityExchangeEventListener} to send the capability exchange
+     * event to the framework.
+     * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
+     * exchange if it is supported by the device.
+     */
+    public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
+            @NonNull CapabilityExchangeEventListener listener) {
+        // Base Implementation, override to implement functionality
+        return new RcsCapabilityExchangeImplBase();
+    }
+
+    /**
      * Remove the given CapabilityExchangeImplBase instance.
      * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be removed.
+     * @hide
      */
     public void removeCapabilityExchangeImpl(
             @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
         // Override to implement the process of removing RcsCapabilityExchangeImplBase instance.
     }
 
+    /**
+     * Remove the given CapabilityExchangeImplBase instance.
+     * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed.
+     */
+    public void destroyCapabilityExchangeImpl(
+            @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
+        // Override to implement the process of destroying RcsCapabilityExchangeImplBase instance.
+    }
+
     /**{@inheritDoc}*/
     @Override
     public void onFeatureRemoved() {
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 25b9446..57616d35 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -356,12 +356,13 @@
         void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException;
     }
 
-    private final Executor mBinderExecutor;
+    private Executor mBinderExecutor;
 
     /**
      * Create a new RcsCapabilityExchangeImplBase instance.
      *
      * @param executor The executor that remote calls from the framework will be called on.
+     * @hide
      */
     public RcsCapabilityExchangeImplBase(@NonNull Executor executor) {
         if (executor == null) {
@@ -371,6 +372,12 @@
     }
 
     /**
+     * Create a new RcsCapabilityExchangeImplBase instance.
+     */
+    public RcsCapabilityExchangeImplBase() {
+    }
+
+    /**
      * The user capabilities of one or multiple contacts have been requested by the framework.
      * <p>
      * The implementer must follow up this call with an
@@ -434,30 +441,6 @@
      * @param contactUri The URI of the remote user that we wish to get the capabilities of.
      * @param myCapabilities The capabilities of this device to send to the remote user.
      * @param callback The callback of this request which is sent from the remote user.
-     * @hide
-     */
-    // executor used is defined in the constructor.
-    @SuppressLint("ExecutorRegistration")
-    public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
-            @NonNull List<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
-        try {
-            callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
-        } catch (ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-
-    /**
-     * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
-     * in order to receive the capabilities of the remote user in response.
-     * <p>
-     * The implementer must use {@link OptionsResponseCallback} to send the response of
-     * this query from the network back to the framework.
-     * @param contactUri The URI of the remote user that we wish to get the capabilities of.
-     * @param myCapabilities The capabilities of this device to send to the remote user.
-     * @param callback The callback of this request which is sent from the remote user.
      */
     // executor used is defined in the constructor.
     @SuppressLint("ExecutorRegistration")
diff --git a/tests/SilkFX/OWNERS b/tests/SilkFX/OWNERS
new file mode 100644
index 0000000..c88a9f8
--- /dev/null
+++ b/tests/SilkFX/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index a4d8353..1e54093 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -19,6 +19,7 @@
 import android.os.Build
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
+import com.android.modules.utils.build.SdkLevel.isAtLeastS
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.assertParcelSane
@@ -44,7 +45,13 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
         }.build()
-        assertParcelSane(config, 10)
+        if (isAtLeastS()) {
+            // From S, the config will have 12 items
+            assertParcelSane(config, 12)
+        } else {
+            // For R or below, the config will have 10 items
+            assertParcelSane(config, 10)
+        }
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1f50e31..e7718b5 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -38,14 +38,12 @@
 import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
 import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
 import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
 import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
 import static android.os.Process.INVALID_UID;
 
 import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
@@ -103,20 +101,6 @@
 
     @Test
     public void testMaybeMarkCapabilitiesRestricted() {
-        // verify EIMS is restricted
-        assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
-                (1 << NET_CAPABILITY_EIMS));
-
-        // verify CBS is also restricted
-        assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
-                (1 << NET_CAPABILITY_CBS));
-
-        // verify default is not restricted
-        assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
-
-        // just to see
-        assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
-
         // check that internet does not get restricted
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -985,26 +969,6 @@
         assertNotEquals(-50, nc.getSignalStrength());
     }
 
-    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
-    public void testDeduceRestrictedCapability() {
-        final NetworkCapabilities nc = new NetworkCapabilities();
-        // Default capabilities don't have restricted capability.
-        assertFalse(nc.deduceRestrictedCapability());
-        // If there is a force restricted capability, then the network capabilities is restricted.
-        nc.addCapability(NET_CAPABILITY_OEM_PAID);
-        nc.addCapability(NET_CAPABILITY_INTERNET);
-        assertTrue(nc.deduceRestrictedCapability());
-        // Except for the force restricted capability, if there is any unrestricted capability in
-        // capabilities, then the network capabilities is not restricted.
-        nc.removeCapability(NET_CAPABILITY_OEM_PAID);
-        nc.addCapability(NET_CAPABILITY_CBS);
-        assertFalse(nc.deduceRestrictedCapability());
-        // Except for the force restricted capability, the network capabilities will only be treated
-        // as restricted when there is no any unrestricted capability.
-        nc.removeCapability(NET_CAPABILITY_INTERNET);
-        assertTrue(nc.deduceRestrictedCapability());
-    }
-
     private void assertNoTransport(NetworkCapabilities nc) {
         for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
             assertFalse(nc.hasTransport(i));
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index f5a4234..db18500 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     <!-- Reading DeviceConfig flags -->
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner"/>
 
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 36f205b..6cbdd25 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -41,10 +41,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index b7a42ec..fee65f0 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -16,6 +16,9 @@
 
 package android.net;
 
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
+
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 
 import static org.junit.Assert.assertEquals;
@@ -33,23 +36,33 @@
 
     @Test
     public void testParceling() {
-        VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
-        assertParcelSane(v, 1 /* fieldCount */);
+        VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+        assertParcelSane(v, 2 /* fieldCount */);
     }
 
     @Test
     public void testEqualsAndHashCode() {
-        VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
-        VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
-        VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
-        VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
-        VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+        String session1 = "12345";
+        String session2 = "6789";
+        VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+        VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
+        VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+        VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
+        VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
+        VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
 
-        assertNotEquals(v1, v2);
-        assertNotEquals(v3, v4);
-        assertNotEquals(v4, v5);
+        VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+        VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
 
-        assertEquals(v1, v3);
-        assertEquals(v1.hashCode(), v3.hashCode());
+        assertNotEquals(v11, v12);
+        assertNotEquals(v13, v14);
+        assertNotEquals(v14, v15);
+        assertNotEquals(v14, v21);
+
+        assertEquals(v11, v13);
+        assertEquals(v31, v32);
+        assertEquals(v11.hashCode(), v13.hashCode());
+        assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
+        assertEquals(session1, v15.makeCopy(REDACT_NONE).sessionId);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8938c1d..e050495 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,7 +18,12 @@
 
 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
+import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_PACKAGE_REPLACED;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.ACTION_USER_UNLOCKED;
@@ -31,6 +36,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
 import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
 import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
 import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
 import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
@@ -57,6 +63,7 @@
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -83,6 +90,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
 import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
@@ -575,6 +583,7 @@
             final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
                     .getSystemService(UserManager.class);
             doReturn(value).when(umMock).isManagedProfile();
+            doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
         }
 
         @Override
@@ -715,6 +724,9 @@
         private int mProbesSucceeded;
         private String mNmValidationRedirectUrl = null;
         private boolean mNmProvNotificationRequested = false;
+        private Runnable mCreatedCallback;
+        private Runnable mUnwantedCallback;
+        private Runnable mDisconnectedCallback;
 
         private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
         // Contains the redirectUrl from networkStatus(). Before reading, wait for
@@ -769,6 +781,24 @@
                     mRedirectUrl = redirectUrl;
                     mNetworkStatusReceived.open();
                 }
+
+                @Override
+                public void onNetworkCreated() {
+                    super.onNetworkCreated();
+                    if (mCreatedCallback != null) mCreatedCallback.run();
+                }
+
+                @Override
+                public void onNetworkUnwanted() {
+                    super.onNetworkUnwanted();
+                    if (mUnwantedCallback != null) mUnwantedCallback.run();
+                }
+
+                @Override
+                public void onNetworkDestroyed() {
+                    super.onNetworkDestroyed();
+                    if (mDisconnectedCallback != null) mDisconnectedCallback.run();
+                }
             };
 
             assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
@@ -970,6 +1000,18 @@
             p.timestampMillis = DATA_STALL_TIMESTAMP;
             mNmCallbacks.notifyDataStallSuspected(p);
         }
+
+        public void setCreatedCallback(Runnable r) {
+            mCreatedCallback = r;
+        }
+
+        public void setUnwantedCallback(Runnable r) {
+            mUnwantedCallback = r;
+        }
+
+        public void setDisconnectedCallback(Runnable r) {
+            mDisconnectedCallback = r;
+        }
     }
 
     /**
@@ -1193,10 +1235,12 @@
             if (mAgentRegistered) throw new IllegalStateException("already registered");
             updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
             mConfig = new VpnConfig();
+            mConfig.session = "MySession12345";
             setUids(uids);
             if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
             mInterface = VPN_IFNAME;
-            mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+            mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType(),
+                    mConfig.session));
             mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
                     mNetworkCapabilities);
             mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -1373,10 +1417,21 @@
     }
 
     private void mockUidNetworkingBlocked() {
-        doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
+        doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
         ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
     }
 
+    private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
+        final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
+        if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
+            return true;
+        }
+        if (meteredNetwork) {
+            return blockedReasons != BLOCKED_REASON_NONE;
+        }
+        return false;
+    }
+
     private void setBlockedReasonChanged(int blockedReasons) {
         mBlockedReasons = blockedReasons;
         mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
@@ -1571,7 +1626,7 @@
         doReturn(mNetworkStack).when(deps).getNetworkStack();
         doReturn(mSystemProperties).when(deps).getSystemProperties();
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
-        doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+        doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
                     inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -2438,8 +2493,7 @@
     public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
         mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
                 PERMISSION_DENIED);
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_DENIED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
         doNetworkCallbacksSanitizationTest(true /* sanitized */);
     }
 
@@ -2447,7 +2501,7 @@
     public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
         mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
                 PERMISSION_GRANTED);
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
         doNetworkCallbacksSanitizationTest(false /* sanitized */);
     }
 
@@ -2455,7 +2509,7 @@
     public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
         mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
                 PERMISSION_DENIED);
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
         doNetworkCallbacksSanitizationTest(false /* sanitized */);
     }
 
@@ -2746,10 +2800,14 @@
     }
 
     private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
-        final String myPackageName = mContext.getPackageName();
-        when(mPackageManager.getPackageInfo(eq(myPackageName), eq(GET_PERMISSIONS)))
+        grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
+    }
+
+    private void grantUsingBackgroundNetworksPermissionForUid(
+            final int uid, final String packageName) throws Exception {
+        when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
                 .thenReturn(buildPackageInfo(true, uid));
-        mService.mPermissionMonitor.onPackageAdded(myPackageName, uid);
+        mService.mPermissionMonitor.onPackageAdded(packageName, uid);
     }
 
     @Test
@@ -2799,6 +2857,94 @@
     }
 
     @Test
+    public void testNetworkAgentCallbacks() throws Exception {
+        // Keeps track of the order of events that happen in this test.
+        final LinkedBlockingQueue<String> eventOrder = new LinkedBlockingQueue<>();
+
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI).build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+        // Expectations for state when various callbacks fire. These expectations run on the handler
+        // thread and not on the test thread because they need to prevent the handler thread from
+        // advancing while they examine state.
+
+        // 1. When onCreated fires, netd has been told to create the network.
+        mWiFiNetworkAgent.setCreatedCallback(() -> {
+            eventOrder.offer("onNetworkCreated");
+            wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
+            assertNotNull(wifiNetwork.get());
+            try {
+                verify(mMockNetd).networkCreatePhysical(wifiNetwork.get().getNetId(),
+                        INetd.PERMISSION_NONE);
+            } catch (RemoteException impossible) {
+                fail();
+            }
+        });
+
+        // 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
+        //    check that it is fired at some point after disconnect.
+        mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
+
+        // 3. While the teardown timer is running, connectivity APIs report the network is gone, but
+        //    netd has not yet been told to destroy it.
+        final Runnable duringTeardown = () -> {
+            eventOrder.offer("timePasses");
+            assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+            try {
+                verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
+            } catch (RemoteException impossible) {
+                fail();
+            }
+        };
+
+        // 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
+        // and netd has been told to destroy it.
+        mWiFiNetworkAgent.setDisconnectedCallback(() -> {
+            eventOrder.offer("onNetworkDisconnected");
+            assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+            try {
+                verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
+            } catch (RemoteException impossible) {
+                fail();
+            }
+        });
+
+        // Connect a network, and file a request for it after it has come up, to ensure the nascent
+        // timer is cleared and the test does not have to wait for it. Filing the request after the
+        // network has come up is necessary because ConnectivityService does not appear to clear the
+        // nascent timer if the first request satisfied by the network was filed before the network
+        // connected.
+        // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
+        mWiFiNetworkAgent.connectWithoutInternet();
+        waitForIdle();
+        mCm.requestNetwork(request, callback);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+        // Set teardown delay and make sure CS has processed it.
+        mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMs(300);
+        waitForIdle();
+
+        // Post the duringTeardown lambda to the handler so it fires while teardown is in progress.
+        // The delay must be long enough it will run after the unregisterNetworkCallback has torn
+        // down the network and started the teardown timer, and short enough that the lambda is
+        // scheduled to run before the teardown timer.
+        final Handler h = new Handler(mCsHandlerThread.getLooper());
+        h.postDelayed(duringTeardown, 150);
+
+        // Disconnect the network and check that events happened in the right order.
+        mCm.unregisterNetworkCallback(callback);
+        assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        mCm.unregisterNetworkCallback(callback);
+    }
+
+    @Test
     public void testExplicitlySelected() throws Exception {
         NetworkRequest request = new NetworkRequest.Builder()
                 .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -2898,10 +3044,11 @@
         // Verify NOT_RESTRICTED is set appropriately
         final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
                 .build().networkCapabilities;
-        if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
-                capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
-                capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
-                capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+        if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN
+                || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA
+                || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
+                || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+                || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
                 || capability == NET_CAPABILITY_ENTERPRISE) {
             assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
         } else {
@@ -3011,6 +3158,8 @@
         tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
         tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
         tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
+        tryNetworkFactoryRequests(NET_CAPABILITY_VSIM);
+        tryNetworkFactoryRequests(NET_CAPABILITY_BIP);
         // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
     }
 
@@ -3439,8 +3588,7 @@
 
     @Test
     public void testCaptivePortalApi() throws Exception {
-        mServiceContext.setPermission(
-                android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3474,8 +3622,7 @@
     private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
         // Grant NETWORK_SETTINGS permission to be able to receive LinkProperties change callbacks
         // with sensitive (captive portal) data
-        mServiceContext.setPermission(
-                android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3909,8 +4056,7 @@
     @Test
     public void testRegisterDefaultNetworkCallback() throws Exception {
         // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -4069,8 +4215,7 @@
                 () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler));
         callback.assertNoCallback();
 
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
         mCm.registerSystemDefaultNetworkCallback(callback, handler);
         callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         mCm.unregisterNetworkCallback(callback);
@@ -5391,10 +5536,11 @@
     }
 
     @Test
-    public void testNetworkCallbackMaximum() {
+    public void testNetworkCallbackMaximum() throws Exception {
         final int MAX_REQUESTS = 100;
         final int CALLBACKS = 89;
         final int INTENTS = 11;
+        final int SYSTEM_ONLY_MAX_REQUESTS = 250;
         assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
 
         NetworkRequest networkRequest = new NetworkRequest.Builder().build();
@@ -5443,6 +5589,33 @@
                                 new Intent("d"), FLAG_IMMUTABLE))
         );
 
+        // The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
+        final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+            ArrayList<NetworkCallback> systemRegistered = new ArrayList<>();
+            for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) {
+                NetworkCallback cb = new NetworkCallback();
+                if (i % 2 == 0) {
+                    mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, cb, handler);
+                } else {
+                    mCm.registerNetworkCallback(networkRequest, cb);
+                }
+                systemRegistered.add(cb);
+            }
+            waitForIdle();
+
+            assertThrows(TooManyRequestsException.class, () ->
+                    mCm.registerDefaultNetworkCallbackAsUid(1001042, new NetworkCallback(),
+                            handler));
+            assertThrows(TooManyRequestsException.class, () ->
+                    mCm.registerNetworkCallback(networkRequest, new NetworkCallback()));
+
+            for (NetworkCallback callback : systemRegistered) {
+                mCm.unregisterNetworkCallback(callback);
+            }
+            waitForIdle();  // Wait for requests to be unregistered before giving up the permission.
+        });
+
         for (Object o : registered) {
             if (o instanceof NetworkCallback) {
                 mCm.unregisterNetworkCallback((NetworkCallback)o);
@@ -5469,6 +5642,30 @@
         waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.registerDefaultNetworkCallback(networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        waitForIdle();
+
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.registerDefaultNetworkCallback(networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        waitForIdle();
+
+        withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+            for (int i = 0; i < MAX_REQUESTS; i++) {
+                NetworkCallback networkCallback = new NetworkCallback();
+                mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, networkCallback,
+                        new Handler(ConnectivityThread.getInstanceLooper()));
+                mCm.unregisterNetworkCallback(networkCallback);
+            }
+        });
+        waitForIdle();
+
+        for (int i = 0; i < MAX_REQUESTS; i++) {
             final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                     mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
             mCm.requestNetwork(networkRequest, pendingIntent);
@@ -6461,8 +6658,7 @@
     @Test
     public void testVpnNetworkActive() throws Exception {
         // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final int uid = Process.myUid();
 
@@ -6954,8 +7150,7 @@
     @Test
     public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
         // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final NetworkRequest request = new NetworkRequest.Builder()
                 .removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7041,8 +7236,7 @@
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
         // Necessary to see the UID ranges in NetworkCapabilities.
-        mServiceContext.setPermission(
-                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final NetworkRequest request = new NetworkRequest.Builder()
                 .removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7277,6 +7471,20 @@
         mMockVpn.disconnect();
     }
 
+    private class DetailedBlockedStatusCallback extends TestNetworkCallback {
+        public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
+            super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
+        }
+        public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
+            // This doesn't work:
+            // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
+            super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
+        }
+        public void onBlockedStatusChanged(Network network, int blockedReasons) {
+            getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
+        }
+    }
+
     @Test
     public void testNetworkBlockedStatus() throws Exception {
         final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -7284,11 +7492,16 @@
                 .addTransportType(TRANSPORT_CELLULAR)
                 .build();
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+        final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
+        mCm.registerNetworkCallback(cellRequest, detailedCallback);
+
         mockUidNetworkingBlocked();
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
+                BLOCKED_REASON_NONE);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7296,17 +7509,23 @@
 
         setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+                BLOCKED_REASON_BATTERY_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertExtraInfoFromCmBlocked(mCellNetworkAgent);
 
-        // ConnectivityService should cache it not to invoke the callback again.
+        // If blocked state does not change but blocked reason does, the boolean callback is called.
+        // TODO: investigate de-duplicating.
         setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
-        cellNetworkCallback.assertNoCallback();
+        cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+                BLOCKED_METERED_REASON_USER_RESTRICTED);
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7314,6 +7533,8 @@
 
         setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+                BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7323,6 +7544,8 @@
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7332,6 +7555,10 @@
         cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
                 mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
+                mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+                BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7339,6 +7566,7 @@
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7346,10 +7574,13 @@
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.assertNoCallback();
+        detailedCallback.assertNoCallback();
 
         // Restrict background data. Networking is not blocked because the network is unmetered.
         setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+                BLOCKED_METERED_REASON_DATA_SAVER);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7359,12 +7590,14 @@
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+        detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellNetworkAgent);
 
         setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.assertNoCallback();
+        detailedCallback.assertNoCallback();
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7491,8 +7724,7 @@
                 Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
-        mServiceContext.setPermission(
-                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final TestNetworkCallback callback = new TestNetworkCallback();
         final NetworkRequest request = new NetworkRequest.Builder()
@@ -7728,8 +7960,7 @@
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
         // For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
-        mServiceContext.setPermission(
-                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
         final TestNetworkCallback callback = new TestNetworkCallback();
@@ -7918,12 +8149,12 @@
         assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
 
         b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+        b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         b1.expectBroadcast();
         callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
-        b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
         mMockVpn.expectStopVpnRunnerPrivileged();
         callback.expectCallback(CallbackEntry.LOST, mMockVpn);
         b2.expectBroadcast();
@@ -8859,8 +9090,7 @@
     private void denyAllLocationPrivilegedPermissions() {
         mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
                 PERMISSION_DENIED);
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
-                PERMISSION_DENIED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
         mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
                 PERMISSION_DENIED);
         mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
@@ -8927,7 +9157,7 @@
 
         final int expectedOwnerUidWithoutIncludeFlag =
                 shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
-                        ? Process.myUid() : INVALID_UID;
+                        ? myUid : INVALID_UID;
         assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
                 myUid, myUid, false /* includeLocationSensitiveInfo */));
 
@@ -8946,22 +9176,26 @@
 
     }
 
+    private void verifyOwnerUidAndTransportInfoNetCapsPermissionPreS() {
+        verifyOwnerUidAndTransportInfoNetCapsPermission(
+                // Ensure that owner uid is included even if the request asks to remove it (which is
+                // the default) since the app has necessary permissions and targetSdk < S.
+                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                // Ensure that location info is removed if the request asks to remove it even if the
+                // app has necessary permissions.
+                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+                true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+        );
+    }
+
     @Test
-    public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
+    public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQPreS()
             throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        verifyOwnerUidAndTransportInfoNetCapsPermission(
-                // Ensure that we include owner uid even if the request asks to remove it since the
-                // app has necessary permissions and targetSdk < S.
-                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                // Ensure that we remove location info if the request asks to remove it even if the
-                // app has necessary permissions.
-                true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
-        );
+        verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
     }
 
     @Test
@@ -8970,16 +9204,7 @@
         setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        verifyOwnerUidAndTransportInfoNetCapsPermission(
-                // Ensure that we include owner uid even if the request asks to remove it since the
-                // app has necessary permissions and targetSdk < S.
-                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                // Ensure that we remove location info if the request asks to remove it even if the
-                // app has necessary permissions.
-                true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
-        );
+        verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
     }
 
     @Test
@@ -8990,13 +9215,13 @@
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
         verifyOwnerUidAndTransportInfoNetCapsPermission(
-                // Ensure that we owner UID if the request asks us to remove it even if the app
-                // has necessary permissions since targetSdk >= S.
+                // Ensure that the owner UID is removed if the request asks us to remove it even
+                // if the app has necessary permissions since targetSdk >= S.
                 false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
                 true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                // Ensure that we remove location info if the request asks to remove it even if the
+                // Ensure that location info is removed if the request asks to remove it even if the
                 // app has necessary permissions.
+                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
                 true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
         );
     }
@@ -9007,15 +9232,15 @@
         setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
 
+        verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
+    }
+
+    private void verifyOwnerUidAndTransportInfoNetCapsNotIncluded() {
         verifyOwnerUidAndTransportInfoNetCapsPermission(
-                // Ensure that we owner UID if the request asks us to remove it even if the app
-                // has necessary permissions since targetSdk >= S.
-                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
                 false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                // Ensure that we remove location info if the request asks to remove it even if the
-                // app has necessary permissions.
-                true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+                false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
         );
     }
 
@@ -9025,12 +9250,7 @@
         setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        verifyOwnerUidAndTransportInfoNetCapsPermission(
-                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
-        );
+        verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
     }
 
     @Test
@@ -9052,26 +9272,17 @@
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
 
-        verifyOwnerUidAndTransportInfoNetCapsPermission(
-                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
-        );
+        verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
     }
 
     @Test
-    public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
+    public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterS()
             throws Exception {
         // Test that not having fine location permission leads to sanitization.
-        setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+        setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION);
 
-        verifyOwnerUidAndTransportInfoNetCapsPermission(
-                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
-                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
-                false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
-                false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
-        );
+        verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
     }
 
     @Test
@@ -9116,7 +9327,7 @@
     @Test
     public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
             throws Exception {
-        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
 
         final TransportInfo transportInfo = mock(TransportInfo.class);
         when(transportInfo.getApplicableRedactions())
@@ -10039,6 +10250,12 @@
                 .thenReturn(applicationInfo);
     }
 
+    private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+            throws Exception {
+        when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+                .thenThrow(new PackageManager.NameNotFoundException(packageName));
+    }
+
     private void mockHasSystemFeature(@NonNull final String featureName,
             @NonNull final boolean hasFeature) {
         when(mPackageManager.hasSystemFeature(eq(featureName)))
@@ -10435,8 +10652,7 @@
 
     private void registerDefaultNetworkCallbacks() {
         // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
-        mServiceContext.setPermission(
-                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
         mSystemDefaultNetworkCallback = new TestNetworkCallback();
         mDefaultNetworkCallback = new TestNetworkCallback();
         mProfileDefaultNetworkCallback = new TestNetworkCallback();
@@ -10446,8 +10662,7 @@
         registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
                 TEST_WORK_PROFILE_APP_UID);
         // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
-        mServiceContext.setPermission(
-                Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+        mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
     }
 
     private void unregisterDefaultNetworkCallbacks() {
@@ -10497,15 +10712,23 @@
             @NonNull final UidRangeParcel[] uidRanges,
             @NonNull final String testPackageName)
             throws Exception {
-        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
         // These tests work off a single UID therefore using 'start' is valid.
         mockGetApplicationInfo(testPackageName, uidRanges[0].start);
 
+        setOemNetworkPreference(networkPrefToSetup, testPackageName);
+    }
+
+    private void setOemNetworkPreference(final int networkPrefToSetup,
+            @NonNull final String... testPackageNames)
+            throws Exception {
+        mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
         // Build OemNetworkPreferences object
-        final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
-                .addNetworkPreference(testPackageName, networkPrefToSetup)
-                .build();
+        final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
+        for (final String packageName : testPackageNames) {
+            builder.addNetworkPreference(packageName, networkPrefToSetup);
+        }
+        final OemNetworkPreferences pref = builder.build();
 
         // Act on ConnectivityService.setOemNetworkPreference()
         final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
@@ -10602,7 +10825,7 @@
         defaultNetworkCallback.assertNoCallback();
 
         final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
-        withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+        withPermission(NETWORK_SETTINGS, () ->
                 mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
                         new Handler(ConnectivityThread.getInstanceLooper())));
 
@@ -10650,7 +10873,7 @@
         defaultNetworkCallback.assertNoCallback();
 
         final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
-        withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+        withPermission(NETWORK_SETTINGS, () ->
                 mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
                         new Handler(ConnectivityThread.getInstanceLooper())));
 
@@ -10692,7 +10915,7 @@
         defaultNetworkCallback.assertNoCallback();
 
         final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
-        withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+        withPermission(NETWORK_SETTINGS, () ->
                 mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
                         new Handler(ConnectivityThread.getInstanceLooper())));
 
@@ -11104,8 +11327,7 @@
         // Arrange PackageManager mocks
         final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
         final UidRangeParcel[] uidRangesSingleUser =
-                toUidRangeStableParcels(
-                        uidRangesForUids(TEST_PACKAGE_UID));
+                toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
         final UidRangeParcel[] uidRangesBothUsers =
                 toUidRangeStableParcels(
                         uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
@@ -11152,6 +11374,84 @@
                 false /* shouldDestroyNetwork */);
     }
 
+    @Test
+    public void testMultilayerForPackageChangesEvaluatesCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OEM_NETWORK_PREFERENCE_OEM_PAID;
+        final String packageScheme = "package:";
+
+        // Arrange PackageManager mocks
+        final String packageToInstall = "package.to.install";
+        final int packageToInstallUid = 81387;
+        final UidRangeParcel[] uidRangesSinglePackage =
+                toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+        mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+        setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
+        grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
+
+        // Verify the starting state. No networks should be connected.
+        verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Test that we correctly add the expected values for installed packages.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                OEM_PREF_ANY_NET_ID, 0 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Set the system to recognize the package to be installed
+        mockGetApplicationInfo(packageToInstall, packageToInstallUid);
+        final UidRangeParcel[] uidRangesAllPackages =
+                toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
+
+        // Send a broadcast indicating a package was installed.
+        final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
+        addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+        processBroadcast(addedIntent);
+
+        // Test the single package is removed and the combined packages are added.
+        verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Set the system to no longer recognize the package to be installed
+        mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+
+        // Send a broadcast indicating a package was removed.
+        final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
+        removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+        processBroadcast(removedIntent);
+
+        // Test the combined packages are removed and the single package is added.
+        verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+
+        // Set the system to change the installed package's uid
+        final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
+        mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
+        final UidRangeParcel[] uidRangesReplacedPackage =
+                toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
+
+        // Send a broadcast indicating a package was replaced.
+        final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
+        replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
+        processBroadcast(replacedIntent);
+
+        // Test the original uid is removed and is replaced with the new uid.
+        verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+                false /* shouldDestroyNetwork */);
+    }
+
     /**
      * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
      * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
@@ -11974,4 +12274,68 @@
                         mCm.setProfileNetworkPreference(testHandle,
                                 PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
     }
+
+    @Test
+    public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
+        mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+        final NetworkCapabilities nc = new NetworkCapabilities();
+        nc.setSubIds(Collections.singleton(Process.myUid()));
+
+        final NetworkCapabilities result =
+                mService.networkCapabilitiesRestrictedForCallerPermissions(
+                        nc, Process.myPid(), Process.myUid());
+        assertTrue(result.getSubIds().isEmpty());
+    }
+
+    @Test
+    public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
+        mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+
+        final Set<Integer> subIds = Collections.singleton(Process.myUid());
+        final NetworkCapabilities nc = new NetworkCapabilities();
+        nc.setSubIds(subIds);
+
+        final NetworkCapabilities result =
+                mService.networkCapabilitiesRestrictedForCallerPermissions(
+                        nc, Process.myPid(), Process.myUid());
+        assertEquals(subIds, result.getSubIds());
+    }
+
+    private NetworkRequest getRequestWithSubIds() {
+        return new NetworkRequest.Builder()
+                .setSubIds(Collections.singleton(Process.myUid()))
+                .build();
+    }
+
+    @Test
+    public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
+        mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+        final NetworkCallback networkCallback1 = new NetworkCallback();
+        final NetworkCallback networkCallback2 = new NetworkCallback();
+
+        mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
+        mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
+        mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
+
+        mCm.unregisterNetworkCallback(networkCallback1);
+        mCm.releaseNetworkRequest(pendingIntent);
+        mCm.unregisterNetworkCallback(networkCallback2);
+    }
+
+    @Test
+    public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
+        mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+
+        final Class<SecurityException> expected = SecurityException.class;
+        assertThrows(
+                expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
+        assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
+        assertThrows(
+                expected,
+                () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 8c5d1d6..8b072c4 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -22,7 +22,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -56,6 +58,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -80,6 +83,12 @@
 
     IpConnectivityMetrics mService;
     NetdEventListenerService mNetdListener;
+    private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+            .build();
+    private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .build();
 
     @Before
     public void setUp() {
@@ -263,14 +272,6 @@
         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
 
-        NetworkCapabilities ncWifi = new NetworkCapabilities();
-        NetworkCapabilities ncCell = new NetworkCapabilities();
-        ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-        ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
-        when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
-        when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
         ApfStats apfStats = new ApfStats.Builder()
                 .setDurationMs(45000)
                 .setReceivedRas(10)
@@ -584,11 +585,21 @@
         return buffer.toString();
     }
 
-    void connectEvent(int netid, int error, int latencyMs, String ipAddr) throws Exception {
-        mNetdListener.onConnectEvent(netid, error, latencyMs, ipAddr, 80, 1);
+    private void setCapabilities(int netId) {
+        final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+                ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+        verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+        networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+                netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+    }
+
+    void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
+        setCapabilities(netId);
+        mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
     }
 
     void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+        setCapabilities(netId);
         mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 8ccea1a..50aaaee 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -23,8 +23,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -42,6 +43,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
@@ -61,18 +63,16 @@
 
     NetdEventListenerService mService;
     ConnectivityManager mCm;
+    private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+            .build();
+    private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .build();
 
     @Before
     public void setUp() {
-        NetworkCapabilities ncWifi = new NetworkCapabilities();
-        NetworkCapabilities ncCell = new NetworkCapabilities();
-        ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-        ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
         mCm = mock(ConnectivityManager.class);
-        when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
-        when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
         mService = new NetdEventListenerService(mCm);
     }
 
@@ -470,7 +470,16 @@
         assertEquals(want, got);
     }
 
+    private void setCapabilities(int netId) {
+        final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+                ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+        verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+        networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+                netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+    }
+
     Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
+        setCapabilities(netId);
         return new Thread(() -> {
             try {
                 mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
@@ -481,6 +490,7 @@
     }
 
     void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+        setCapabilities(netId);
         mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
     }
 
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 9334e2c..eeeb4fb 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -89,6 +89,7 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.net.UnderlyingNetworkInfo;
+import android.net.TelephonyNetworkSpecifier;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -1280,6 +1281,77 @@
     }
 
     @Test
+    public void testDualVilteProviderStats() throws Exception {
+        // Pretend that network comes online.
+        expectDefaultSettings();
+        final int subId1 = 1;
+        final int subId2 = 2;
+        final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+                buildImsState(IMSI_1, subId1, TEST_IFACE),
+                buildImsState(IMSI_2, subId2, TEST_IFACE2)};
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+
+        // Register custom provider and retrieve callback.
+        final TestableNetworkStatsProviderBinder provider =
+                new TestableNetworkStatsProviderBinder();
+        final INetworkStatsProviderCallback cb =
+                mService.registerNetworkStatsProvider("TEST", provider);
+        assertNotNull(cb);
+
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
+
+        // Verifies that one requestStatsUpdate will be called during iface update.
+        provider.expectOnRequestStatsUpdate(0 /* unused */);
+
+        // Create some initial traffic and report to the service.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        final String vtIface1 = NetworkStats.IFACE_VT + subId1;
+        final String vtIface2 = NetworkStats.IFACE_VT + subId2;
+        final NetworkStats expectedStats = new NetworkStats(0L, 1)
+                .addEntry(new NetworkStats.Entry(vtIface1, UID_RED, SET_DEFAULT,
+                        TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+                        128L, 2L, 128L, 2L, 1L))
+                .addEntry(new NetworkStats.Entry(vtIface2, UID_RED, SET_DEFAULT,
+                        TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+                        64L, 1L, 64L, 1L, 1L));
+        cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
+
+        // Make another empty mutable stats object. This is necessary since the new NetworkStats
+        // object will be used to compare with the old one in NetworkStatsRecoder, two of them
+        // cannot be the same object.
+        expectNetworkStatsUidDetail(buildEmptyStats());
+
+        forcePollAndWaitForIdle();
+
+        // Verifies that one requestStatsUpdate and setAlert will be called during polling.
+        provider.expectOnRequestStatsUpdate(0 /* unused */);
+        provider.expectOnSetAlert(MB_IN_BYTES);
+
+        // Verifies that service recorded history, does not verify uid tag part.
+        assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 1);
+
+        // Verifies that onStatsUpdated updates the stats accordingly.
+        NetworkStats stats = mSession.getSummaryForAllUid(
+                sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+        assertEquals(1, stats.size());
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+                DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
+
+        stats = mSession.getSummaryForAllUid(
+                sTemplateImsi2, Long.MIN_VALUE, Long.MAX_VALUE, true);
+        assertEquals(1, stats.size());
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+                DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
+
+        // Verifies that unregister the callback will remove the provider from service.
+        cb.unregister();
+        forcePollAndWaitForIdle();
+        provider.assertNoCallback();
+    }
+
+    @Test
     public void testStatsProviderSetAlert() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
@@ -1616,6 +1688,20 @@
                 TYPE_MOBILE);
     }
 
+    private static NetworkStateSnapshot buildImsState(
+            String subscriberId, int subId, String ifaceName) {
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(ifaceName);
+        final NetworkCapabilities capabilities = new NetworkCapabilities();
+        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true);
+        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true);
+        capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+        return new NetworkStateSnapshot(
+                MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
+    }
+
     private long getElapsedRealtime() {
         return mElapsedRealtime;
     }
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
index c1ef350..7ac51b7 100644
--- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -79,6 +79,18 @@
     }
 
     @Test
+    public void testBuilderRequiresUniqueGatewayConnectionNames() {
+        final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.buildTestConfig();
+        try {
+            new VcnConfig.Builder(mContext)
+                    .addGatewayConnectionConfig(config)
+                    .addGatewayConnectionConfig(config);
+            fail("Expected exception due to duplicate gateway connection name");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
     public void testBuilderAndGetters() {
         final VcnConfig config = buildTestConfig(mContext);
 
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 8a0c923..4ee4d61 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.net.NetworkCapabilities;
@@ -61,13 +62,20 @@
     public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG =
             VcnControlPlaneIkeConfigTest.buildTestConfig();
 
+    public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
+    private static int sGatewayConnectionConfigCount = 0;
+
     // Public for use in VcnGatewayConnectionTest
     public static VcnGatewayConnectionConfig buildTestConfig() {
         return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
     }
 
     private static VcnGatewayConnectionConfig.Builder newBuilder() {
-        return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG);
+        // Append a unique identifier to the name prefix to guarantee that all created
+        // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
+        return new VcnGatewayConnectionConfig.Builder(
+                GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
+                CONTROL_PLANE_CONFIG);
     }
 
     // Public for use in VcnGatewayConnectionTest
@@ -87,9 +95,23 @@
     }
 
     @Test
+    public void testBuilderRequiresNonNullGatewayConnectionName() {
+        try {
+            new VcnGatewayConnectionConfig.Builder(
+                            null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG)
+                    .build();
+
+            fail("Expected exception due to invalid gateway connection name");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    @Test
     public void testBuilderRequiresNonNullControlPlaneConfig() {
         try {
-            new VcnGatewayConnectionConfig.Builder(null).build();
+            new VcnGatewayConnectionConfig.Builder(
+                            GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */)
+                    .build();
 
             fail("Expected exception due to invalid control plane config");
         } catch (NullPointerException e) {
@@ -139,6 +161,8 @@
     public void testBuilderAndGetters() {
         final VcnGatewayConnectionConfig config = buildTestConfig();
 
+        assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
+
         int[] exposedCaps = config.getExposedCapabilities();
         Arrays.sort(exposedCaps);
         assertArrayEquals(EXPOSED_CAPS, exposedCaps);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 516c206..8461de6 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -50,9 +50,7 @@
 
 public class VcnManagerTest {
     private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
-    private static final int[] UNDERLYING_NETWORK_CAPABILITIES = {
-        NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET
-    };
+    private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName";
     private static final Executor INLINE_EXECUTOR = Runnable::run;
 
     private IVcnManagementService mMockVcnManagementService;
@@ -207,13 +205,13 @@
         verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
 
         cbBinder.onGatewayConnectionError(
-                UNDERLYING_NETWORK_CAPABILITIES,
+                GATEWAY_CONNECTION_NAME,
                 VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
                 UnknownHostException.class.getName(),
                 "exception_message");
         verify(mMockStatusCallback)
                 .onGatewayConnectionError(
-                        eq(UNDERLYING_NETWORK_CAPABILITIES),
+                        eq(GATEWAY_CONNECTION_NAME),
                         eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
                         any(UnknownHostException.class));
     }
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index f15d420..43e6676 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,9 +16,13 @@
 
 package com.android.server;
 
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
 
@@ -34,8 +38,8 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -45,7 +49,6 @@
 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.annotation.NonNull;
 import android.app.AppOpsManager;
@@ -54,8 +57,10 @@
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkCapabilities.Transport;
+import android.net.NetworkRequest;
 import android.net.TelephonyNetworkSpecifier;
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -63,7 +68,6 @@
 import android.net.vcn.VcnConfigTest;
 import android.net.vcn.VcnManager;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
-import android.net.wifi.WifiInfo;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
@@ -258,6 +262,10 @@
 
         verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
         verify(mSubscriptionTracker).register();
+        verify(mConnMgr)
+                .registerNetworkCallback(
+                        eq(new NetworkRequest.Builder().clearCapabilities().build()),
+                        any(NetworkCallback.class));
     }
 
     @Test
@@ -529,17 +537,6 @@
     }
 
     @Test
-    public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception {
-        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */);
-        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
-        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
-
-        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
-
-        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
-    }
-
-    @Test
     public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
 
@@ -697,36 +694,35 @@
                 hasCarrierPrivileges);
 
         final Vcn vcn = startAndGetVcnInstance(subGrp);
-        doReturn(isVcnActive).when(vcn).isActive();
+        doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
+                .when(vcn)
+                .getStatus();
 
         doReturn(true)
                 .when(mLocationPermissionChecker)
                 .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
     }
 
+    private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
+            int subId, int transport) {
+        final NetworkCapabilities.Builder ncBuilder =
+                new NetworkCapabilities.Builder()
+                        .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+                        .addTransportType(transport);
+        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            ncBuilder.setSubIds(Collections.singleton(subId));
+        }
+
+        return ncBuilder;
+    }
+
     private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
             int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
         setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
 
-        final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder();
-        ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
-        if (transport == TRANSPORT_CELLULAR) {
-            ncBuilder
-                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                    .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID));
-        } else if (transport == TRANSPORT_WIFI) {
-            WifiInfo wifiInfo = mock(WifiInfo.class);
-            when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo);
-            when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
-
-            ncBuilder
-                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                    .setTransportInfo(wifiInfo);
-        } else {
-            throw new IllegalArgumentException("Unknown transport");
-        }
-
-        return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
+        return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+                getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
+                new LinkProperties());
     }
 
     @Test
@@ -788,6 +784,53 @@
                 true /* isRestricted */);
     }
 
+    private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
+        mVcnMgmtSvc.systemReady();
+
+        final ArgumentCaptor<NetworkCallback> captor =
+                ArgumentCaptor.forClass(NetworkCallback.class);
+        verify(mConnMgr)
+                .registerNetworkCallback(
+                        eq(new NetworkRequest.Builder().clearCapabilities().build()),
+                        captor.capture());
+        captor.getValue().onCapabilitiesChanged(new Network(0), caps);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
+            throws Exception {
+        final NetworkCapabilities existingNetworkCaps =
+                getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+                        .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                        .build();
+        setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+        // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
+        // immutable capability
+        final VcnUnderlyingNetworkPolicy policy =
+                mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+                        getNetworkCapabilitiesBuilderForTransport(
+                                        TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+                                .build(),
+                        new LinkProperties());
+        assertTrue(policy.isTeardownRequested());
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
+            throws Exception {
+        final NetworkCapabilities existingNetworkCaps =
+                getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+                        .build();
+        setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+        final VcnUnderlyingNetworkPolicy policy =
+                startVcnAndGetPolicyForTransport(
+                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+        assertTrue(policy.isTeardownRequested());
+    }
+
     @Test
     public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
@@ -848,7 +891,9 @@
     }
 
     private void triggerVcnSafeMode(
-            @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
+            @NonNull ParcelUuid subGroup,
+            @NonNull TelephonySubscriptionSnapshot snapshot,
+            boolean isInSafeMode)
             throws Exception {
         verify(mMockDeps)
                 .newVcn(
@@ -859,22 +904,32 @@
                         mVcnCallbackCaptor.capture());
 
         VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
-        vcnCallback.onEnteredSafeMode();
+        vcnCallback.onSafeModeStatusChanged(isInSafeMode);
     }
 
-    @Test
-    public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+    private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
+            throws Exception {
         TelephonySubscriptionSnapshot snapshot =
                 triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
 
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
-        triggerVcnSafeMode(TEST_UUID_1, snapshot);
+        triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
 
         verify(mMockPolicyListener).onPolicyChanged();
     }
 
-    private void triggerVcnStatusCallbackOnEnteredSafeMode(
+    @Test
+    public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+        verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
+    }
+
+    @Test
+    public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
+        verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
+    }
+
+    private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
             @NonNull ParcelUuid subGroup,
             @NonNull String pkgName,
             int uid,
@@ -897,12 +952,13 @@
 
         mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
 
-        triggerVcnSafeMode(subGroup, snapshot);
+        triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
     }
 
     @Test
-    public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
-        triggerVcnStatusCallbackOnEnteredSafeMode(
+    public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
+            throws Exception {
+        triggerVcnStatusCallbackOnSafeModeStatusChanged(
                 TEST_UUID_1,
                 TEST_PACKAGE_NAME,
                 TEST_UID,
@@ -913,8 +969,9 @@
     }
 
     @Test
-    public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
-        triggerVcnStatusCallbackOnEnteredSafeMode(
+    public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
+            throws Exception {
+        triggerVcnStatusCallbackOnSafeModeStatusChanged(
                 TEST_UUID_1,
                 TEST_PACKAGE_NAME,
                 TEST_UID,
@@ -926,8 +983,9 @@
     }
 
     @Test
-    public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
-        triggerVcnStatusCallbackOnEnteredSafeMode(
+    public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission()
+            throws Exception {
+        triggerVcnStatusCallbackOnSafeModeStatusChanged(
                 TEST_UUID_1,
                 TEST_PACKAGE_NAME,
                 TEST_UID,
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 1ef1a61..b592000 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -146,27 +146,15 @@
 
     @Test
     public void testNetworkCallbacksRegisteredOnStartup() {
-        // verify NetworkCallbacks registered when instantiated
-        verify(mConnectivityManager)
-                .requestBackgroundNetwork(
-                        eq(getWifiRequest()),
-                        any(),
-                        any(NetworkBringupCallback.class));
-        verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
-
-        verify(mConnectivityManager)
-                .requestBackgroundNetwork(
-                        eq(getRouteSelectionRequest()),
-                        any(),
-                        any(RouteSelectionCallback.class));
+        verifyNetworkRequestsRegistered(INITIAL_SUB_IDS);
     }
 
-    private void verifyBackgroundCellRequests(
-            TelephonySubscriptionSnapshot snapshot,
-            ParcelUuid subGroup,
-            Set<Integer> expectedSubIds) {
-        verify(snapshot).getAllSubIdsInGroup(eq(subGroup));
-
+    private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) {
+        verify(mConnectivityManager)
+                .requestBackgroundNetwork(
+                        eq(getWifiRequest(expectedSubIds)),
+                        any(),
+                        any(NetworkBringupCallback.class));
         for (final int subId : expectedSubIds) {
             verify(mConnectivityManager)
                     .requestBackgroundNetwork(
@@ -174,12 +162,18 @@
                             any(),
                             any(NetworkBringupCallback.class));
         }
+
+        verify(mConnectivityManager)
+                .requestBackgroundNetwork(
+                        eq(getRouteSelectionRequest(expectedSubIds)),
+                        any(),
+                        any(RouteSelectionCallback.class));
     }
 
     @Test
     public void testUpdateSubscriptionSnapshot() {
         // Verify initial cell background requests filed
-        verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
+        verifyNetworkRequestsRegistered(INITIAL_SUB_IDS);
 
         TelephonySubscriptionSnapshot subscriptionUpdate =
                 mock(TelephonySubscriptionSnapshot.class);
@@ -187,30 +181,32 @@
 
         mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
 
-        // verify that initially-filed bringup requests are unregistered
-        verify(mConnectivityManager, times(INITIAL_SUB_IDS.size()))
+        // verify that initially-filed bringup requests are unregistered (cell + wifi)
+        verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1))
                 .unregisterNetworkCallback(any(NetworkBringupCallback.class));
-        verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS);
+        verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class));
+        verifyNetworkRequestsRegistered(UPDATED_SUB_IDS);
     }
 
-    private NetworkRequest getWifiRequest() {
-        return getExpectedRequestBase(true)
+    private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
+        return getExpectedRequestBase()
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setSubIds(netCapsSubIds)
                 .build();
     }
 
     private NetworkRequest getCellRequestForSubId(int subId) {
-        return getExpectedRequestBase(false)
+        return getExpectedRequestBase()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
                 .build();
     }
 
-    private NetworkRequest getRouteSelectionRequest() {
-        return getExpectedRequestBase(true).build();
+    private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
+        return getExpectedRequestBase().setSubIds(netCapsSubIds).build();
     }
 
-    private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) {
+    private NetworkRequest.Builder getExpectedRequestBase() {
         final NetworkRequest.Builder builder =
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
@@ -218,10 +214,6 @@
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
 
-        if (requireVcnManaged) {
-            builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-        }
-
         return builder;
     }
 
@@ -274,7 +266,7 @@
             NetworkCapabilities networkCapabilities) {
         verify(mConnectivityManager)
                 .requestBackgroundNetwork(
-                        eq(getRouteSelectionRequest()),
+                        eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
                         any(),
                         mRouteSelectionCallbackCaptor.capture());
 
@@ -328,7 +320,7 @@
     public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
         RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
 
-        cb.onNetworkSuspended(mNetwork);
+        cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
 
         UnderlyingNetworkRecord expectedRecord =
                 new UnderlyingNetworkRecord(
@@ -336,7 +328,11 @@
                         SUSPENDED_NETWORK_CAPABILITIES,
                         INITIAL_LINK_PROPERTIES,
                         false /* isBlocked */);
-        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+        // change.
+        cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
     }
 
     @Test
@@ -344,7 +340,7 @@
         RouteSelectionCallback cb =
                 verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
 
-        cb.onNetworkResumed(mNetwork);
+        cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
 
         UnderlyingNetworkRecord expectedRecord =
                 new UnderlyingNetworkRecord(
@@ -352,7 +348,11 @@
                         INITIAL_NETWORK_CAPABILITIES,
                         INITIAL_LINK_PROPERTIES,
                         false /* isBlocked */);
-        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+        // change.
+        cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index ca6448c..34c0018 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -32,6 +32,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -40,6 +41,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
@@ -58,19 +61,29 @@
 import org.mockito.ArgumentCaptor;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
 
 /** Tests for VcnGatewayConnection.ConnectedState */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
     private VcnIkeSession mIkeSession;
+    private NetworkAgent mNetworkAgent;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
 
+        mNetworkAgent = mock(NetworkAgent.class);
+        doReturn(mNetworkAgent)
+                .when(mDeps)
+                .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
+
         mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
 
         mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
@@ -159,21 +172,44 @@
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
     }
 
-    @Test
-    public void testChildOpenedRegistersNetwork() throws Exception {
-        // Verify scheduled but not canceled when entering ConnectedState
-        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+    private void triggerChildOpened() {
+        triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR);
+    }
 
+    private void triggerChildOpened(List<LinkAddress> internalAddresses, InetAddress dnsAddress) {
         final VcnChildSessionConfiguration mMockChildSessionConfig =
                 mock(VcnChildSessionConfiguration.class);
-        doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
-                .when(mMockChildSessionConfig)
-                .getInternalAddresses();
-        doReturn(Collections.singletonList(TEST_DNS_ADDR))
+        doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses();
+        doReturn(Collections.singletonList(dnsAddress))
                 .when(mMockChildSessionConfig)
                 .getInternalDnsServers();
 
         getChildSessionCallback().onOpened(mMockChildSessionConfig);
+    }
+
+    private void triggerValidation(int status) {
+        final ArgumentCaptor<Consumer<Integer>> validationCallbackCaptor =
+                ArgumentCaptor.forClass(Consumer.class);
+        verify(mDeps)
+                .newNetworkAgent(
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        anyInt(),
+                        any(),
+                        any(),
+                        any(),
+                        validationCallbackCaptor.capture());
+
+        validationCallbackCaptor.getValue().accept(status);
+    }
+
+    @Test
+    public void testChildOpenedRegistersNetwork() throws Exception {
+        // Verify scheduled but not canceled when entering ConnectedState
+        verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+        triggerChildOpened();
         mTestLooper.dispatchAll();
 
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
@@ -182,15 +218,20 @@
                 ArgumentCaptor.forClass(LinkProperties.class);
         final ArgumentCaptor<NetworkCapabilities> ncCaptor =
                 ArgumentCaptor.forClass(NetworkCapabilities.class);
-        verify(mConnMgr)
-                .registerNetworkAgent(
-                        any(),
-                        any(),
-                        lpCaptor.capture(),
+        verify(mDeps)
+                .newNetworkAgent(
+                        eq(mVcnContext),
+                        any(String.class),
                         ncCaptor.capture(),
+                        lpCaptor.capture(),
+                        anyInt(),
+                        argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
                         any(),
                         any(),
-                        anyInt());
+                        any());
+        verify(mNetworkAgent).register();
+        verify(mNetworkAgent).markConnected();
+
         verify(mIpSecSvc)
                 .addAddressToTunnelInterface(
                         eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
@@ -208,9 +249,78 @@
 
         // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
         // canceled
-        mGatewayConnection.mNetworkAgent.onValidationStatus(
-                NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
+        triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
         verify(mSafeModeTimeoutAlarm).cancel();
+        assertFalse(mGatewayConnection.isInSafeMode());
+    }
+
+    @Test
+    public void testInternalAndDnsAddressesChanged() throws Exception {
+        final List<LinkAddress> startingInternalAddrs =
+                Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2});
+        triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR);
+        mTestLooper.dispatchAll();
+
+        for (LinkAddress addr : startingInternalAddrs) {
+            verify(mIpSecSvc)
+                    .addAddressToTunnelInterface(
+                            eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+        }
+
+        verify(mDeps)
+                .newNetworkAgent(
+                        any(),
+                        any(),
+                        any(),
+                        argThat(
+                                lp ->
+                                        startingInternalAddrs.equals(lp.getLinkAddresses())
+                                                && Collections.singletonList(TEST_DNS_ADDR)
+                                                        .equals(lp.getDnsServers())),
+                        anyInt(),
+                        any(),
+                        any(),
+                        any(),
+                        any());
+
+        // Trigger another connection event, and verify that the addresses change
+        final List<LinkAddress> newInternalAddrs =
+                Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3});
+        triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2);
+        mTestLooper.dispatchAll();
+
+        // Verify addresses on tunnel network added/removed
+        for (LinkAddress addr : newInternalAddrs) {
+            verify(mIpSecSvc)
+                    .addAddressToTunnelInterface(
+                            eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+        }
+        verify(mIpSecSvc)
+                .removeAddressFromTunnelInterface(
+                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+        // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
+        // is mockable
+
+        // Verify that IpSecTunnelInterface only created once
+        verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+        verifyNoMoreInteractions(mIpSecSvc);
+    }
+
+    @Test
+    public void testSuccessfulConnectionExitsSafeMode() throws Exception {
+        verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+                mGatewayConnection.mConnectedState);
+
+        assertTrue(mGatewayConnection.isInSafeMode());
+        assertFalse(mGatewayConnection.isQuitting());
+
+        triggerChildOpened();
+        mTestLooper.dispatchAll();
+
+        triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+
+        assertFalse(mGatewayConnection.isInSafeMode());
     }
 
     @Test
@@ -241,7 +351,7 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getExposedCapabilities()),
+                        eq(mConfig.getGatewayConnectionName()),
                         eq(VCN_ERROR_CODE_INTERNAL_ERROR),
                         any(),
                         any());
@@ -275,7 +385,10 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any());
+                        eq(mConfig.getGatewayConnectionName()),
+                        eq(expectedErrorType),
+                        any(),
+                        any());
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 7afa449..bfe8c73 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -118,8 +118,9 @@
     }
 
     @Test
-    public void testSafeModeTimeoutNotifiesCallback() {
-        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
+    public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+        verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+                mGatewayConnection.mConnectingState);
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 99feffd..9da8b45 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -86,8 +86,9 @@
     }
 
     @Test
-    public void testSafeModeTimeoutNotifiesCallback() {
-        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
+    public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+        verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+                mGatewayConnection.mDisconnectingState);
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 85a0277..6dbf7d5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -96,8 +96,9 @@
     }
 
     @Test
-    public void testSafeModeTimeoutNotifiesCallback() {
-        verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
+    public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+        verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+                mGatewayConnection.mRetryTimeoutState);
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index a660735..c5ed8f6 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -21,6 +21,8 @@
 import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
@@ -42,6 +44,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.IkeSessionCallback;
@@ -71,8 +74,14 @@
     protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
     protected static final InetAddress TEST_DNS_ADDR =
             InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+    protected static final InetAddress TEST_DNS_ADDR_2 =
+            InetAddresses.parseNumericAddress("2001:DB8:0:2::");
     protected static final LinkAddress TEST_INTERNAL_ADDR =
-            new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+            new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64);
+    protected static final LinkAddress TEST_INTERNAL_ADDR_2 =
+            new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64);
+    protected static final LinkAddress TEST_INTERNAL_ADDR_3 =
+            new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64);
 
     protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
     protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
@@ -267,7 +276,12 @@
                 expectCanceled);
     }
 
-    protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
+    protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+            @NonNull State expectedState) {
+        // Set a NetworkAgent, and expect it to be unregistered and cleared
+        final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
+        mGatewayConnection.setNetworkAgent(mockNetworkAgent);
+
         // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
         // state)
         final Runnable delayedEvent =
@@ -275,7 +289,11 @@
         delayedEvent.run();
         mTestLooper.dispatchAll();
 
-        verify(mGatewayStatusCallback).onEnteredSafeMode();
+        verify(mGatewayStatusCallback).onSafeModeStatusChanged();
         assertEquals(expectedState, mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isInSafeMode());
+
+        verify(mockNetworkAgent).unregister();
+        assertNull(mGatewayConnection.getNetworkAgent());
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index c853fc5..90eb75e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -19,12 +19,13 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -51,7 +52,8 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
@@ -132,6 +134,7 @@
     private void startVcnGatewayWithCapabilities(
             NetworkRequestListener requestListener, int... netCapabilities) {
         final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+        requestBuilder.addTransportType(TRANSPORT_CELLULAR);
         for (final int netCapability : netCapabilities) {
             requestBuilder.addCapability(netCapability);
         }
@@ -140,7 +143,7 @@
         mTestLooper.dispatchAll();
     }
 
-    private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) {
+    private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
 
@@ -150,25 +153,24 @@
         final TelephonySubscriptionSnapshot updatedSnapshot =
                 mock(TelephonySubscriptionSnapshot.class);
 
-        mVcn.setIsActive(isActive);
+        mVcn.setStatus(status);
 
         mVcn.updateSubscriptionSnapshot(updatedSnapshot);
         mTestLooper.dispatchAll();
 
         for (final VcnGatewayConnection gateway : gatewayConnections) {
-            verify(gateway, isActive ? times(1) : never())
-                    .updateSubscriptionSnapshot(eq(updatedSnapshot));
+            verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
         }
     }
 
     @Test
     public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
-        verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */);
+        verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
     }
 
     @Test
-    public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() {
-        verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */);
+    public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() {
+        verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE);
     }
 
     private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
@@ -198,32 +200,53 @@
 
     private void verifySafeMode(
             NetworkRequestListener requestListener,
-            Set<VcnGatewayConnection> expectedGatewaysTornDown) {
-        assertFalse(mVcn.isActive());
-        for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
-            verify(gatewayConnection).teardownAsynchronously();
+            Set<VcnGatewayConnection> activeGateways,
+            boolean expectInSafeMode) {
+        for (VcnGatewayConnection gatewayConnection : activeGateways) {
+            verify(gatewayConnection, never()).teardownAsynchronously();
         }
-        verify(mVcnNetworkProvider).unregisterListener(requestListener);
-        verify(mVcnCallback).onEnteredSafeMode();
+
+        assertEquals(
+                expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE,
+                mVcn.getStatus());
+        verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode);
     }
 
     @Test
-    public void testGatewayEnteringSafeModeNotifiesVcn() {
+    public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         final Set<VcnGatewayConnection> gatewayConnections =
                 startGatewaysAndGetGatewayConnections(requestListener);
 
-        // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
-        // all Gateways
+        // Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway
+        // entering Safemode should trigger safe mode
         final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
-        statusCallback.onEnteredSafeMode();
+        final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next();
+
+        doReturn(true).when(gatewayConnection).isInSafeMode();
+        statusCallback.onSafeModeStatusChanged();
         mTestLooper.dispatchAll();
 
-        verifySafeMode(requestListener, gatewayConnections);
+        verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */);
+
+        // Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode
+        doReturn(false).when(gatewayConnection).isInSafeMode();
+        statusCallback.onSafeModeStatusChanged();
+        mTestLooper.dispatchAll();
+
+        verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */);
+
+        // Re-trigger, verify safe mode callback does not get fired again for identical state
+        statusCallback.onSafeModeStatusChanged();
+        mTestLooper.dispatchAll();
+
+        // Expect only once still; from above.
+        verify(mVcnCallback).onSafeModeStatusChanged(false);
     }
 
-    @Test
-    public void testGatewayQuit() {
+    private void verifyGatewayQuit(int status) {
+        mVcn.setStatus(status);
+
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         final Set<VcnGatewayConnection> gatewayConnections =
                 new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
@@ -236,7 +259,7 @@
         assertEquals(1, mVcn.getVcnGatewayConnections().size());
         verify(mVcnNetworkProvider).resendAllRequests(requestListener);
 
-        // Verify that the VcnGatewayConnection is restarted
+        // Verify that the VcnGatewayConnection is restarted if a request exists for it
         triggerVcnRequestListeners(requestListener);
         mTestLooper.dispatchAll();
         assertEquals(2, mVcn.getVcnGatewayConnections().size());
@@ -250,21 +273,13 @@
     }
 
     @Test
-    public void testGatewayQuitWhileInactive() {
-        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        final Set<VcnGatewayConnection> gatewayConnections =
-                new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+    public void testGatewayQuitReevaluatesRequests() {
+        verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE);
+    }
 
-        mVcn.teardownAsynchronously();
-        mTestLooper.dispatchAll();
-
-        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
-        statusCallback.onQuit();
-        mTestLooper.dispatchAll();
-
-        // Verify that the VCN requests the networkRequests be resent
-        assertEquals(1, mVcn.getVcnGatewayConnections().size());
-        verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener);
+    @Test
+    public void testGatewayQuitReevaluatesRequestsInSafeMode() {
+        verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE);
     }
 
     @Test
@@ -274,11 +289,12 @@
         assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
 
         // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
-        // down
-        final VcnGatewayConnectionConfig activeConfig =
-                VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]);
-        final VcnGatewayConnectionConfig removedConfig =
-                VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]);
+        // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
+        // matches.
+        final List<VcnGatewayConnectionConfig> currentConfigs =
+                new ArrayList<>(mVcn.getVcnGatewayConnectionConfigMap().keySet());
+        final VcnGatewayConnectionConfig activeConfig = currentConfigs.get(0);
+        final VcnGatewayConnectionConfig removedConfig = currentConfigs.get(1);
         final VcnConfig updatedConfig =
                 new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
 
@@ -293,49 +309,4 @@
         verify(removedGatewayConnection).teardownAsynchronously();
         verify(mVcnNetworkProvider).resendAllRequests(requestListener);
     }
-
-    @Test
-    public void testUpdateConfigExitsSafeMode() {
-        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        final Set<VcnGatewayConnection> gatewayConnections =
-                new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
-
-        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
-        statusCallback.onEnteredSafeMode();
-        mTestLooper.dispatchAll();
-        verifySafeMode(requestListener, gatewayConnections);
-
-        doAnswer(invocation -> {
-            final NetworkRequestListener listener = invocation.getArgument(0);
-            triggerVcnRequestListeners(listener);
-            return null;
-        }).when(mVcnNetworkProvider).registerListener(eq(requestListener));
-
-        mVcn.updateConfig(mConfig);
-        mTestLooper.dispatchAll();
-
-        // Registered on start, then re-registered with new configs
-        verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
-        assertTrue(mVcn.isActive());
-        for (final int[] caps : TEST_CAPS) {
-            // Expect each gateway connection created only on initial startup
-            verify(mDeps)
-                    .newVcnGatewayConnection(
-                            eq(mVcnContext),
-                            eq(TEST_SUB_GROUP),
-                            eq(mSubscriptionSnapshot),
-                            argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())),
-                            any());
-        }
-    }
-
-    @Test
-    public void testIgnoreNetworkRequestWhileInactive() {
-        mVcn.setIsActive(false /* isActive */);
-
-        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        triggerVcnRequestListeners(requestListener);
-
-        verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
-    }
 }
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 7de7065..a4a315b 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -11,12 +11,6 @@
 
 EMOJI_VS = 0xFE0F
 
-#TODO(179952916): Rename CutiveMono and DancingScript
-CANONICAL_NAME_EXCEPTION_LIST = [
-    'CutiveMono.ttf',
-    'DancingScript-Regular.ttf',
-]
-
 LANG_TO_SCRIPT = {
     'as': 'Beng',
     'be': 'Cyrl',
@@ -664,53 +658,6 @@
             assert_font_supports_none_of_chars(record.font, cjk_punctuation, name)
 
 
-def getPostScriptName(font):
-  ttf = open_font(font)
-  nameTable = ttf['name']
-  for name in nameTable.names:
-    if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409:
-      return str(name)
-
-
-def getSuffix(font):
-  file_path, index = font
-  with open(path.join(_fonts_dir, file_path), 'rb') as f:
-    tag = f.read(4)
-    isCollection = tag == b'ttcf'
-
-  ttf = open_font(font)
-  isType1 = ('CFF ' in ttf or 'CFF2' in ttf)
-
-  if isType1:
-    if isCollection:
-      return '.otc'
-    else:
-      return '.otf'
-  else:
-    if isCollection:
-      return '.ttc'
-    else:
-      return '.ttf'
-
-
-def check_canonical_name():
-  for record in _all_fonts:
-    file_name, index = record.font
-    if file_name in CANONICAL_NAME_EXCEPTION_LIST:
-      continue
-
-    if index and index != 0:
-      continue
-
-    psName = getPostScriptName(record.font)
-    assert psName, 'PostScript must be defined'
-
-    suffix = getSuffix(record.font)
-    canonicalName = '%s%s' % (psName, suffix)
-
-    assert file_name == canonicalName, (
-        '%s is not a canonical name. Must be %s' % (file_name, canonicalName))
-
 def main():
     global _fonts_dir
     target_out = sys.argv[1]
@@ -728,8 +675,6 @@
 
     check_cjk_punctuation()
 
-    check_canonical_name()
-
     check_emoji = sys.argv[2]
     if check_emoji == 'true':
         ucd_path = sys.argv[3]
diff --git a/tools/hiddenapi/OWNERS b/tools/hiddenapi/OWNERS
new file mode 100644
index 0000000..afbeef5
--- /dev/null
+++ b/tools/hiddenapi/OWNERS
@@ -0,0 +1,7 @@
+# compat-team@ for changes to hiddenapi files
+andreionea@google.com
+mathewi@google.com
+satayev@google.com
+
+# soong-team@ as the files these tools protect are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 18c4054..2924e01 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -7,11 +7,9 @@
 # the team email to use in the event of this detecting an entry in a <team> package. Also
 # add <team> to the TEAMS list. 
 LIBCORE_PACKAGES="\
-  android.icu \
   android.system \
   android.test \
   com.android.bouncycastle \
-  com.android.conscrypt \
   com.android.i18n.phonenumbers \
   com.android.okhttp \
   com.sun \
@@ -24,37 +22,54 @@
   org.json \
   org.w3c.dom \
   org.xml.sax \
+  org.xmlpull.v1 \
   sun \
   "
 LIBCORE_EMAIL=libcore-team@android.com
 
+I18N_PACKAGES="\
+  android.icu \
+  "
+
+I18N_EMAIL=$LIBCORE_EMAIL
+
+CONSCRYPT_PACKAGES="\
+  com.android.org.conscrypt \
+  "
+
+CONSCRYPT_EMAIL=$LIBCORE_EMAIL
+
 # List of teams.
-TEAMS=LIBCORE
+TEAMS="LIBCORE I18N CONSCRYPT"
+
+SHA=$1
 
 # Generate the list of packages and convert to a regular expression.
 PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
 RE=$(echo ${PACKAGES} | sed "s/ /|/g")
-git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
-    ENTRIES=$(grep -E "^L(${RE})/" <(git show $1:$file))
+EXIT_CODE=0
+for file in $(git show --name-only --pretty=format: $SHA | grep "config/hiddenapi-.*txt"); do
+    ENTRIES=$(grep -E "^\+L(${RE})/" <(git diff ${SHA}~1 ${SHA} $file) | sed "s|^\+||" || echo)
     if [[ -n "${ENTRIES}" ]]; then
-      echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
+      echo -e "\e[1m\e[31m$file $SHA contains the following entries\e[0m"
       echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"
       echo -e "\e[1m\e[31mthese entries and add annotations instead.\e[0m"
       # Partition the entries by team and provide contact details to aid in fixing the issue.
       for t in ${TEAMS}
       do
         PACKAGES=$(eval echo \${${t}_PACKAGES})
-        RE=$(echo ${PACKAGES} | sed "s/ /|/g")
-        TEAM_ENTRIES=$(grep -E "^L(${RE})/" <(echo "${ENTRIES}"))
+        TEAM_RE=$(echo ${PACKAGES} | sed "s/ /|/g")
+        TEAM_ENTRIES=$(grep -E "^L(${TEAM_RE})/" <(echo "${ENTRIES}") || echo)
         if [[ -n "${TEAM_ENTRIES}" ]]; then
           EMAIL=$(eval echo \${${t}_EMAIL})
-          echo -e "\e[33mContact ${EMAIL} or compat- for help with the following:\e[0m"
-          for i in ${ENTRIES}
+          echo -e "\e[33mContact ${EMAIL} for help with the following:\e[0m"
+          for i in ${TEAM_ENTRIES}
           do
             echo -e "\e[33m  ${i}\e[0m"
           done
         fi
       done
-      exit 1
+      EXIT_CODE=1
     fi
 done
+exit $EXIT_CODE