Merge "Fix FrameworksNetIntegrationTests failure"
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index c0560f6..1a2d5d5 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -26,7 +26,10 @@
     defaults: ["framework-module-defaults"],
 
     // Restrict access to implementation library.
-    impl_library_visibility: ["//frameworks/base/apex/permission:__subpackages__"],
+    impl_library_visibility: [
+        "//frameworks/base/apex/permission:__subpackages__",
+        "//packages/modules/Permission:__subpackages__",
+    ],
 
     srcs: [
         ":framework-permission-sources",
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
index 6e04edf..cc6f201 100644
--- a/apex/permission/service/Android.bp
+++ b/apex/permission/service/Android.bp
@@ -27,6 +27,7 @@
         "//frameworks/base/apex/permission/tests",
         "//frameworks/base/services/tests/mockingservicestests",
         "//frameworks/base/services/tests/servicestests",
+        "//packages/modules/Permission/tests",
     ],
     srcs: [
         ":service-permission-sources",
diff --git a/config/OWNERS b/config/OWNERS
index d59c6f2..001038d 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -4,5 +4,11 @@
 
 per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
 
+# art-team@ manages the boot image profiles
+per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
 # Escalations:
 per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 047761a..b0534a1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12128,6 +12128,8 @@
     field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
     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";
+    field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS = "android.hardware.identity_credential_direct_access";
     field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
     field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
@@ -12214,7 +12216,7 @@
     field @Deprecated public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
-    field public static final int GET_INTENT_FILTERS = 32; // 0x20
+    field @Deprecated public static final int GET_INTENT_FILTERS = 32; // 0x20
     field public static final int GET_META_DATA = 128; // 0x80
     field public static final int GET_PERMISSIONS = 4096; // 0x1000
     field public static final int GET_PROVIDERS = 8; // 0x8
@@ -25084,6 +25086,8 @@
     method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
@@ -25093,6 +25097,12 @@
     field public static final int DIRECTION_OUT = 1; // 0x1
   }
 
+  public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    method public void close();
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+  }
+
   public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
   }
 
@@ -36074,15 +36084,20 @@
   public abstract class IdentityCredential {
     method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair();
     method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException;
+    method @NonNull public byte[] delete(@NonNull byte[]);
     method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
     method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification();
     method @NonNull public abstract int[] getAuthenticationDataUsageCount();
     method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain();
     method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
+    method @NonNull public byte[] proveOwnership(@NonNull byte[]);
     method public abstract void setAllowUsingExhaustedKeys(boolean);
+    method public void setAllowUsingExpiredKeys(boolean);
     method public abstract void setAvailableAuthenticationKeys(int, int);
     method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
-    method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+    method @Deprecated public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+    method public void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull java.time.Instant, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+    method @NonNull public byte[] update(@NonNull android.security.identity.PersonalizationData);
   }
 
   public class IdentityCredentialException extends java.lang.Exception {
@@ -36092,7 +36107,7 @@
 
   public abstract class IdentityCredentialStore {
     method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException;
-    method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
+    method @Deprecated @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
     method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException;
     method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context);
     method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context);
@@ -39581,6 +39596,7 @@
     field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
     field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
     field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+    field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool";
     field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
     field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
     field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9f651e7..ea23709 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -44,6 +44,7 @@
     field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
     field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final String BIND_RESUME_ON_REBOOT_SERVICE = "android.permission.BIND_RESUME_ON_REBOOT_SERVICE";
     field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
     field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
@@ -1410,6 +1411,15 @@
 
 }
 
+package android.apphibernation {
+
+  public final class AppHibernationManager {
+    method public boolean isHibernating(@NonNull String);
+    method public void setHibernating(@NonNull String, boolean);
+  }
+
+}
+
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -1706,6 +1716,7 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+    field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
     field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
@@ -6119,15 +6130,11 @@
   }
 
   public final class IpSecManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-    method public void close();
     method @NonNull public String getInterfaceName();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
   }
 
   public static class IpSecTransform.Builder {
@@ -6414,6 +6421,7 @@
 
   public abstract class QosFilter {
     method @NonNull public abstract android.net.Network getNetwork();
+    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
   }
 
   public final class QosSession implements android.os.Parcelable {
@@ -9062,6 +9070,18 @@
 
 }
 
+package android.service.resumeonreboot {
+
+  public abstract class ResumeOnRebootService extends android.app.Service {
+    ctor public ResumeOnRebootService();
+    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @NonNull public abstract byte[] onUnwrap(@NonNull byte[]) throws java.io.IOException;
+    method @NonNull public abstract byte[] onWrap(@NonNull byte[], long) throws java.io.IOException;
+    field public static final String SERVICE_INTERFACE = "android.service.resumeonreboot.ResumeOnRebootService";
+  }
+
+}
+
 package android.service.settings.suggestions {
 
   public final class Suggestion implements android.os.Parcelable {
@@ -11879,6 +11899,7 @@
     ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
     method public int describeContents();
     method @NonNull public byte[] getContent();
+    method @NonNull public byte[] getEncodedMessage();
     method @NonNull public String getHeaderSection();
     method @NonNull public String getStartLine();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ea9e926..546e72b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1726,7 +1726,6 @@
     method public static java.util.Map<java.lang.String,java.lang.String> getAllFeatureFlags();
     method public static boolean isEnabled(android.content.Context, String);
     method public static void setEnabled(android.content.Context, String, boolean);
-    field public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override.";
     field public static final String FFLAG_PREFIX = "sys.fflag.";
     field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java
index fc93f03..08861d4 100644
--- a/core/java/android/annotation/RequiresFeature.java
+++ b/core/java/android/annotation/RequiresFeature.java
@@ -30,7 +30,6 @@
  * Denotes that the annotated element requires one or more device features. This
  * is used to auto-generate documentation.
  *
- * @see PackageManager#hasSystemFeature(String)
  * @hide
  */
 @Retention(SOURCE)
@@ -38,8 +37,16 @@
 public @interface RequiresFeature {
     /**
      * The name of the device feature that is required.
-     *
-     * @see PackageManager#hasSystemFeature(String)
      */
     String value();
+
+    /**
+     * Defines the name of the method that should be called to check whether the feature is
+     * available, using the same signature format as javadoc. The feature checking method can have
+     * multiple parameters, but the feature name parameter must be of type String and must also be
+     * the first String-type parameter.
+     * <p>
+     * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}.
+     */
+    String enforcement() default("android.content.pm.PackageManager#hasSystemFeature");
 }
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 60bfac5..afa1560 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -50,6 +50,9 @@
 # ResourcesManager
 per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
 
+# VoiceInteraction
+per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
+
 # Wallpaper
 per-file *Wallpaper* = file:/core/java/android/service/wallpaper/OWNERS
 
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
new file mode 100644
index 0000000..8f1934c
--- /dev/null
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -0,0 +1,79 @@
+/*
+ * 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.apphibernation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * This class provides an API surface for system apps to manipulate the app hibernation
+ * state of a package for the user provided in the context.
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.APP_HIBERNATION_SERVICE)
+public final class AppHibernationManager {
+    private static final String TAG = "AppHibernationManager";
+    private final Context mContext;
+    private final IAppHibernationService mIAppHibernationService;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context The current context associated with the user
+     *
+     * @hide
+     */
+    public AppHibernationManager(@NonNull Context context) {
+        mContext = context;
+        mIAppHibernationService = IAppHibernationService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_HIBERNATION_SERVICE));
+    }
+
+    /**
+     * Returns true if the package is hibernating, false otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isHibernating(@NonNull String packageName) {
+        try {
+            return mIAppHibernationService.isHibernating(packageName, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set whether the package is hibernating.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setHibernating(@NonNull String packageName, boolean isHibernating) {
+        try {
+            mIAppHibernationService.setHibernating(packageName, mContext.getUserId(),
+                    isHibernating);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
new file mode 100644
index 0000000..db57ecb
--- /dev/null
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.apphibernation;
+
+/**
+ * Binder interface to communicate with AppHibernationService.
+ * @hide
+ */
+interface IAppHibernationService {
+    boolean isHibernating(String packageName, int userId);
+    void setHibernating(String packageName, int userId, boolean isHibernating);
+}
\ No newline at end of file
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index eecdb84..9c88566 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4539,6 +4539,17 @@
     public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
 
     /**
+     * Use with {@link #getSystemService(String) to retrieve an
+     * {@link android.apphibernation.AppHibernationManager}} for
+     * communicating with the hibernation service.
+     * @hide
+     *
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.app.backup.IBackupManager IBackupManager} for communicating
      * with the backup mechanism.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 00f5fb9..31beb6e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -299,7 +299,10 @@
     /**
      * {@link PackageInfo} flag: return information about the
      * intent filters supported by the activity.
+     *
+     * @deprecated The platform does not support getting {@link IntentFilter}s for the package.
      */
+    @Deprecated
     public static final int GET_INTENT_FILTERS          = 0x00000020;
 
     /**
@@ -2122,6 +2125,35 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
+     * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
+     * at the given feature version.
+     *
+     * <p>Known feature versions include:
+     * <ul>
+     * <li><code>202009</code>: corresponds to the features included in the Identity Credential
+     * API shipped in Android 11.
+     * <li><code>202101</code>: corresponds to the features included in the Identity Credential
+     * API shipped in Android 12.
+     * </ul>
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE =
+            "android.hardware.identity_credential";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
+     * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
+     * with direct access at the given feature version.
+     * See {@link #FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known feature versions.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS =
+            "android.hardware.identity_credential_direct_access";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports one or more methods of
      * reporting current location.
      */
diff --git a/core/java/android/graphics/fonts/OWNERS b/core/java/android/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/android/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d83715c..b6ae7ec 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -705,7 +705,7 @@
     }
 
     /**
-     * This class represents an IpSecTunnelInterface
+     * This class represents an IpSecTunnelInterface.
      *
      * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
      * local endpoints for IPsec tunnels.
@@ -714,9 +714,7 @@
      * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
      * cannot be used in standalone mode within Android, the higher layers may use the tunnel
      * to create Network objects which are accessible to the Android system.
-     * @hide
      */
-    @SystemApi
     public static final class IpSecTunnelInterface implements AutoCloseable {
         private final String mOpPackageName;
         private final IIpSecService mService;
@@ -727,23 +725,26 @@
         private String mInterfaceName;
         private int mResourceId = INVALID_RESOURCE_ID;
 
-        /** Get the underlying SPI held by this object. */
+        /**
+         * Get the underlying SPI held by this object.
+         *
+         * @hide
+         */
+        @SystemApi
         @NonNull
         public String getInterfaceName() {
             return mInterfaceName;
         }
 
         /**
-         * Add an address to the IpSecTunnelInterface
+         * Add an address to the IpSecTunnelInterface.
          *
          * <p>Add an address which may be used as the local inner address for
          * tunneled traffic.
          *
          * @param address the local address for traffic inside the tunnel
          * @param prefixLen length of the InetAddress prefix
-         * @hide
          */
-        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -758,15 +759,13 @@
         }
 
         /**
-         * Remove an address from the IpSecTunnelInterface
+         * Remove an address from the IpSecTunnelInterface.
          *
-         * <p>Remove an address which was previously added to the IpSecTunnelInterface
+         * <p>Remove an address which was previously added to the IpSecTunnelInterface.
          *
          * @param address to be removed
          * @param prefixLen length of the InetAddress prefix
-         * @hide
          */
-        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -817,7 +816,7 @@
         }
 
         /**
-         * Delete an IpSecTunnelInterface
+         * Delete an IpSecTunnelInterface.
          *
          * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
          * resources. Any packets bound for this interface either inbound or outbound will
@@ -839,7 +838,12 @@
             }
         }
 
-        /** Check that the Interface was closed properly. */
+
+        /**
+         * Check that the Interface was closed properly.
+         *
+         * @hide
+         */
         @Override
         protected void finalize() throws Throwable {
             if (mCloseGuard != null) {
@@ -871,17 +875,52 @@
      * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
      *
      * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
-     * underlying network goes away, and the onLost() callback is received.
+     * underlying network disconnects, and the {@link
+     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
      *
-     * @param localAddress The local addres of the tunnel
-     * @param remoteAddress The local addres of the tunnel
-     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
-     *        This network should almost certainly be a network such as WiFi with an L2 address.
-     * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
-     * @throws IOException indicating that the socket could not be opened or bound
-     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
-     * @hide
+     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
+     *     This network should almost certainly be a physical network such as WiFi.
+     * @return a new {@link IpSecTunnelInterface} with the specified properties
+     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+     *     error
+     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+     *     reached the limit.
      */
+    @NonNull
+    @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+    public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork)
+            throws ResourceUnavailableException, IOException {
+
+        // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link
+        // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be
+        // safely removed.
+        final InetAddress address = InetAddress.getLocalHost();
+        return createIpSecTunnelInterface(address, address, underlyingNetwork);
+    }
+
+    /**
+     * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
+     *
+     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
+     * underlying network disconnects, and the {@link
+     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
+     *
+     * @param localAddress The local address of the tunnel
+     * @param remoteAddress The local address of the tunnel
+     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
+     *     This network should almost certainly be a physical network such as WiFi.
+     * @return a new {@link IpSecTunnelInterface} with the specified properties
+     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+     *     error
+     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+     *     reached the limit.
+     * @hide
+     * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)}
+     */
+    @Deprecated
     @SystemApi
     @NonNull
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@@ -905,16 +944,14 @@
      * <p>Applications should probably not use this API directly.
      *
      *
-     * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
+     * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied
      *        transform.
-     * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
+     * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which
      *        the transform will be used.
      * @param transform an {@link IpSecTransform} created in tunnel mode
-     * @throws IOException indicating that the transform could not be applied due to a lower
-     *         layer failure.
-     * @hide
+     * @throws IOException indicating that the transform could not be applied due to a lower-layer
+     *     error
      */
-    @SystemApi
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
     @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index a0dc72d..b644ed5 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -194,13 +194,15 @@
         subscriberId = state.subscriberId;
 
         if (type == TYPE_WIFI) {
-            if (state.networkId != null) {
-                networkId = state.networkId;
-            } else {
-                final WifiManager wifi = (WifiManager) context.getSystemService(
-                        Context.WIFI_SERVICE);
-                final WifiInfo info = wifi.getConnectionInfo();
-                networkId = info != null ? info.getSSID() : null;
+            if (state.networkCapabilities.getSsid() != null) {
+                networkId = state.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;
+                }
             }
         }
 
diff --git a/core/java/android/net/QosFilter.java b/core/java/android/net/QosFilter.java
index 0705468..ab55002 100644
--- a/core/java/android/net/QosFilter.java
+++ b/core/java/android/net/QosFilter.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 
+import java.net.InetAddress;
+
 /**
  * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
  * to their related {@link QosCallback}.
@@ -58,5 +60,16 @@
      */
     @QosCallbackException.ExceptionType
     public abstract int validate();
+
+    /**
+     * Determines whether or not the parameters is a match for the filter.
+     *
+     * @param address the local address
+     * @param startPort the start of the port range
+     * @param endPort the end of the port range
+     * @return whether the parameters match the local address of the filter
+     */
+    public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
+            int startPort, int endPort);
 }
 
diff --git a/core/java/android/net/QosSocketFilter.java b/core/java/android/net/QosSocketFilter.java
index f51a088..2080e68 100644
--- a/core/java/android/net/QosSocketFilter.java
+++ b/core/java/android/net/QosSocketFilter.java
@@ -26,7 +26,10 @@
 import android.system.Os;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileDescriptor;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
@@ -125,4 +128,39 @@
     public Network getNetwork() {
         return mQosSocketInfo.getNetwork();
     }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
+            final int endPort) {
+        if (mQosSocketInfo.getLocalSocketAddress() == null) {
+            return false;
+        }
+
+        return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+                endPort);
+    }
+
+    /**
+     * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+     * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
+     * <p>
+     * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
+     * due to being final.
+     *
+     * @param filterSocketAddress the socket address of the filter
+     * @param address the address to compare the filterSocketAddressWith
+     * @param startPort the start of the port range to check
+     * @param endPort the end of the port range to check
+     */
+    @VisibleForTesting
+    public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+            @NonNull final InetAddress address,
+            final int startPort, final int endPort) {
+        return startPort <= filterSocketAddress.getPort()
+                && endPort >= filterSocketAddress.getPort()
+                && filterSocketAddress.getAddress().equals(address);
+    }
 }
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 7e17a08..ff126e1 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -1,10 +1,10 @@
 # Bug component: 95221
 
-narayan@google.com
-nandana@google.com
 corinac@google.com
+nandana@google.com
 zezeozue@google.com
 maco@google.com
 sahanas@google.com
 abkaur@google.com
 chiangi@google.com
+narayan@google.com
diff --git a/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
new file mode 100644
index 0000000..d9b403c
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.service.resumeonreboot;
+
+import android.os.RemoteCallback;
+
+/** @hide */
+interface IResumeOnRebootService {
+    oneway void wrapSecret(in byte[] unwrappedBlob, in long lifeTimeInMillis, in RemoteCallback resultCallback);
+    oneway void unwrap(in byte[] wrappedBlob, in RemoteCallback resultCallback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
new file mode 100644
index 0000000..4ebaa96
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.service.resumeonreboot;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+
+/**
+ * Base class for service that provides wrapping/unwrapping of the opaque blob needed for
+ * ResumeOnReboot operation. The package needs to provide a wrap/unwrap implementation for handling
+ * the opaque blob, that's secure even when on device keystore and clock is compromised. This can
+ * be achieved by using tamper-resistant hardware such as a secure element with a secure clock, or
+ * using a remote server to store and retrieve data and manage timing.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE} permission,
+ * include an intent filter with the {@link #SERVICE_INTERFACE} action and mark the service as
+ * direct-boot aware. In addition, the package that contains the service must be granted
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE}.
+ * For example:</p>
+ * <pre>
+ *     &lt;service android:name=".FooResumeOnRebootService"
+ *             android:exported="true"
+ *             android:priority="100"
+ *             android:directBootAware="true"
+ *             android:permission="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"&gt;
+ *         &lt;intent-filter&gt;
+ *             &lt;action android:name="android.service.resumeonreboot.ResumeOnRebootService" /&gt;
+ *         &lt;/intent-filter&gt;
+ *     &lt;/service&gt;
+ * </pre>
+ *
+ * //TODO: Replace this with public link when available.
+ *
+ * @hide
+ * @see
+ * <a href="https://goto.google.com/server-based-ror">https://goto.google.com/server-based-ror</a>
+ */
+@SystemApi
+public abstract class ResumeOnRebootService extends Service {
+
+    /**
+     * The intent that the service must respond to. Add it to the intent filter of the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.service.resumeonreboot.ResumeOnRebootService";
+    /** @hide */
+    public static final String UNWRAPPED_BLOB_KEY = "unrwapped_blob_key";
+    /** @hide */
+    public static final String WRAPPED_BLOB_KEY = "wrapped_blob_key";
+    /** @hide */
+    public static final String EXCEPTION_KEY = "exception_key";
+
+    private final Handler mHandler = BackgroundThread.getHandler();
+
+    /**
+     * Implementation for wrapping the opaque blob used for resume-on-reboot prior to
+     * reboot. The service should not assume any structure of the blob to be wrapped. The
+     * implementation should wrap the opaque blob in a reasonable time or throw {@link IOException}
+     * if it's unable to complete the action.
+     *
+     * @param blob             The opaque blob with size on the order of 100 bytes.
+     * @param lifeTimeInMillis The life time of the blob. This must be strictly enforced by the
+     *                         implementation and any attempt to unWrap the wrapped blob returned by
+     *                         this function after expiration should
+     *                         fail.
+     * @return Wrapped blob to be persisted across reboot with size on the order of 100 bytes.
+     * @throws IOException if the implementation is unable to wrap the blob successfully.
+     */
+    @NonNull
+    public abstract byte[] onWrap(@NonNull byte[] blob, @DurationMillisLong long lifeTimeInMillis)
+            throws IOException;
+
+    /**
+     * Implementation for unwrapping the wrapped blob used for resume-on-reboot after reboot. This
+     * operation would happen after reboot during direct boot mode (i.e before device is unlocked
+     * for the first time). The implementation should unwrap the wrapped blob in a reasonable time
+     * and returns the result or throw {@link IOException} if it's unable to complete the action
+     * and {@link IllegalArgumentException} if {@code unwrapBlob} fails because the wrappedBlob is
+     * stale.
+     *
+     * @param wrappedBlob The wrapped blob with size on the order of 100 bytes.
+     * @return Unwrapped blob used for resume-on-reboot with the size on the order of 100 bytes.
+     * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully.
+     */
+    @NonNull
+    public abstract byte[] onUnwrap(@NonNull byte[] wrappedBlob) throws IOException;
+
+    private final android.service.resumeonreboot.IResumeOnRebootService mInterface =
+            new android.service.resumeonreboot.IResumeOnRebootService.Stub() {
+
+                @Override
+                public void wrapSecret(byte[] unwrappedBlob,
+                        @DurationMillisLong long lifeTimeInMillis,
+                        RemoteCallback resultCallback) throws RemoteException {
+                    mHandler.post(() -> {
+                        try {
+                            byte[] wrappedBlob = onWrap(unwrappedBlob,
+                                    lifeTimeInMillis);
+                            Bundle bundle = new Bundle();
+                            bundle.putByteArray(WRAPPED_BLOB_KEY, wrappedBlob);
+                            resultCallback.sendResult(bundle);
+                        } catch (Throwable e) {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+                            resultCallback.sendResult(bundle);
+                        }
+                    });
+                }
+
+                @Override
+                public void unwrap(byte[] wrappedBlob, RemoteCallback resultCallback)
+                        throws RemoteException {
+                    mHandler.post(() -> {
+                        try {
+                            byte[] unwrappedBlob = onUnwrap(wrappedBlob);
+                            Bundle bundle = new Bundle();
+                            bundle.putByteArray(UNWRAPPED_BLOB_KEY, unwrappedBlob);
+                            resultCallback.sendResult(bundle);
+                        } catch (Throwable e) {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+                            resultCallback.sendResult(bundle);
+                        }
+                    });
+                }
+            };
+
+    @Nullable
+    @Override
+    public IBinder onBind(@Nullable Intent intent) {
+        return mInterface.asBinder();
+    }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 537498c..9d0ae30 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -39,7 +39,6 @@
     public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
-    public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
     public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
     /** @hide */
@@ -53,7 +52,6 @@
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "true");
-        DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index c5a956a..99692d0 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,3 +3,5 @@
 per-file *Chooser* = file:/packages/SystemUI/OWNERS
 per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
 per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
+per-file IVoice* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/graphics/fonts/OWNERS b/core/java/com/android/internal/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/com/android/internal/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c6a1bdd..3183ed3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2984,6 +2984,12 @@
     <permission android:name="android.permission.RECOVERY"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to do certain operations needed for
+         resume on reboot feature.
+         @hide -->
+    <permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to read system update info.
          @hide -->
     <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index bd7da0c..b3f3993 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -1 +1,6 @@
 per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# Notification, DND, Status bar
+per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
diff --git a/core/tests/coretests/src/android/app/people/OWNERS b/core/tests/coretests/src/android/app/people/OWNERS
new file mode 100644
index 0000000..6ec8e6a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/people/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/people/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
index 711f5f0..7b76706 100644
--- a/core/tests/coretests/src/android/content/pm/OWNERS
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -1,2 +1,3 @@
 per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-
+per-file SigningDetailsTest.java = mpgroover@google.com
+per-file SigningDetailsTest.java = cbrubaker@google.com
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 9867d81..65d3a01 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,3 +1,4 @@
+alanstokes@google.com
 cbrubaker@google.com
 hackbod@android.com
 hackbod@google.com
@@ -12,4 +13,4 @@
 toddke@google.com
 yamasani@google.com
 
-per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
\ No newline at end of file
+per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index 7c0af6d..6398cee 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -37,6 +37,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.time.Instant;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.Map;
@@ -237,12 +238,18 @@
     }
 
     private boolean mAllowUsingExhaustedKeys = true;
+    private boolean mAllowUsingExpiredKeys = false;
 
     @Override
     public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) {
         mAllowUsingExhaustedKeys = allowUsingExhaustedKeys;
     }
 
+    @Override
+    public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+        mAllowUsingExpiredKeys = allowUsingExpiredKeys;
+    }
+
     private boolean mOperationHandleSet = false;
     private long mOperationHandle = 0;
 
@@ -256,7 +263,8 @@
     public long getCredstoreOperationHandle() {
         if (!mOperationHandleSet) {
             try {
-                mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys);
+                mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys,
+                        mAllowUsingExpiredKeys);
                 mOperationHandleSet = true;
             } catch (android.os.RemoteException e) {
                 throw new RuntimeException("Unexpected RemoteException ", e);
@@ -306,7 +314,8 @@
                 rnsParcels,
                 sessionTranscript != null ? sessionTranscript : new byte[0],
                 readerSignature != null ? readerSignature : new byte[0],
-                mAllowUsingExhaustedKeys);
+                mAllowUsingExhaustedKeys,
+                mAllowUsingExpiredKeys);
         } catch (android.os.RemoteException e) {
             throw new RuntimeException("Unexpected RemoteException ", e);
         } catch (android.os.ServiceSpecificException e) {
@@ -410,6 +419,34 @@
     }
 
     @Override
+    public void storeStaticAuthenticationData(X509Certificate authenticationKey,
+            Instant expirationDate,
+            byte[] staticAuthData)
+            throws UnknownAuthenticationKeyException {
+        try {
+            AuthKeyParcel authKeyParcel = new AuthKeyParcel();
+            authKeyParcel.x509cert = authenticationKey.getEncoded();
+            long millisSinceEpoch = (expirationDate.getEpochSecond() * 1000)
+                                    + (expirationDate.getNano() / 1000000);
+            mBinder.storeStaticAuthenticationDataWithExpiration(authKeyParcel,
+                    millisSinceEpoch, staticAuthData);
+        } catch (CertificateEncodingException e) {
+            throw new RuntimeException("Error encoding authenticationKey", e);
+        } catch (android.os.RemoteException e) {
+            throw new RuntimeException("Unexpected RemoteException ", e);
+        } catch (android.os.ServiceSpecificException e) {
+            if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) {
+                throw new UnsupportedOperationException("Not supported", e);
+            } else if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) {
+                throw new UnknownAuthenticationKeyException(e.getMessage(), e);
+            } else {
+                throw new RuntimeException("Unexpected ServiceSpecificException with code "
+                        + e.errorCode, e);
+            }
+        }
+    }
+
+    @Override
     public @NonNull int[] getAuthenticationDataUsageCount() {
         try {
             int[] usageCount = mBinder.getAuthenticationDataUsageCount();
@@ -421,4 +458,49 @@
                     + e.errorCode, e);
         }
     }
+
+    @Override
+    public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
+        try {
+            byte[] proofOfOwnership = mBinder.proveOwnership(challenge);
+            return proofOfOwnership;
+        } catch (android.os.RemoteException e) {
+            throw new RuntimeException("Unexpected RemoteException ", e);
+        } catch (android.os.ServiceSpecificException e) {
+            if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) {
+                throw new UnsupportedOperationException("Not supported", e);
+            } else {
+                throw new RuntimeException("Unexpected ServiceSpecificException with code "
+                        + e.errorCode, e);
+            }
+        }
+    }
+
+    @Override
+    public @NonNull byte[] delete(@NonNull byte[] challenge) {
+        try {
+            byte[] proofOfDeletion = mBinder.deleteWithChallenge(challenge);
+            return proofOfDeletion;
+        } catch (android.os.RemoteException e) {
+            throw new RuntimeException("Unexpected RemoteException ", e);
+        } catch (android.os.ServiceSpecificException e) {
+            throw new RuntimeException("Unexpected ServiceSpecificException with code "
+                    + e.errorCode, e);
+        }
+    }
+
+    @Override
+    public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
+        try {
+            IWritableCredential binder = mBinder.update();
+            byte[] proofOfProvision =
+                    CredstoreWritableIdentityCredential.personalize(binder, personalizationData);
+            return proofOfProvision;
+        } catch (android.os.RemoteException e) {
+            throw new RuntimeException("Unexpected RemoteException ", e);
+        } catch (android.os.ServiceSpecificException e) {
+            throw new RuntimeException("Unexpected ServiceSpecificException with code "
+                    + e.errorCode, e);
+        }
+    }
 }
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
index 1290633..d8d4742 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -162,5 +162,4 @@
                     + e.errorCode, e);
         }
     }
-
 }
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
index 725e3d8..d2e7984 100644
--- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -76,7 +76,14 @@
 
     @NonNull @Override
     public byte[] personalize(@NonNull PersonalizationData personalizationData) {
+        return personalize(mBinder, personalizationData);
+    }
 
+    // Used by both personalize() and CredstoreIdentityCredential.update().
+    //
+    @NonNull
+    static byte[] personalize(IWritableCredential binder,
+            @NonNull PersonalizationData personalizationData) {
         Collection<AccessControlProfile> accessControlProfiles =
                 personalizationData.getAccessControlProfiles();
 
@@ -144,7 +151,7 @@
             secureUserId = getRootSid();
         }
         try {
-            byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels,
+            byte[] personalizationReceipt = binder.personalize(acpParcels, ensParcels,
                     secureUserId);
             return personalizationReceipt;
         } catch (android.os.RemoteException e) {
@@ -164,5 +171,4 @@
         return rootSid;
     }
 
-
 }
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 4eb6e42..8f175bb 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -23,6 +23,7 @@
 import java.security.KeyPair;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.time.Instant;
 import java.util.Collection;
 import java.util.Map;
 
@@ -114,6 +115,25 @@
     public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys);
 
     /**
+     * Sets whether to allow using an authentication key which has been expired if no
+     * other key is available. This must be called prior to calling
+     * {@link #getEntries(byte[], Map, byte[], byte[])}.
+     *
+     * <p>By default this is set to false.
+     *
+     * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+     * fails with {@link UnsupportedOperationException}. See
+     * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+     * feature versions.
+     *
+     * @param allowUsingExpiredKeys whether to allow using an authentication key which use count
+     *                              has been exceeded if no other key is available.
+     */
+    public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
      * operation handle.
      *
@@ -289,6 +309,21 @@
      *
      * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
      * can be obtained using the {@link #getCredentialKeyCertificateChain()} method.
+
+     * <p>If the implementation is feature version 202101 or later,
+     * each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26 which
+     * contains a DER encoded OCTET STRING with the bytes of the CBOR with the following CDDL:
+     * <pre>
+     *   ProofOfBinding = [
+     *     "ProofOfBinding",
+     *     bstr,              // Contains SHA-256(ProofOfProvisioning)
+     *   ]
+     * </pre>
+     * <p>This CBOR enables an issuer to determine the exact state of the credential it
+     * returns issuer-signed data for.
+     *
+     * <p> See {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for
+     * known feature versions.
      *
      * @return A collection of X.509 certificates for dynamic authentication keys that need issuer
      * certification.
@@ -308,16 +343,136 @@
      *                          the authenticity
      *                          and integrity of the credential data fields.
      * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
+     * @deprecated Use {@link #storeStaticAuthenticationData(X509Certificate, Instant, byte[])}
+     *     instead.
      */
+    @Deprecated
     public abstract void storeStaticAuthenticationData(
             @NonNull X509Certificate authenticationKey,
             @NonNull byte[] staticAuthData)
             throws UnknownAuthenticationKeyException;
 
     /**
+     * Store authentication data associated with a dynamic authentication key.
+     *
+     * This should only be called for an authenticated key returned by
+     * {@link #getAuthKeysNeedingCertification()}.
+     *
+     * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+     * fails with {@link UnsupportedOperationException}. See
+     * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+     * feature versions.
+     *
+     * @param authenticationKey The dynamic authentication key for which certification and
+     *                          associated static
+     *                          authentication data is being provided.
+     * @param expirationDate    The expiration date of the static authentication data.
+     * @param staticAuthData    Static authentication data provided by the issuer that validates
+     *                          the authenticity
+     *                          and integrity of the credential data fields.
+     * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
+     */
+    public void storeStaticAuthenticationData(
+            @NonNull X509Certificate authenticationKey,
+            @NonNull Instant expirationDate,
+            @NonNull byte[] staticAuthData)
+            throws UnknownAuthenticationKeyException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Get the number of times the dynamic authentication keys have been used.
      *
      * @return int array of dynamic authentication key usage counts.
      */
     public @NonNull abstract int[] getAuthenticationDataUsageCount();
+
+    /**
+     * Proves ownership of a credential.
+     *
+     * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
+     * with payload set to {@code ProofOfDeletion} as defined below.</p>
+     *
+     * <p>The returned CBOR is the following:</p>
+     * <pre>
+     *     ProofOfOwnership = [
+     *          "ProofOfOwnership",           ; tstr
+     *          tstr,                         ; DocType
+     *          bstr,                         ; Challenge
+     *          bool                          ; true if this is a test credential, should
+     *                                        ; always be false.
+     *      ]
+     * </pre>
+     *
+     * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+     * fails with {@link UnsupportedOperationException}. See
+     * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+     * feature versions.
+     *
+     * @param challenge is a non-empty byte array whose contents should be unique, fresh and
+     *                  provided by the issuing authority. The value provided is embedded in the
+     *                  generated CBOR and enables the issuing authority to verify that the
+     *                  returned proof is fresh.
+     * @return the COSE_Sign1 data structure above
+     */
+    public @NonNull byte[] proveOwnership(@NonNull byte[] challenge)  {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Deletes a credential.
+     *
+     * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
+     * with payload set to {@code ProofOfDeletion} as defined below.</p>
+     *
+     * <pre>
+     *     ProofOfDeletion = [
+     *          "ProofOfDeletion",            ; tstr
+     *          tstr,                         ; DocType
+     *          bstr,                         ; Challenge
+     *          bool                          ; true if this is a test credential, should
+     *                                        ; always be false.
+     *      ]
+     * </pre>
+     *
+     * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+     * fails with {@link UnsupportedOperationException}. See
+     * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+     * feature versions.
+     *
+     * @param challenge is a non-empty byte array whose contents should be unique, fresh and
+     *                  provided by the issuing authority. The value provided is embedded in the
+     *                  generated CBOR and enables the issuing authority to verify that the
+     *                  returned proof is fresh.
+     * @return the COSE_Sign1 data structure above
+     */
+    public @NonNull byte[] delete(@NonNull byte[] challenge)  {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Updates the credential with new access control profiles and data items.
+     *
+     * <p>This method is similar to
+     * {@link WritableIdentityCredential#personalize(PersonalizationData)} except that it operates
+     * on an existing credential, see the documentation for that method for the format of the
+     * returned data.
+     *
+     * <p>If this call succeeds an side-effect is that all dynamic authentication keys for the
+     * credential are deleted. The application will need to use
+     * {@link #getAuthKeysNeedingCertification()} to generate replacement keys and return
+     * them for issuer certification.
+     *
+     * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+     * fails with {@link UnsupportedOperationException}. See
+     * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+     * feature versions.
+     *
+     * @param personalizationData   The data to update, including access control profiles
+     *                              and data elements and their values, grouped into namespaces.
+     * @return A COSE_Sign1 data structure, see above.
+     */
+    public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java
index 3843d92..6ccd0e8 100644
--- a/identity/java/android/security/identity/IdentityCredentialStore.java
+++ b/identity/java/android/security/identity/IdentityCredentialStore.java
@@ -72,6 +72,17 @@
  * <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader
  * authentication to protect data elements. The reason for this is user authentication or user
  * approval of data release is not possible when the device is off.
+ *
+ * <p>The Identity Credential API is designed to be able to evolve and change over time
+ * but still provide 100% backwards compatibility. This is complicated by the fact that
+ * there may be a version skew between the API used by the application and the version
+ * implemented in secure hardware. To solve this problem, the API provides for a way
+ * for the application to query which feature version the hardware implements (if any
+ * at all) using
+ * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} and
+ * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS}.
+ * Methods which only work on certain feature versions are clearly documented as
+ * such.
  */
 public abstract class IdentityCredentialStore {
     IdentityCredentialStore() {}
@@ -193,7 +204,9 @@
      * @param credentialName the name of the credential to delete.
      * @return {@code null} if the credential was not found, the COSE_Sign1 data structure above
      *     if the credential was found and deleted.
+     * @deprecated Use {@link IdentityCredential#delete(byte[])} instead.
      */
+    @Deprecated
     public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName);
 
     /** @hide */
@@ -201,5 +214,4 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Ciphersuite {
     }
-
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
index 6ddaa70..b631999 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
@@ -38,9 +38,10 @@
 
     public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
             @NonNull KeyMetadata metadata,
+            @NonNull byte[] x509EncodedForm,
             @NonNull KeyStoreSecurityLevel securityLevel,
             @NonNull ECParameterSpec params, @NonNull ECPoint w) {
-        super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
+        super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
         mParams = params;
         mW = w;
     }
@@ -48,7 +49,7 @@
     public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
             @NonNull KeyMetadata metadata,
             @NonNull KeyStoreSecurityLevel securityLevel, @NonNull ECPublicKey info) {
-        this(descriptor, metadata, securityLevel, info.getParams(), info.getW());
+        this(descriptor, metadata, info.getEncoded(), securityLevel, info.getParams(), info.getW());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
index 49dd77e..db3e567 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
@@ -32,13 +32,15 @@
 public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
     private final byte[] mCertificate;
     private final byte[] mCertificateChain;
+    private final byte[] mEncoded;
 
     public AndroidKeyStorePublicKey(@NonNull KeyDescriptor descriptor,
-            @NonNull KeyMetadata metadata, @NonNull String algorithm,
-            @NonNull KeyStoreSecurityLevel securityLevel) {
+            @NonNull KeyMetadata metadata, @NonNull byte[] x509EncodedForm,
+            @NonNull String algorithm, @NonNull KeyStoreSecurityLevel securityLevel) {
         super(descriptor, metadata.key.nspace, metadata.authorizations, algorithm, securityLevel);
         mCertificate = metadata.certificate;
         mCertificateChain = metadata.certificateChain;
+        mEncoded = x509EncodedForm;
     }
 
     abstract AndroidKeyStorePrivateKey getPrivateKey();
@@ -50,7 +52,7 @@
 
     @Override
     public byte[] getEncoded() {
-        return ArrayUtils.cloneIfNotEmpty(mCertificate);
+        return ArrayUtils.cloneIfNotEmpty(mEncoded);
     }
 
     @Override
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
index b578ea9..9fe6cf3 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
@@ -36,9 +36,11 @@
 
     public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor,
             @NonNull KeyMetadata metadata,
+            @NonNull byte[] x509EncodedForm,
             @NonNull KeyStoreSecurityLevel securityLevel, @NonNull BigInteger modulus,
             @NonNull BigInteger publicExponent) {
-        super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_RSA, securityLevel);
+        super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_RSA,
+                securityLevel);
         mModulus = modulus;
         mPublicExponent = publicExponent;
     }
@@ -46,7 +48,8 @@
     public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor,
             @NonNull KeyMetadata metadata,
             @NonNull KeyStoreSecurityLevel securityLevel, @NonNull RSAPublicKey info) {
-        this(descriptor, metadata, securityLevel, info.getModulus(), info.getPublicExponent());
+        this(descriptor, metadata, info.getEncoded(), securityLevel, info.getModulus(),
+                info.getPublicExponent());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
index 06c5294..fcee98d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
@@ -19,11 +19,8 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.image.DynamicSystemClient;
-import android.os.image.DynamicSystemManager;
-import android.util.FeatureFlagUtils;
 
 
 /**
@@ -43,24 +40,10 @@
             return;
         }
 
-        DynamicSystemManager dynSystem =
-                (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
-
-        boolean isInUse = (dynSystem != null) && dynSystem.isInUse();
-
-        if (!isInUse && !featureFlagEnabled()) {
-            return;
-        }
-
         Intent startServiceIntent = new Intent(
                 context, DynamicSystemInstallationService.class);
 
         startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
         context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
     }
-
-    private boolean featureFlagEnabled() {
-        return SystemProperties.getBoolean(
-                FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.DYNAMIC_SYSTEM, false);
-    }
 }
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index 82ea744..64e42cc 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -22,10 +22,8 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.image.DynamicSystemClient;
-import android.util.FeatureFlagUtils;
 import android.util.Log;
 
 /**
@@ -46,12 +44,6 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if (!featureFlagEnabled()) {
-            Log.w(TAG, FeatureFlagUtils.DYNAMIC_SYSTEM + " not enabled; activity aborted.");
-            finish();
-            return;
-        }
-
         KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
 
         if (km != null) {
@@ -101,11 +93,6 @@
         startServiceAsUser(intent, UserHandle.SYSTEM);
     }
 
-    private boolean featureFlagEnabled() {
-        return SystemProperties.getBoolean(
-                FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.DYNAMIC_SYSTEM, false);
-    }
-
     static boolean isVerified(String url) {
         if (url == null) return true;
         return sVerifiedUrl != null && sVerifiedUrl.equals(url);
diff --git a/services/OWNERS b/services/OWNERS
index 88d0b61..03e0807 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1 +1,6 @@
 per-file Android.bp = file:platform/build/soong:/OWNERS
+
+# art-team@ manages the system server profile
+per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
+per-file java/com/android/server/* = toddke@google.com
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5c34584..4e2519b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3297,6 +3297,12 @@
         enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
 
         if (isFsEncrypted) {
+            // When a user has secure lock screen, require secret to actually unlock.
+            // This check is mostly in place for emulation mode.
+            if (StorageManager.isFileEncryptedEmulatedOnly() &&
+                mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
+                throw new IllegalStateException("Secret required to unlock secure user " + userId);
+            }
             try {
                 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
                         encodeBytes(secret));
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
new file mode 100644
index 0000000..e8e83cc
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.apphibernation;
+
+import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
+
+import android.annotation.NonNull;
+import android.apphibernation.IAppHibernationService;
+import android.content.Context;
+import android.provider.DeviceConfig;
+
+import com.android.server.SystemService;
+
+/**
+ * System service that manages app hibernation state, a state apps can enter that means they are
+ * not being actively used and can be optimized for storage. The actual policy for determining
+ * if an app should hibernate is managed by PermissionController code.
+ */
+public final class AppHibernationService extends SystemService {
+
+    private final Context mContext;
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public AppHibernationService(@NonNull Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub);
+    }
+
+    /**
+     * Whether a package is hibernating for a given user.
+     *
+     * @param packageName the package to check
+     * @param userId the user to check
+     * @return true if package is hibernating for the user
+     */
+    public boolean isHibernating(String packageName, int userId) {
+        // Stub
+        throw new UnsupportedOperationException("Hibernation state management not implemented yet");
+    }
+
+    /**
+     * Set whether the package is hibernating for the given user.
+     *
+     * @param packageName package to modify state
+     * @param userId user
+     * @param isHibernating new hibernation state
+     */
+    public void setHibernating(String packageName, int userId, boolean isHibernating) {
+        // Stub
+        throw new UnsupportedOperationException("Hibernation state management not implemented yet");
+    }
+
+    private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
+
+    static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
+        final AppHibernationService mService;
+
+        AppHibernationServiceStub(AppHibernationService service) {
+            mService = service;
+        }
+
+        @Override
+        public boolean isHibernating(String packageName, int userId) {
+            return mService.isHibernating(packageName, userId);
+        }
+
+        @Override
+        public void setHibernating(String packageName, int userId, boolean isHibernating) {
+            mService.setHibernating(packageName, userId, isHibernating);
+        }
+    }
+
+    /**
+     * Whether app hibernation is enabled on this device.
+     *
+     * @return true if enabled, false otherwise
+     */
+    public static boolean isAppHibernationEnabled() {
+        return DeviceConfig.getBoolean(
+                NAMESPACE_APP_HIBERNATION,
+                AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED,
+                false /* defaultValue */);
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index ab289ea..f876e1a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -901,7 +901,6 @@
 
     @ServiceThreadOnly
     void setArcStatus(boolean enabled) {
-        // TODO(shubang): add tests
         assertRunOnServiceThread();
 
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
new file mode 100644
index 0000000..8399f54
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -0,0 +1,249 @@
+/*
+ * 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.locksettings;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.service.resumeonreboot.IResumeOnRebootService;
+import android.service.resumeonreboot.ResumeOnRebootService;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/** @hide */
+public class ResumeOnRebootServiceProvider {
+
+    private static final String PROVIDER_PACKAGE = DeviceConfig.getString(
+            DeviceConfig.NAMESPACE_OTA, "resume_on_reboot_service_package", "");
+    private static final String PROVIDER_REQUIRED_PERMISSION =
+            Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
+    private static final String TAG = "ResumeOnRebootServiceProvider";
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+
+    public ResumeOnRebootServiceProvider(Context context) {
+        this(context, context.getPackageManager());
+    }
+
+    @VisibleForTesting
+    public ResumeOnRebootServiceProvider(Context context, PackageManager packageManager) {
+        this.mContext = context;
+        this.mPackageManager = packageManager;
+    }
+
+    @Nullable
+    private ServiceInfo resolveService() {
+        Intent intent = new Intent();
+        intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
+        if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+            intent.setPackage(PROVIDER_PACKAGE);
+        }
+
+        List<ResolveInfo> resolvedIntents =
+                mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+        for (ResolveInfo resolvedInfo : resolvedIntents) {
+            if (resolvedInfo.serviceInfo != null
+                    && PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
+                return resolvedInfo.serviceInfo;
+            }
+        }
+        return null;
+    }
+
+    /** Creates a new {@link ResumeOnRebootServiceConnection} */
+    @Nullable
+    public ResumeOnRebootServiceConnection getServiceConnection() {
+        ServiceInfo serviceInfo = resolveService();
+        if (serviceInfo == null) {
+            return null;
+        }
+        return new ResumeOnRebootServiceConnection(mContext, serviceInfo.getComponentName());
+    }
+
+    /**
+     * Connection class used for contacting the registered {@link IResumeOnRebootService}
+     */
+    public static class ResumeOnRebootServiceConnection {
+
+        private static final String TAG = "ResumeOnRebootServiceConnection";
+        private final Context mContext;
+        private final ComponentName mComponentName;
+        private IResumeOnRebootService mBinder;
+
+        private ResumeOnRebootServiceConnection(Context context,
+                @NonNull ComponentName componentName) {
+            mContext = context;
+            mComponentName = componentName;
+        }
+
+        /** Unbind from the service */
+        public void unbindService() {
+            mContext.unbindService(new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    mBinder = null;
+
+                }
+            });
+        }
+
+        /** Bind to the service */
+        public void bindToService(long timeOut) throws TimeoutException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                CountDownLatch connectionLatch = new CountDownLatch(1);
+                Intent intent = new Intent();
+                intent.setComponent(mComponentName);
+                final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder service) {
+                                mBinder = IResumeOnRebootService.Stub.asInterface(service);
+                                connectionLatch.countDown();
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(ComponentName name) {
+                            }
+                        },
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        BackgroundThread.getHandler(), UserHandle.SYSTEM);
+
+                if (!success) {
+                    Slog.e(TAG, "Binding: " + mComponentName + " u" + UserHandle.SYSTEM
+                            + " failed.");
+                    return;
+                }
+                waitForLatch(connectionLatch, "serviceConnection", timeOut);
+            }
+        }
+
+        /** Wrap opaque blob */
+        public byte[] wrapBlob(byte[] unwrappedBlob, long lifeTimeInMillis,
+                long timeOutInMillis)
+                throws RemoteException, TimeoutException, IOException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                throw new RemoteException("Service not bound");
+            }
+            CountDownLatch binderLatch = new CountDownLatch(1);
+            ResumeOnRebootServiceCallback
+                    resultCallback =
+                    new ResumeOnRebootServiceCallback(
+                            binderLatch);
+            mBinder.wrapSecret(unwrappedBlob, lifeTimeInMillis, new RemoteCallback(resultCallback));
+            waitForLatch(binderLatch, "wrapSecret", timeOutInMillis);
+            if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+                throwTypedException(resultCallback.getResult().getParcelable(
+                        ResumeOnRebootService.EXCEPTION_KEY));
+            }
+            return resultCallback.mResult.getByteArray(ResumeOnRebootService.WRAPPED_BLOB_KEY);
+        }
+
+        /** Unwrap wrapped blob */
+        public byte[] unwrap(byte[] wrappedBlob, long timeOut)
+                throws RemoteException, TimeoutException, IOException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                throw new RemoteException("Service not bound");
+            }
+            CountDownLatch binderLatch = new CountDownLatch(1);
+            ResumeOnRebootServiceCallback
+                    resultCallback =
+                    new ResumeOnRebootServiceCallback(
+                            binderLatch);
+            mBinder.unwrap(wrappedBlob, new RemoteCallback(resultCallback));
+            waitForLatch(binderLatch, "unWrapSecret", timeOut);
+            if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+                throwTypedException(resultCallback.getResult().getParcelable(
+                        ResumeOnRebootService.EXCEPTION_KEY));
+            }
+            return resultCallback.getResult().getByteArray(
+                    ResumeOnRebootService.UNWRAPPED_BLOB_KEY);
+        }
+
+        private void throwTypedException(
+                ParcelableException exception)
+                throws IOException {
+            if (exception.getCause() instanceof IOException) {
+                exception.maybeRethrow(IOException.class);
+            } else if (exception.getCause() instanceof IllegalStateException) {
+                exception.maybeRethrow(IllegalStateException.class);
+            } else {
+                // This should not happen. Wrap the cause in IllegalStateException so that it
+                // doesn't disrupt the exception handling
+                throw new IllegalStateException(exception.getCause());
+            }
+        }
+
+        private void waitForLatch(CountDownLatch latch, String reason, long timeOut)
+                throws TimeoutException {
+            try {
+                if (!latch.await(timeOut, TimeUnit.SECONDS)) {
+                    throw new TimeoutException("Latch wait for " + reason + " elapsed");
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new IllegalStateException("Latch wait for " + reason + " interrupted");
+            }
+        }
+    }
+
+    private static class ResumeOnRebootServiceCallback implements
+            RemoteCallback.OnResultListener {
+
+        private final CountDownLatch mResultLatch;
+        private Bundle mResult;
+
+        private ResumeOnRebootServiceCallback(CountDownLatch resultLatch) {
+            this.mResultLatch = resultLatch;
+        }
+
+        @Override
+        public void onResult(@Nullable Bundle result) {
+            this.mResult = result;
+            mResultLatch.countDown();
+        }
+
+        private Bundle getResult() {
+            return mResult;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 06706cd..0ffc1ed 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -184,7 +184,7 @@
         List<PackageInfo> allPackages;
         try {
             allPackages = mPackageManager.getInstalledPackages(
-                    flags | PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM).getList();
+                    flags | PackageManager.MATCH_APEX, UserHandle.getCallingUserId()).getList();
         } catch (RemoteException e) {
             Slog.w(TAG, "Unable to retrieve all package names", e);
             return Collections.emptyList();
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index e1feb5a..6427ae2 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -24,6 +24,9 @@
 import android.os.Handler;
 import android.os.ParcelUuid;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
 import java.util.Objects;
 
 /**
@@ -72,7 +75,8 @@
         @NonNull public final LinkProperties linkProperties;
         public final boolean blocked;
 
-        private UnderlyingNetworkRecord(
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        UnderlyingNetworkRecord(
                 @NonNull Network network,
                 @NonNull NetworkCapabilities networkCapabilities,
                 @NonNull LinkProperties linkProperties,
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 4e0c0c5..0fa97a2 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -24,7 +24,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.ConnectivityManager;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
@@ -36,8 +35,6 @@
 import android.net.Network;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
 import android.net.RouteInfo;
 import android.net.annotations.PolicyDirection;
 import android.net.ipsec.ike.ChildSessionCallback;
@@ -54,7 +51,6 @@
 import android.os.HandlerExecutor;
 import android.os.Message;
 import android.os.ParcelUuid;
-import android.telephony.TelephonyManager;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -360,11 +356,25 @@
      */
     private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
 
-    @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState();
-    @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState();
-    @NonNull private final ConnectingState mConnectingState = new ConnectingState();
-    @NonNull private final ConnectedState mConnectedState = new ConnectedState();
-    @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final DisconnectedState mDisconnectedState = new DisconnectedState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final DisconnectingState mDisconnectingState = new DisconnectingState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final ConnectingState mConnectingState = new ConnectingState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final ConnectedState mConnectedState = new ConnectedState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
 
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
@@ -455,7 +465,8 @@
         this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
     }
 
-    private VcnGatewayConnection(
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    VcnGatewayConnection(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
             @NonNull VcnGatewayConnectionConfig connectionConfig,
@@ -508,7 +519,6 @@
                 EVENT_DISCONNECT_REQUESTED,
                 TOKEN_ALL,
                 new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
-        quit();
 
         // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
         // is also called asynchronously when a NetworkAgent becomes unwanted
@@ -654,7 +664,7 @@
 
         protected void teardownNetwork() {
             if (mNetworkAgent != null) {
-                mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */));
+                mNetworkAgent.unregister();
                 mNetworkAgent = null;
             }
         }
@@ -667,6 +677,8 @@
 
         protected void handleDisconnectRequested(String msg) {
             Slog.v(TAG, "Tearing down. Cause: " + msg);
+            mIsRunning = false;
+
             teardownNetwork();
             teardownIke();
 
@@ -697,7 +709,37 @@
      */
     private class DisconnectedState extends BaseState {
         @Override
-        protected void processStateMsg(Message msg) {}
+        protected void enterState() {
+            if (!mIsRunning) {
+                quitNow(); // Ignore all queued events; cleanup is complete.
+            }
+
+            if (mIkeSession != null || mNetworkAgent != null) {
+                Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+            }
+        }
+
+        @Override
+        protected void processStateMsg(Message msg) {
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED:
+                    // First network found; start tunnel
+                    mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+                    if (mUnderlying != null) {
+                        transitionTo(mConnectingState);
+                    }
+                    break;
+                case EVENT_DISCONNECT_REQUESTED:
+                    mIsRunning = false;
+
+                    quitNow();
+                    break;
+                default:
+                    logUnhandledMessage(msg);
+                    break;
+            }
+        }
     }
 
     private abstract class ActiveBaseState extends BaseState {
@@ -769,20 +811,6 @@
         protected void processStateMsg(Message msg) {}
     }
 
-    // TODO: Remove this when migrating to new NetworkAgent API
-    private static NetworkInfo buildNetworkInfo(boolean isConnected) {
-        NetworkInfo info =
-                new NetworkInfo(
-                        ConnectivityManager.TYPE_MOBILE,
-                        TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                        "MOBILE",
-                        "VCN");
-        info.setDetailedState(
-                isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null);
-
-        return info;
-    }
-
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static NetworkCapabilities buildNetworkCapabilities(
             @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
@@ -893,7 +921,32 @@
         }
     }
 
-    /** External dependencies used by VcnGatewayConnection, for injection in tests. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
+        return mUnderlyingNetworkTrackerCallback;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    UnderlyingNetworkRecord getUnderlyingNetwork() {
+        return mUnderlying;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) {
+        mUnderlying = record;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    boolean isRunning() {
+        return mIsRunning;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setIsRunning(boolean isRunning) {
+        mIsRunning = isRunning;
+    }
+
+    /** External dependencies used by VcnGatewayConnection, for injection in tests */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public static class Dependencies {
         /** Builds a new UnderlyingNetworkTracker. */
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 516c642..6089a52 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,6 +97,7 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
+import com.android.server.apphibernation.AppHibernationService;
 import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.AuthService;
@@ -220,6 +221,8 @@
             "com.android.server.appwidget.AppWidgetService";
     private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.voiceinteraction.VoiceInteractionManagerService";
+    private static final String APP_HIBERNATION_SERVICE_CLASS =
+            "com.android.server.apphibernation.AppHibernationService";
     private static final String PRINT_MANAGER_SERVICE_CLASS =
             "com.android.server.print.PrintManagerService";
     private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
@@ -457,7 +460,7 @@
                 }
 
                 try {
-                    Thread.sleep(checkInterval);
+                    Thread.sleep(checkInterval * 1000);
                 } catch (InterruptedException ex) {
                     continue;
                 }
@@ -1863,6 +1866,12 @@
             mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
             t.traceEnd();
 
+            if (AppHibernationService.isAppHibernationEnabled()) {
+                t.traceBegin("StartAppHibernationService");
+                mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
+                t.traceEnd();
+            }
+
             if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
                 t.traceBegin("StartGestureLauncher");
                 mSystemServiceManager.startService(GestureLauncherService.class);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index dd98c4b..09dd3e3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -538,6 +538,15 @@
     }
 
     @Test
+    public void setArcStatus() {
+        mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
+
+        mHdmiCecLocalDeviceAudioSystem.setArcStatus(false);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
+    }
+
+    @Test
     @Ignore("b/151150320")
     public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() {
         HdmiCecMessage message =
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
new file mode 100644
index 0000000..b9af82b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
@@ -0,0 +1,111 @@
+/*
+ * 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.locksettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.service.resumeonreboot.ResumeOnRebootService;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class ResumeOnRebootServiceProviderTests {
+
+    @Mock
+    Context mMockContext;
+    @Mock
+    PackageManager mMockPackageManager;
+    @Mock
+    ResolveInfo mMockResolvedInfo;
+    @Mock
+    ServiceInfo mMockServiceInfo;
+    @Mock
+    ComponentName mMockComponentName;
+    @Captor
+    ArgumentCaptor<Intent> mIntentArgumentCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mMockContext.getUserId()).thenReturn(0);
+        when(mMockResolvedInfo.serviceInfo).thenReturn(mMockServiceInfo);
+        when(mMockServiceInfo.getComponentName()).thenReturn(mMockComponentName);
+    }
+
+    @Test
+    public void noServiceFound() throws Exception {
+        when(mMockPackageManager.queryIntentServices(any(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+                null);
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNull();
+    }
+
+    @Test
+    public void serviceNotGuardedWithPermission() throws Exception {
+        ArrayList<ResolveInfo> resultList = new ArrayList<>();
+        when(mMockServiceInfo.permission).thenReturn("");
+        resultList.add(mMockResolvedInfo);
+        when(mMockPackageManager.queryIntentServices(any(), any())).thenReturn(
+                resultList);
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNull();
+    }
+
+    @Test
+    public void serviceResolved() throws Exception {
+        ArrayList<ResolveInfo> resultList = new ArrayList<>();
+        resultList.add(mMockResolvedInfo);
+        when(mMockServiceInfo.permission).thenReturn(
+                Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE);
+        when(mMockPackageManager.queryIntentServices(any(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+                resultList);
+
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNotNull();
+
+        verify(mMockPackageManager).queryIntentServices(mIntentArgumentCaptor.capture(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY));
+        assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo(
+                ResumeOnRebootService.SERVICE_INTERFACE);
+    }
+}
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 4db7ce2..df19aeb 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2051,6 +2051,7 @@
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        networkCapabilities.setSSID(TEST_SSID);
         return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
     }
 
diff --git a/services/tests/shortcutmanagerutils/OWNERS b/services/tests/shortcutmanagerutils/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e3eb0b5..3a9896a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2774,6 +2774,30 @@
     public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
 
     /**
+     * String representation of a carrier's public key used for IMSI encryption for ePDG. If this
+     * is provided, the device will use it as a fallback when no key exists on device, but the key
+     * download will still initiate.
+     * Example string:
+     *         "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+     * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+     * @hide
+     */
+    public static final String IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING =
+            "imsi_carrier_public_key_epdg_string";
+
+    /**
+     * String representation of a carrier's public key used for IMSI encryption for WLAN. If this
+     * is provided, the device will use it as a fallback when no key exists on device, but the key
+     * download will still initiate.
+     * Example string:
+     *         "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+     * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+     * @hide
+     */
+    public static final String IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING =
+            "imsi_carrier_public_key_wlan_string";
+
+    /**
      * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
      * 0 indicates that neither EPDG or WLAN is enabled.
      * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
@@ -4089,6 +4113,12 @@
             "default_rtt_mode_int";
 
     /**
+     * Indicates whether RTT is supported while roaming.
+     */
+    public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL =
+            "rtt_supported_while_roaming_bool";
+
+    /**
      * Indicates if auto-configuration server is used for the RCS config
      * Reference: GSMA RCC.14
      */
@@ -4445,6 +4475,8 @@
         sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
         sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
         sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+        sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING, null);
+        sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING, null);
         sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
                 false);
         sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
@@ -4453,6 +4485,7 @@
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
+        sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 75a79d6..4978692 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -163,8 +163,8 @@
     public String toString(){
         return "[ImsiEncryptionInfo "
                 + "mcc=" + mcc
-                + "mnc=" + mnc
-                + "publicKey=" + publicKey
+                + " mnc=" + mnc
+                + " publicKey=" + publicKey
                 + ", keyIdentifier=" + keyIdentifier
                 + ", keyType=" + keyType
                 + ", expirationTime=" + expirationTime
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index 006cca8..9cfa640 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -16,6 +16,8 @@
 
 package android.telephony.ims;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Build;
@@ -39,6 +41,7 @@
 public final class SipMessage implements Parcelable {
     // Should not be set to true for production!
     private static final boolean IS_DEBUGGING = Build.IS_ENG;
+    private static final String CRLF = "\r\n";
 
     private final String mStartLine;
     private final String mHeaderSection;
@@ -165,4 +168,19 @@
         result = 31 * result + Arrays.hashCode(mContent);
         return result;
     }
+
+    /**
+     * @return the UTF-8 encoded SIP message.
+     */
+    public @NonNull byte[] getEncodedMessage() {
+        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/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0537742..e556664 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2367,6 +2367,11 @@
     boolean setCarrierSingleRegistrationEnabledOverride(int subId, String enabled);
 
     /**
+     * Sends a device to device message; only for use through shell.
+     */
+    void sendDeviceToDeviceMessage(int message, int value);
+
+    /**
      * Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
      */
     boolean getCarrierSingleRegistrationEnabled(int subId);
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index e9227e94..eb04f69 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -131,6 +131,10 @@
         assertThat(platformCompat.isChangeEnabled(TEST_CHANGE_ID, appInfo)).isEqualTo(params.result)
     }
 
-    private fun command(command: String) =
-            FileReader(uiAutomation.executeShellCommand(command).fileDescriptor).readText()
+    private fun command(command: String): String {
+        val fileDescriptor = uiAutomation.executeShellCommand(command)
+        return String(ParcelFileDescriptor.AutoCloseInputStream(fileDescriptor).use {
+            inputStream -> inputStream.readBytes()
+        })
+    }
 }
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 9ba56e4..91fcbc0 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -67,6 +67,7 @@
         val caps = NetworkCapabilities().apply {
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+            setSSID(ssid)
         }
         return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
     }
diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/tests/net/java/android/net/QosSocketFilterTest.java
new file mode 100644
index 0000000..ad58960
--- /dev/null
+++ b/tests/net/java/android/net/QosSocketFilterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class QosSocketFilterTest {
+
+    @Test
+    public void testPortExactMatch() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertTrue(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 10, 10));
+
+    }
+
+    @Test
+    public void testPortLessThanStart() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 8), addressB, 10, 10));
+    }
+
+    @Test
+    public void testPortGreaterThanEnd() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 18), addressB, 10, 10));
+    }
+
+    @Test
+    public void testPortBetweenStartAndEnd() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertTrue(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 8, 18));
+    }
+
+    @Test
+    public void testAddressesDontMatch() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 10, 10));
+    }
+}
+
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index c783629..19f9641 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -21,7 +21,6 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -44,6 +43,7 @@
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
+import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
@@ -146,7 +146,7 @@
     private static final String IMSI_2 = "310260";
     private static final String TEST_SSID = "AndroidAP";
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
+    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
     private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
     private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
 
@@ -291,7 +291,6 @@
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
 
-
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectDefaultSettings();
@@ -567,61 +566,6 @@
     }
 
     @Test
-    public void testUid3gWimaxCombinedByTemplate() throws Exception {
-        // pretend that network comes online
-        expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(buildEmptyStats());
-
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
-        // create some traffic
-        incrementCurrentTime(HOUR_IN_MILLIS);
-        expectDefaultSettings();
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-        mService.incrementOperationCount(UID_RED, 0xF00D, 5);
-
-        forcePollAndWaitForIdle();
-
-        // verify service recorded history
-        assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
-
-
-        // now switch over to wimax network
-        incrementCurrentTime(HOUR_IN_MILLIS);
-        expectDefaultSettings();
-        states = new NetworkState[] {buildWimaxState(TEST_IFACE2)};
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-
-        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-        forcePollAndWaitForIdle();
-
-
-        // create traffic on second network
-        incrementCurrentTime(HOUR_IN_MILLIS);
-        expectDefaultSettings();
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
-                .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
-                .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
-                .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
-        mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
-
-        forcePollAndWaitForIdle();
-
-        // verify that ALL_MOBILE template combines both
-        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
-    }
-
-    @Test
     public void testMobileStatsByRatType() throws Exception {
         final NetworkTemplate template3g =
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
@@ -1503,6 +1447,7 @@
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+        capabilities.setSSID(TEST_SSID);
         return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
     }
 
@@ -1524,17 +1469,6 @@
         return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
     }
 
-    private static NetworkState buildWimaxState(@NonNull String iface) {
-        final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
-        final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(iface);
-        final NetworkCapabilities capabilities = new NetworkCapabilities();
-        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
-        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
-        return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null);
-    }
-
     private NetworkStats buildEmptyStats() {
         return new NetworkStats(getElapsedRealtime(), 0);
     }
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 29cfdb6f..f0cdde3 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -138,11 +139,16 @@
     private final IBinder mMockIBinder = mock(IBinder.class);
 
     public VcnManagementServiceTest() throws Exception {
-        setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
-        setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
         setupSystemService(
-                mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
-        setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+                mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+        setupSystemService(
+                mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+        setupSystemService(
+                mMockContext,
+                mSubMgr,
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+                SubscriptionManager.class);
+        setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
 
         doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
 
@@ -186,11 +192,6 @@
         mTestLooper.dispatchAll();
     }
 
-    private void setupSystemService(Object service, String name, Class<?> serviceClass) {
-        doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
-        doReturn(service).when(mMockContext).getSystemService(name);
-    }
-
     private void setupMockedCarrierPrivilege(boolean isPrivileged) {
         doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
                 .when(mSubMgr)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
new file mode 100644
index 0000000..4ecd215
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+        final VcnGatewayConnection vgc =
+                new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+
+        vgc.setIsRunning(false);
+        vgc.transitionTo(vgc.mDisconnectedState);
+        mTestLooper.dispatchAll();
+
+        assertNull(vgc.getCurrentState());
+    }
+
+    @Test
+    public void testNetworkChangesTriggerStateTransitions() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertNull(mGatewayConnection.getCurrentState());
+        verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
new file mode 100644
index 0000000..1725dd9
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+
+import com.android.server.IpSecService;
+
+import org.junit.Before;
+
+import java.util.UUID;
+
+public class VcnGatewayConnectionTestBase {
+    protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+    protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
+    protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
+            new UnderlyingNetworkRecord(
+                    new Network(0),
+                    new NetworkCapabilities(),
+                    new LinkProperties(),
+                    false /* blocked */);
+    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
+            new UnderlyingNetworkRecord(
+                    new Network(1),
+                    new NetworkCapabilities(),
+                    new LinkProperties(),
+                    false /* blocked */);
+
+    @NonNull protected final Context mContext;
+    @NonNull protected final TestLooper mTestLooper;
+    @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+    @NonNull protected final VcnContext mVcnContext;
+    @NonNull protected final VcnGatewayConnectionConfig mConfig;
+    @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
+    @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+    @NonNull protected final IpSecService mIpSecSvc;
+
+    protected VcnGatewayConnection mGatewayConnection;
+
+    public VcnGatewayConnectionTestBase() {
+        mContext = mock(Context.class);
+        mTestLooper = new TestLooper();
+        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+        mVcnContext = mock(VcnContext.class);
+        mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+        mDeps = mock(VcnGatewayConnection.Dependencies.class);
+        mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+
+        mIpSecSvc = mock(IpSecService.class);
+        setupIpSecManager(mContext, mIpSecSvc);
+
+        doReturn(mContext).when(mVcnContext).getContext();
+        doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+        doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+        doReturn(mUnderlyingNetworkTracker)
+                .when(mDeps)
+                .newUnderlyingNetworkTracker(any(), any(), any());
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        IpSecTunnelInterfaceResponse resp =
+                new IpSecTunnelInterfaceResponse(
+                        IpSecManager.Status.OK,
+                        TEST_IPSEC_TUNNEL_RESOURCE_ID,
+                        TEST_IPSEC_TUNNEL_IFACE);
+        doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+
+        mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
new file mode 100644
index 0000000..2b10806
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.IpSecManager;
+
+import com.android.server.IpSecService;
+
+public class VcnTestUtils {
+    /** Mock system services by directly mocking the *Manager interface. */
+    public static void setupSystemService(
+            Context mockContext, Object service, String name, Class<?> serviceClass) {
+        doReturn(name).when(mockContext).getSystemServiceName(serviceClass);
+        doReturn(service).when(mockContext).getSystemService(name);
+    }
+
+    /** Mock IpSecService by mocking the underlying service binder. */
+    public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) {
+        doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class);
+
+        final IpSecManager ipSecMgr = new IpSecManager(mockContext, service);
+        doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE);
+
+        // Return to ensure this doesn't get reaped.
+        return ipSecMgr;
+    }
+}
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index afe91cd..15088fc 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
 
 # Copyright (C) 2018 The Android Open Source Project
 #
@@ -33,9 +34,6 @@
 import re, sys, codecs
 import lxml.etree as ET
 
-reload(sys)
-sys.setdefaultencoding('utf8')
-
 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
 
 def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
@@ -118,7 +116,7 @@
         raw = f.read()
         if len(raw.strip()) == 0:
             return warnings
-        tree = ET.fromstring(raw)
+        tree = ET.fromstring(bytes(raw, encoding='utf-8'))
         root = tree #tree.getroot()
 
     last_comment = None
@@ -231,6 +229,6 @@
 
 if len(after) > 0:
     for a in sorted(after.keys()):
-        print after[a]
-        print
+        print(after[a])
+        print()
     sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index bd80bb4..bd05698 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
 LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
 git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
-    python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+    python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
 done