Merge "Suppress deprecation warnings in LegacyTypeTrackerTest."
diff --git a/apex/Android.bp b/apex/Android.bp
index c381c0f..3a63c805 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -63,6 +63,63 @@
     "--hide-annotation android.annotation.Hide " +
     "--hide InternalClasses " // com.android.* classes are okay in this interface
 
+// Defaults for mainline module provided java_sdk_library instances.
+java_defaults {
+    name: "framework-module-defaults",
+
+    // Additional annotations used for compiling both the implementation and the
+    // stubs libraries.
+    libs: ["framework-annotations-lib"],
+
+    // Enable api lint. This will eventually become the default for java_sdk_library
+    // but it cannot yet be turned on because some usages have not been cleaned up.
+    // TODO(b/156126315) - Remove when no longer needed.
+    api_lint: {
+        enabled: true,
+    },
+
+    // The API scope specific properties.
+    public: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+    system: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+    module_lib: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+
+    // Configure framework module specific metalava options.
+    droiddoc_options: [mainline_stubs_args],
+
+    // The stub libraries must be visible to frameworks/base so they can be combined
+    // into API specific libraries.
+    stubs_library_visibility: [
+        "//frameworks/base", // Framework
+    ],
+
+    // Set the visibility of the modules creating the stubs source.
+    stubs_source_visibility: [
+        // Ignore any visibility rules specified on the java_sdk_library when
+        // setting the visibility of the stubs source modules.
+        "//visibility:override",
+
+        // Currently, the stub source is not required for anything other than building
+        // the stubs library so is private to avoid misuse.
+        "//visibility:private",
+    ],
+
+    // Collates API usages from each module for further analysis.
+    plugins: ["java_api_finder"],
+
+    // Mainline modules should only rely on 'module_lib' APIs provided by other modules
+    // and the non updatable parts of the platform.
+    sdk_version: "module_current",
+}
+
 stubs_defaults {
     name: "framework-module-stubs-defaults-publicapi",
     args: mainline_framework_stubs_args,
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index dbb5bd3d..fdb078e 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -39,7 +39,7 @@
 
 sdk {
     name: "sdkextensions-sdk",
-    java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ],
+    java_sdk_libs: [ "framework-sdkextensions" ],
 }
 
 apex_key {
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 6a78711..b8aad7d 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -25,14 +25,18 @@
     visibility: [ "//frameworks/base" ] // For the "global" stubs.
 }
 
-java_library {
+java_sdk_library {
     name: "framework-sdkextensions",
     srcs: [ ":framework-sdkextensions-sources" ],
-    sdk_version: "system_current",
-    libs: [ "framework-annotations-lib" ],
+    defaults: ["framework-module-defaults"],
+
+    // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
+    // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
+    // modules to java_sdk_library.
+    naming_scheme: "framework-modules",
+
     permitted_packages: [ "android.os.ext" ],
     installable: true,
-    plugins: ["java_api_finder"],
     visibility: [
         "//frameworks/base/apex/sdkextensions",
         "//frameworks/base/apex/sdkextensions/testing",
@@ -43,75 +47,3 @@
         "test_com.android.sdkext",
     ],
 }
-
-stubs_defaults {
-    name: "framework-sdkextensions-stubs-defaults",
-    srcs: [ ":framework-sdkextensions-sources" ],
-    libs: [ "framework-annotations-lib" ],
-    dist: { dest: "framework-sdkextensions.txt" },
-}
-
-droidstubs {
-    name: "framework-sdkextensions-stubs-srcs-publicapi",
-    defaults: [
-        "framework-module-stubs-defaults-publicapi",
-        "framework-sdkextensions-stubs-defaults",
-    ],
-}
-
-droidstubs {
-    name: "framework-sdkextensions-stubs-srcs-systemapi",
-    defaults: [
-        "framework-module-stubs-defaults-systemapi",
-        "framework-sdkextensions-stubs-defaults",
-    ],
-}
-
-droidstubs {
-    name: "framework-sdkextensions-api-module_libs_api",
-    defaults: [
-        "framework-module-api-defaults-module_libs_api",
-        "framework-sdkextensions-stubs-defaults",
-    ],
-}
-
-droidstubs {
-    name: "framework-sdkextensions-stubs-srcs-module_libs_api",
-    defaults: [
-        "framework-module-stubs-defaults-module_libs_api",
-        "framework-sdkextensions-stubs-defaults",
-    ],
-}
-
-java_library {
-    name: "framework-sdkextensions-stubs-publicapi",
-    srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
-    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
-    visibility: [
-        "//frameworks/base", // Framework
-        "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
-    ],
-    dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
-    name: "framework-sdkextensions-stubs-systemapi",
-    srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
-    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
-    visibility: [
-        "//frameworks/base", // Framework
-        "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
-    ],
-    dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
-    name: "framework-sdkextensions-stubs-module_libs_api",
-    srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
-    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
-    visibility: [
-        "//frameworks/base", // Framework
-        "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
-    ],
-    dist: { dest: "framework-sdkextensions.jar" },
-}
diff --git a/api/current.txt b/api/current.txt
index e63cb45..8163426 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41304,6 +41304,7 @@
     method public int getPurposes();
     method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
+    method public boolean isDevicePropertiesAttestationIncluded();
     method @NonNull public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
@@ -41325,6 +41326,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(@NonNull java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(@NonNull java.math.BigInteger);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(@NonNull javax.security.auth.x500.X500Principal);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setDevicePropertiesAttestationIncluded(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
diff --git a/cmds/device_config/Android.bp b/cmds/device_config/Android.bp
new file mode 100644
index 0000000..67e014a
--- /dev/null
+++ b/cmds/device_config/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2018 The Android Open Source Project
+//
+
+sh_binary {
+    name: "device_config",
+    src: "device_config",
+}
diff --git a/cmds/device_config/Android.mk b/cmds/device_config/Android.mk
deleted file mode 100644
index 4041e01..0000000
--- a/cmds/device_config/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2018 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := device_config
-LOCAL_SRC_FILES := device_config
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d9d697a..52e9385 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5884,11 +5884,11 @@
  * Logs when a data stall event occurs.
  *
  * Log from:
- *     frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+ *     packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
  */
 message DataStallEvent {
     // Data stall evaluation type.
-    // See frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+    // See packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
     // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*.
     optional int32 evaluation_type = 1;
     // See definition in data_stall_event.proto.
@@ -5901,6 +5901,10 @@
     optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES];
     // See definition in data_stall_event.proto.
     optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
+    // The tcp packets fail rate from the latest tcp polling.
+    optional int32 tcp_fail_rate = 7;
+    // Number of packets sent since the last received packet.
+    optional int32 tcp_sent_since_last_recv = 8;
 }
 
 /*
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 9a17346..2888fbd 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -110,8 +110,9 @@
      * off to save power. Scanning is resumed when screen is turned on again. To avoid this, use
      * {@link #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}.
      * <p>
-     * An app must hold
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * An app must have
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
+     * in order to get results. An App targeting Android Q or later must have
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
      * in order to get results.
      *
@@ -129,8 +130,9 @@
      * resumed when screen is turned on again. To avoid this, do filetered scanning by
      * using proper {@link ScanFilter}.
      * <p>
-     * An app must hold
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * An app must have
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
+     * in order to get results. An App targeting Android Q or later must have
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
      * in order to get results.
      *
@@ -150,8 +152,9 @@
      * the PendingIntent. Use this method of scanning if your process is not always running and it
      * should be started when scan results are available.
      * <p>
-     * An app must hold
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * An app must have
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
+     * in order to get results. An App targeting Android Q or later must have
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
      * in order to get results.
      * <p>
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 836624b..407ff04 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -101,6 +101,7 @@
     private final boolean mIsBypassable; // Defaults in builder
     private final boolean mIsMetered; // Defaults in builder
     private final int mMaxMtu; // Defaults in builder
+    private final boolean mIsRestrictedToTestNetworks;
 
     private Ikev2VpnProfile(
             int type,
@@ -116,7 +117,8 @@
             @NonNull List<String> allowedAlgorithms,
             boolean isBypassable,
             boolean isMetered,
-            int maxMtu) {
+            int maxMtu,
+            boolean restrictToTestNetworks) {
         super(type);
 
         checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
@@ -140,6 +142,7 @@
         mIsBypassable = isBypassable;
         mIsMetered = isMetered;
         mMaxMtu = maxMtu;
+        mIsRestrictedToTestNetworks = restrictToTestNetworks;
 
         validate();
     }
@@ -329,6 +332,15 @@
         return mMaxMtu;
     }
 
+    /**
+     * Returns whether or not this VPN profile is restricted to test networks.
+     *
+     * @hide
+     */
+    public boolean isRestrictedToTestNetworks() {
+        return mIsRestrictedToTestNetworks;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(
@@ -345,7 +357,8 @@
                 mAllowedAlgorithms,
                 mIsBypassable,
                 mIsMetered,
-                mMaxMtu);
+                mMaxMtu,
+                mIsRestrictedToTestNetworks);
     }
 
     @Override
@@ -368,7 +381,8 @@
                 && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
                 && mIsBypassable == other.mIsBypassable
                 && mIsMetered == other.mIsMetered
-                && mMaxMtu == other.mMaxMtu;
+                && mMaxMtu == other.mMaxMtu
+                && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
     }
 
     /**
@@ -381,7 +395,8 @@
      */
     @NonNull
     public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
-        final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */);
+        final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
+                mIsRestrictedToTestNetworks);
         profile.type = mType;
         profile.server = mServerAddr;
         profile.ipsecIdentifier = mUserIdentity;
@@ -449,6 +464,9 @@
         builder.setBypassable(profile.isBypassable);
         builder.setMetered(profile.isMetered);
         builder.setMaxMtu(profile.maxMtu);
+        if (profile.isRestrictedToTestNetworks) {
+            builder.restrictToTestNetworks();
+        }
 
         switch (profile.type) {
             case TYPE_IKEV2_IPSEC_USER_PASS:
@@ -621,6 +639,7 @@
         private boolean mIsBypassable = false;
         private boolean mIsMetered = true;
         private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
+        private boolean mIsRestrictedToTestNetworks = false;
 
         /**
          * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -842,6 +861,21 @@
         }
 
         /**
+         * Restricts this profile to use test networks (only).
+         *
+         * <p>This method is for testing only, and must not be used by apps. Calling
+         * provisionVpnProfile() with a profile where test-network usage is enabled will require the
+         * MANAGE_TEST_NETWORKS permission.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder restrictToTestNetworks() {
+            mIsRestrictedToTestNetworks = true;
+            return this;
+        }
+
+        /**
          * Validates, builds and provisions the VpnProfile.
          *
          * @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -862,7 +896,8 @@
                     mAllowedAlgorithms,
                     mIsBypassable,
                     mIsMetered,
-                    mMaxMtu);
+                    mMaxMtu,
+                    mIsRestrictedToTestNetworks);
         }
     }
 }
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 6632ca5..9b360ed 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -118,7 +118,21 @@
      * by this Parcelable object instance.
      */
     public @ContentsFlags int describeContents();
-    
+
+    /**
+     * 'Stable' means this parcelable is guaranteed to be stable for multiple years.
+     * It must be guaranteed by setting stability field in aidl_interface,
+     * OR explicitly override this method from @JavaOnlyStableParcelable marked Parcelable.
+     * WARNING: isStable() is only expected to be overridden by auto-generated code,
+     * OR @JavaOnlyStableParcelable marked Parcelable only if there is guaranteed to
+     * be only once copy of the parcelable on the system.
+     * @return true if this parcelable is stable.
+     * @hide
+     */
+    default boolean isStable() {
+        return false;
+    }
+
     /**
      * Flatten this object in to a Parcel.
      * 
diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java
index d6afd04..bde7ec1 100644
--- a/core/java/android/os/Registrant.java
+++ b/core/java/android/os/Registrant.java
@@ -46,7 +46,7 @@
     {
         internalNotifyRegistrant (null, null);
     }
-    
+
     @UnsupportedAppUsage
     public void
     notifyResult(Object result)
@@ -81,9 +81,7 @@
             Message msg = Message.obtain();
 
             msg.what = what;
-            
             msg.obj = new AsyncResult(userObj, result, exception);
-            
             h.sendMessage(msg);
         }
     }
@@ -126,4 +124,3 @@
     int             what;
     Object          userObj;
 }
-
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
index 98f949b..53e0ae4 100644
--- a/core/java/android/os/RegistrantList.java
+++ b/core/java/android/os/RegistrantList.java
@@ -42,9 +42,9 @@
     {
         // if the handler is already in the registrant list, remove it
         remove(h);
-        add(new Registrant(h, what, obj));        
+        add(new Registrant(h, what, obj));
     }
-    
+
     @UnsupportedAppUsage
     public synchronized void
     add(Registrant r)
@@ -59,7 +59,7 @@
     {
         for (int i = registrants.size() - 1; i >= 0 ; i--) {
             Registrant  r = (Registrant) registrants.get(i);
-            
+
             if (r.refH == null) {
                 registrants.remove(i);
             }
@@ -88,7 +88,7 @@
             r.internalNotifyRegistrant(result, exception);
        }
     }
-    
+
     @UnsupportedAppUsage
     public /*synchronized*/ void
     notifyRegistrants()
@@ -109,14 +109,14 @@
         internalNotifyRegistrants (result, null);
     }
 
-    
+
     @UnsupportedAppUsage
     public /*synchronized*/ void
     notifyRegistrants(AsyncResult ar)
     {
         internalNotifyRegistrants(ar.result, ar.exception);
     }
-    
+
     @UnsupportedAppUsage
     public synchronized void
     remove(Handler h)
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 9cbb035..f44f24a 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.annotation.InterpolatorRes;
 import android.annotation.NonNull;
@@ -246,6 +248,8 @@
 
     private AccessibilityEventSender mAccessibilityEventSender;
 
+    private ObjectAnimator mLastProgressAnimator;
+
     /**
      * Create a new progress bar with range 0...100 and initial progress of 0.
      * @param context the application environment
@@ -1544,8 +1548,19 @@
             animator.setAutoCancel(true);
             animator.setDuration(PROGRESS_ANIM_DURATION);
             animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR);
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mLastProgressAnimator = null;
+                }
+            });
             animator.start();
+            mLastProgressAnimator = animator;
         } else {
+            if (isPrimary && mLastProgressAnimator != null) {
+                mLastProgressAnimator.cancel();
+                mLastProgressAnimator = null;
+            }
             setVisualProgress(id, scale);
         }
 
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 829bd8a..8ea5aa8 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -136,13 +136,19 @@
     public boolean isMetered = false;                            // 21
     public int maxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;      // 22
     public boolean areAuthParamsInline = false;                  // 23
+    public final boolean isRestrictedToTestNetworks;             // 24
 
     // Helper fields.
     @UnsupportedAppUsage
     public transient boolean saveLogin = false;
 
     public VpnProfile(String key) {
+        this(key, false);
+    }
+
+    public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
         this.key = key;
+        this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
     }
 
     @UnsupportedAppUsage
@@ -171,6 +177,7 @@
         isMetered = in.readBoolean();
         maxMtu = in.readInt();
         areAuthParamsInline = in.readBoolean();
+        isRestrictedToTestNetworks = in.readBoolean();
     }
 
     /**
@@ -220,6 +227,7 @@
         out.writeBoolean(isMetered);
         out.writeInt(maxMtu);
         out.writeBoolean(areAuthParamsInline);
+        out.writeBoolean(isRestrictedToTestNetworks);
     }
 
     /**
@@ -237,12 +245,21 @@
             String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1);
             // Acceptable numbers of values are:
             // 14-19: Standard profile, with option for serverCert, proxy
-            // 24: Standard profile with serverCert, proxy and platform-VPN parameters.
-            if ((values.length < 14 || values.length > 19) && values.length != 24) {
+            // 24: Standard profile with serverCert, proxy and platform-VPN parameters
+            // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+            if ((values.length < 14 || values.length > 19)
+                    && values.length != 24 && values.length != 25) {
                 return null;
             }
 
-            VpnProfile profile = new VpnProfile(key);
+            final boolean isRestrictedToTestNetworks;
+            if (values.length >= 25) {
+                isRestrictedToTestNetworks = Boolean.parseBoolean(values[24]);
+            } else {
+                isRestrictedToTestNetworks = false;
+            }
+
+            VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
             profile.name = values[0];
             profile.type = Integer.parseInt(values[1]);
             if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -283,6 +300,8 @@
                 profile.areAuthParamsInline = Boolean.parseBoolean(values[23]);
             }
 
+            // isRestrictedToTestNetworks (values[24]) assigned as part of the constructor
+
             profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
             return profile;
         } catch (Exception e) {
@@ -330,6 +349,7 @@
         builder.append(VALUE_DELIMITER).append(isMetered);
         builder.append(VALUE_DELIMITER).append(maxMtu);
         builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
+        builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
 
         return builder.toString().getBytes(StandardCharsets.UTF_8);
     }
@@ -421,7 +441,8 @@
         return Objects.hash(
             key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
             l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
-            proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline);
+            proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
+            isRestrictedToTestNetworks);
     }
 
     /** Checks VPN profiles for interior equality. */
@@ -453,7 +474,8 @@
                 && isBypassable == other.isBypassable
                 && isMetered == other.isMetered
                 && maxMtu == other.maxMtu
-                && areAuthParamsInline == other.areAuthParamsInline;
+                && areAuthParamsInline == other.areAuthParamsInline
+                && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
     }
 
     @NonNull
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index b30fed6..544340e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -693,6 +693,7 @@
     char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
     char voldDecryptBuf[PROPERTY_VALUE_MAX];
+    char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
     enum {
       kEMDefault,
       kEMIntPortable,
@@ -807,6 +808,16 @@
     addOption("-verbose:gc");
     //addOption("-verbose:class");
 
+    // On Android, we always want to allow loading the PerfettoHprof plugin.
+    // Even with this option set, we will still only actually load the plugin
+    // if we are on a userdebug build or the app is debuggable or profileable.
+    // This is enforced in art/runtime/runtime.cc.
+    //
+    // We want to be able to disable this, because this does not work on host,
+    // and we do not want to enable it in tests.
+    parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=",
+                       "true");
+
     if (primary_zygote) {
         addOption("-Xprimaryzygote");
     }
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 9cc04d3..d5733e3 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -39,7 +39,7 @@
     <!-- Albania: 5 digits, known short codes listed -->
     <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
 
-    <!-- Argentia: 5 digits, known short codes listed -->
+    <!-- Argentina: 5 digits, known short codes listed -->
     <shortcode country="ar" pattern="\\d{5}" free="11711|28291" />
 
     <!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
new file mode 100644
index 0000000..2194d4b
--- /dev/null
+++ b/core/tests/hdmitests/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "HdmiCecTests",
+    // Include all test java files
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "truth-prebuilt",
+    ],
+    libs: ["android.test.runner"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/core/tests/hdmitests/Android.mk b/core/tests/hdmitests/Android.mk
deleted file mode 100644
index f155feb..0000000
--- a/core/tests/hdmitests/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils truth-prebuilt
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_PACKAGE_NAME := HdmiCecTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/packagemanagertests/Android.bp b/core/tests/packagemanagertests/Android.bp
new file mode 100644
index 0000000..6f39af8
--- /dev/null
+++ b/core/tests/packagemanagertests/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+    name: "FrameworksCorePackageManagerTests",
+    // We only want this apk build for tests.
+    // Include all test java files.
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "mockito-target-minus-junit4",
+    ],
+    libs: ["android.test.runner"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/core/tests/packagemanagertests/Android.mk b/core/tests/packagemanagertests/Android.mk
deleted file mode 100644
index 8c00d14..0000000
--- a/core/tests/packagemanagertests/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    frameworks-base-testutils \
-    mockito-target-minus-junit4
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp
new file mode 100644
index 0000000..7f56992
--- /dev/null
+++ b/core/tests/privacytests/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+    name: "FrameworksPrivacyLibraryTests",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "junit",
+        "rappor-tests",
+        "androidx.test.rules",
+        "truth-prebuilt",
+    ],
+    libs: ["android.test.runner"],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/privacytests/Android.mk b/core/tests/privacytests/Android.mk
deleted file mode 100644
index 7765977..0000000
--- a/core/tests/privacytests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit rappor-tests androidx.test.rules truth-prebuilt
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_PACKAGE_NAME := FrameworksPrivacyLibraryTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp
index ca655f1..4b43b41 100644
--- a/core/xsd/vts/Android.bp
+++ b/core/xsd/vts/Android.bp
@@ -40,3 +40,7 @@
     ],
     test_config: "vts_permission_validate_test.xml",
 }
+
+vts_config {
+    name: "VtsValidatePermission",
+}
diff --git a/core/xsd/vts/Android.mk b/core/xsd/vts/Android.mk
deleted file mode 100644
index a5754a4..0000000
--- a/core/xsd/vts/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsValidatePermission
-include test/vts/tools/build/Android.host_config.mk
diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp
new file mode 100644
index 0000000..94e6a80
--- /dev/null
+++ b/data/fonts/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2011 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.
+
+prebuilt_font {
+    name: "DroidSansMono.ttf",
+    src: "DroidSansMono.ttf",
+    required: [
+        "DroidSans.ttf",
+        "DroidSans-Bold.ttf",
+    ],
+}
+
+prebuilt_font {
+    name: "AndroidClock.ttf",
+    src: "AndroidClock.ttf",
+}
+
+/////////////////////////////////
+// Copies the font configuration file into system/etc for the product as fonts.xml.
+// Additional fonts should be installed to /product/fonts/ alongside a corresponding
+// fonts_customiztion.xml in /product/etc/
+prebuilt_etc {
+    name: "fonts.xml",
+    src: "fonts.xml",
+}
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 4226e08..e22b723 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -12,9 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# We have to use BUILD_PREBUILT instead of PRODUCT_COPY_FIES,
-# because MINIMAL_FONT_FOOTPRINT is only available in Android.mks.
-
 LOCAL_PATH := $(call my-dir)
 
 ##########################################
@@ -37,61 +34,7 @@
 ##########################################
 $(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf))
 $(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Regular.ttf,NotoSerif-Regular.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Bold.ttf,NotoSerif-Bold.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf))
-$(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf))
 
-extra_font_files := \
-    DroidSans.ttf \
-    DroidSans-Bold.ttf
-
-################################
-# Use DroidSansMono to hang extra_font_files on
-include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansMono.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-LOCAL_REQUIRED_MODULES := $(extra_font_files)
-include $(BUILD_PREBUILT)
-extra_font_files :=
-
-################################
-# Build the rest of font files as prebuilt.
-
-# $(1): The source file name in LOCAL_PATH.
-#       It also serves as the module name and the dest file name.
-define build-one-font-module
-$(eval include $(CLEAR_VARS))\
-$(eval LOCAL_MODULE := $(1))\
-$(eval LOCAL_SRC_FILES := $(1))\
-$(eval LOCAL_MODULE_CLASS := ETC)\
-$(eval LOCAL_MODULE_TAGS := optional)\
-$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\
-$(eval include $(BUILD_PREBUILT))
-endef
-
-font_src_files := \
-    AndroidClock.ttf
-
-$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
-
-build-one-font-module :=
-font_src_files :=
-
-################################
-# Copies the font configuration file into system/etc for the product as fonts.xml.
-# Additional fonts should be installed to /product/fonts/ alongside a corresponding
-# fonts_customiztion.xml in /product/etc/
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := fonts.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_PREBUILT_MODULE_FILE := frameworks/base/data/fonts/fonts.xml
-
-include $(BUILD_PREBUILT)
 
 # Run sanity tests on fonts on checkbuild
 checkbuild: fontchain_lint
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 91aac83..11775ca 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -17,11 +17,10 @@
 package android.security.keystore;
 
 import android.annotation.Nullable;
+import android.os.Build;
 import android.security.Credentials;
-import android.security.GateKeeper;
 import android.security.KeyPairGeneratorSpec;
 import android.security.KeyStore;
-import android.security.KeyStoreException;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterCertificateChain;
@@ -52,6 +51,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
@@ -494,6 +494,20 @@
         if (challenge != null) {
             KeymasterArguments args = new KeymasterArguments();
             args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
+
+            if (mSpec.isDevicePropertiesAttestationIncluded()) {
+                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
+                        Build.BRAND.getBytes(StandardCharsets.UTF_8));
+                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
+                        Build.DEVICE.getBytes(StandardCharsets.UTF_8));
+                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
+                        Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
+                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
+                        Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
+                args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
+                        Build.MODEL.getBytes(StandardCharsets.UTF_8));
+            }
+
             return getAttestationChain(privateKeyAlias, keyPair, args);
         }
 
@@ -603,8 +617,14 @@
     private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
             KeyPair keyPair, KeymasterArguments args)
                     throws ProviderException {
-        KeymasterCertificateChain outChain = new KeymasterCertificateChain();
-        int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
+        final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
+        final int errorCode;
+        if (mSpec.isDevicePropertiesAttestationIncluded()
+                && mSpec.getAttestationChallenge() == null) {
+            throw new ProviderException("An attestation challenge must be provided when requesting "
+                    + "device properties attestation.");
+        }
+        errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
         if (errorCode != KeyStore.NO_ERROR) {
             throw new ProviderException("Failed to generate attestation certificate chain",
                     KeyStore.getKeyStoreException(errorCode));
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 630a6dd..e7e410a 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -24,6 +24,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricPrompt;
+import android.os.Build;
 import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.text.TextUtils;
@@ -264,6 +265,7 @@
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mUserPresenceRequired;
     private final byte[] mAttestationChallenge;
+    private final boolean mDevicePropertiesAttestationIncluded;
     private final boolean mUniqueIdIncluded;
     private final boolean mUserAuthenticationValidWhileOnBody;
     private final boolean mInvalidatedByBiometricEnrollment;
@@ -301,6 +303,7 @@
             int userAuthenticationValidityDurationSeconds,
             boolean userPresenceRequired,
             byte[] attestationChallenge,
+            boolean devicePropertiesAttestationIncluded,
             boolean uniqueIdIncluded,
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
@@ -350,6 +353,7 @@
         mUserPresenceRequired = userPresenceRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
         mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
+        mDevicePropertiesAttestationIncluded = devicePropertiesAttestationIncluded;
         mUniqueIdIncluded = uniqueIdIncluded;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
@@ -644,6 +648,21 @@
     }
 
     /**
+     * Returns {@code true} if attestation for the base device properties ({@link Build#BRAND},
+     * {@link Build#DEVICE}, {@link Build#MANUFACTURER}, {@link Build#MODEL}, {@link Build#PRODUCT})
+     * was requested to be added in the attestation certificate for the generated key.
+     *
+     * {@link javax.crypto.KeyGenerator#generateKey()} will throw
+     * {@link java.security.ProviderException} if device properties attestation fails or is not
+     * supported.
+     *
+     * @see Builder#setDevicePropertiesAttestationIncluded(boolean)
+     */
+    public boolean isDevicePropertiesAttestationIncluded() {
+        return mDevicePropertiesAttestationIncluded;
+    }
+
+    /**
      * @hide This is a system-only API
      *
      * Returns {@code true} if the attestation certificate will contain a unique ID field.
@@ -734,6 +753,7 @@
         private int mUserAuthenticationValidityDurationSeconds = -1;
         private boolean mUserPresenceRequired = false;
         private byte[] mAttestationChallenge = null;
+        private boolean mDevicePropertiesAttestationIncluded = false;
         private boolean mUniqueIdIncluded = false;
         private boolean mUserAuthenticationValidWhileOnBody;
         private boolean mInvalidatedByBiometricEnrollment = true;
@@ -797,6 +817,8 @@
                 sourceSpec.getUserAuthenticationValidityDurationSeconds();
             mUserPresenceRequired = sourceSpec.isUserPresenceRequired();
             mAttestationChallenge = sourceSpec.getAttestationChallenge();
+            mDevicePropertiesAttestationIncluded =
+                    sourceSpec.isDevicePropertiesAttestationIncluded();
             mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
             mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
             mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment();
@@ -1252,6 +1274,31 @@
         }
 
         /**
+         * Sets whether to include the base device properties in the attestation certificate.
+         *
+         * <p>If {@code attestationChallenge} is not {@code null}, the public key certificate for
+         * this key pair will contain an extension that describes the details of the key's
+         * configuration and authorizations, including the device properties values (brand, device,
+         * manufacturer, model, product). These should be the same as in ({@link Build#BRAND},
+         * {@link Build#DEVICE}, {@link Build#MANUFACTURER}, {@link Build#MODEL},
+         * {@link Build#PRODUCT}). The attestation certificate chain can
+         * be retrieved with {@link java.security.KeyStore#getCertificateChain(String)}.
+         *
+         * <p> If {@code attestationChallenge} is {@code null}, the public key certificate for
+         * this key pair will not contain the extension with the requested attested values.
+         *
+         * <p> {@link javax.crypto.KeyGenerator#generateKey()} will throw
+         * {@link java.security.ProviderException} if device properties attestation fails or is not
+         * supported.
+         */
+        @NonNull
+        public Builder setDevicePropertiesAttestationIncluded(
+                boolean devicePropertiesAttestationIncluded) {
+            mDevicePropertiesAttestationIncluded = devicePropertiesAttestationIncluded;
+            return this;
+        }
+
+        /**
          * @hide Only system apps can use this method.
          *
          * Sets whether to include a temporary unique ID field in the attestation certificate.
@@ -1360,6 +1407,7 @@
                     mUserAuthenticationValidityDurationSeconds,
                     mUserPresenceRequired,
                     mAttestationChallenge,
+                    mDevicePropertiesAttestationIncluded,
                     mUniqueIdIncluded,
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index d8030fb..0518f45 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -16,8 +16,8 @@
 
 package android.security.keystore;
 
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.math.BigInteger;
 import java.security.spec.AlgorithmParameterSpec;
@@ -99,6 +99,7 @@
         out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds());
         out.writeBoolean(mSpec.isUserPresenceRequired());
         out.writeByteArray(mSpec.getAttestationChallenge());
+        out.writeBoolean(mSpec.isDevicePropertiesAttestationIncluded());
         out.writeBoolean(mSpec.isUniqueIdIncluded());
         out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
         out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
@@ -154,6 +155,7 @@
         final int userAuthenticationValidityDurationSeconds = in.readInt();
         final boolean userPresenceRequired = in.readBoolean();
         final byte[] attestationChallenge = in.createByteArray();
+        final boolean devicePropertiesAttestationIncluded = in.readBoolean();
         final boolean uniqueIdIncluded = in.readBoolean();
         final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
         final boolean invalidatedByBiometricEnrollment = in.readBoolean();
@@ -185,6 +187,7 @@
                 userAuthenticationValidityDurationSeconds,
                 userPresenceRequired,
                 attestationChallenge,
+                devicePropertiesAttestationIncluded,
                 uniqueIdIncluded,
                 userAuthenticationValidWhileOnBody,
                 invalidatedByBiometricEnrollment,
diff --git a/lowpan/tests/Android.bp b/lowpan/tests/Android.bp
new file mode 100644
index 0000000..ad2bc27
--- /dev/null
+++ b/lowpan/tests/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Make test APK
+// ============================================================
+android_test {
+    name: "FrameworksLowpanApiTests",
+    srcs: ["**/*.java"],
+    // Filter all src files to just java files
+    jacoco: {
+        include_filter: ["android.net.lowpan.*"],
+        exclude_filter: [
+	    "android.net.lowpan.LowpanInterfaceTest*",
+	    "android.net.lowpan.LowpanManagerTest*",
+	],
+    },
+    static_libs: [
+        "androidx.test.rules",
+        "guava",
+        "mockito-target-minus-junit4",
+        "frameworks-base-testutils",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    certificate: "platform",
+}
diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk
deleted file mode 100644
index 832ed2f..0000000
--- a/lowpan/tests/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Make test APK
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-# This list is generated from the java source files in this module
-# The list is a comma separated list of class names with * matching zero or more characters.
-# Example:
-#   Input files: src/com/android/server/lowpan/Test.java src/com/android/server/lowpan/AnotherTest.java
-#   Generated exclude list: com.android.server.lowpan.Test*,com.android.server.lowpan.AnotherTest*
-
-# Filter all src files to just java files
-local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
-# Transform java file names into full class names.
-# This only works if the class name matches the file name and the directory structure
-# matches the package.
-local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
-# Convert class name list to jacoco exclude list
-# This appends a * to all classes and replace the space separators with commas.
-# These patterns will match all classes in this module and their inner classes.
-jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
-
-jacoco_include := android.net.lowpan.*
-
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	androidx.test.rules \
-	guava \
-	mockito-target-minus-junit4 \
-	frameworks-base-testutils \
-
-LOCAL_JAVA_LIBRARIES := \
-	android.test.runner \
-	android.test.base \
-
-LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_PACKAGE)
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 9f52d85..8f36dece 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -93,14 +93,6 @@
     },
 }
 
-// Header-only library used for atrace in platform NDK builds
-cc_library_headers {
-    name: "libandroid_trace",
-    host_supported: true,
-    vendor_available: true,
-    export_include_dirs: ["trace"],
-}
-
 // Network library.
 cc_library_shared {
     name: "libandroid_net",
diff --git a/native/android/trace/android/trace.h b/native/android/trace/android/trace.h
deleted file mode 100644
index 4e569e5..0000000
--- a/native/android/trace/android/trace.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_ATRACE_HEADERS_H
-#define ANDROID_ATRACE_HEADERS_H
-
-#include <cutils/trace.h>
-
-inline void ATrace_beginSection(const char* sectionName) {
-    atrace_begin(ATRACE_TAG_APP, sectionName);
-}
-
-inline void ATrace_endSection() {
-    atrace_end(ATRACE_TAG_APP);
-}
-
-#endif // ANDROID_ATRACE_HEADERS_H
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 24d0896..c1ec9b0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -299,22 +299,6 @@
                   android:excludeFromRecents="true"
                   android:exported="false" />
 
-        <!--
-        The following is used as a no-op/null home activity when
-        no other MAIN/HOME activity is present (e.g., in CSI).
-        -->
-        <activity android:name=".NullHome"
-                  android:excludeFromRecents="true"
-                  android:label=""
-                  android:screenOrientation="nosensor">
-            <!-- The priority here is set to be lower than that for Settings -->
-            <intent-filter android:priority="-1100">
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.HOME" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
         <receiver
             android:name=".BugreportReceiver"
             android:permission="android.permission.DUMP">
diff --git a/packages/Shell/res/layout/null_home_finishing_boot.xml b/packages/Shell/res/layout/null_home_finishing_boot.xml
deleted file mode 100644
index 5f9563a..0000000
--- a/packages/Shell/res/layout/null_home_finishing_boot.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="#80000000"
-    android:forceHasOverlappingRendering="false">
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="center"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="40sp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:text="@*android:string/android_start_title"/>
-        <ProgressBar
-            style="@android:style/Widget.Material.ProgressBar.Horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12.75dp"
-            android:colorControlActivated="?android:attr/textColorPrimary"
-            android:indeterminate="true"/>
-    </LinearLayout>
-</FrameLayout>
diff --git a/packages/Shell/src/com/android/shell/NullHome.java b/packages/Shell/src/com/android/shell/NullHome.java
deleted file mode 100644
index bd97561..0000000
--- a/packages/Shell/src/com/android/shell/NullHome.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.shell;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * This covers the fallback case where no launcher is available.
- * Usually Settings.apk has one fallback home activity.
- * Settings.apk, however, is not part of CSI, which needs to be
- * standalone (bootable and testable).
- */
-public class NullHome extends Activity {
-    private static final String TAG = "NullHome";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Log.i(TAG, "onCreate");
-        setContentView(R.layout.null_home_finishing_boot);
-    }
-
-    protected void onDestroy() {
-        super.onDestroy();
-        Log.i(TAG, "onDestroy");
-    }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 91a6e29..48a600d 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -132,7 +132,7 @@
         isDunRequired = checkDunRequired(ctx);
 
         chooseUpstreamAutomatically = getResourceBoolean(
-                res, R.bool.config_tether_upstream_automatic, false /** default value */);
+                res, R.bool.config_tether_upstream_automatic, false /** defaultValue */);
         preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
 
         legacyDhcpRanges = getLegacyDhcpRanges(res);
@@ -375,30 +375,31 @@
         // Priority 1: Device config
         // Priority 2: Resource config
         // Priority 3: Default value
-        final boolean resourceValue = getResourceBoolean(
+        final boolean defaultValue = getResourceBoolean(
                 res, R.bool.config_tether_enable_bpf_offload, true /** default value */);
 
-        // Due to the limitation of static mock for testing, using #getProperty directly instead
-        // of getDeviceConfigBoolean. getDeviceConfigBoolean is not invoked because it uses
-        // #getBoolean to get the boolean device config. The test can't know that the returned
-        // boolean value comes from device config or default value (because of null property
-        // string). Because the test would like to verify null property boolean string case,
-        // use DeviceConfig.getProperty here. See also the test case testBpfOffload{*} in
-        // TetheringConfigurationTest.java.
-        final String value = DeviceConfig.getProperty(
-                NAMESPACE_CONNECTIVITY, OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD);
-        return (value != null) ? Boolean.parseBoolean(value) : resourceValue;
+        return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue);
     }
 
     private boolean getEnableLegacyDhcpServer(final Resources res) {
         return getResourceBoolean(
-                res, R.bool.config_tether_enable_legacy_dhcp_server, false /** default value */)
-                || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER);
+                res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */)
+                || getDeviceConfigBoolean(
+                TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */);
+    }
+
+    private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
+        // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead
+        // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the
+        // returned boolean value comes from device config or default value (because of null
+        // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java.
+        final String value = getDeviceConfigProperty(name);
+        return value != null ? Boolean.parseBoolean(value) : defaultValue;
     }
 
     @VisibleForTesting
-    protected boolean getDeviceConfigBoolean(final String name) {
-        return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */);
+    protected String getDeviceConfigProperty(String name) {
+        return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name);
     }
 
     private Resources getResources(Context ctx, int subId) {
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
index 31eaabf..355342f 100644
--- a/packages/Tethering/tests/unit/AndroidManifest.xml
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -16,9 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack.tethering.tests.unit">
 
-    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
-    <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
-
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
         <service
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index cdd0e24..72fa916 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -147,9 +147,8 @@
         doReturn(false).when(
                 () -> SystemProperties.getBoolean(
                 eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean()));
-        doReturn(false).when(
-                () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
-                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+        doReturn(null).when(
+                () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), anyString()));
 
         when(mResources.getStringArray(R.array.config_tether_dhcp_range))
                 .thenReturn(new String[0]);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index fbfa871..1999ad7 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -30,7 +30,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -109,9 +108,9 @@
                 .mockStatic(DeviceConfig.class)
                 .strictness(Strictness.WARN)
                 .startMocking();
-        doReturn(false).when(
-                () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
-                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+        doReturn(null).when(
+                () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
 
         when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn(
                 new String[0]);
@@ -328,9 +327,9 @@
     public void testNewDhcpServerDisabled() {
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 true);
-        doReturn(false).when(
-                () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
-                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+        doReturn("false").when(
+                () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
 
         final TetheringConfiguration enableByRes =
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -338,9 +337,9 @@
 
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
-        doReturn(true).when(
-                () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
-                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+        doReturn("true").when(
+                () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
 
         final TetheringConfiguration enableByDevConfig =
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -351,9 +350,9 @@
     public void testNewDhcpServerEnabled() {
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
-        doReturn(false).when(
-                () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
-                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+        doReturn("false").when(
+                () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+                eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
 
         final TetheringConfiguration cfg =
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 3dc6a13..cf060ba 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -16,20 +16,29 @@
 
 package com.android.networkstack.tethering;
 
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.TETHER_PRIVILEGED;
+import static android.Manifest.permission.WRITE_SETTINGS;
 import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
+import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.UiAutomation;
 import android.content.Intent;
 import android.net.IIntResultListener;
 import android.net.ITetheringConnector;
 import android.net.ITetheringEventCallback;
 import android.net.TetheringRequestParcel;
+import android.os.Bundle;
+import android.os.Handler;
 import android.os.ResultReceiver;
 
 import androidx.test.InstrumentationRegistry;
@@ -51,13 +60,14 @@
 @SmallTest
 public final class TetheringServiceTest {
     private static final String TEST_IFACE_NAME = "test_wlan0";
-    private static final String TEST_CALLER_PKG = "test_pkg";
+    private static final String TEST_CALLER_PKG = "com.android.shell";
     private static final String TEST_ATTRIBUTION_TAG = null;
     @Mock private ITetheringEventCallback mITetheringEventCallback;
     @Rule public ServiceTestRule mServiceTestRule;
     private Tethering mTethering;
     private Intent mMockServiceIntent;
     private ITetheringConnector mTetheringConnector;
+    private UiAutomation mUiAutomation;
 
     private class TestTetheringResult extends IIntResultListener.Stub {
         private int mResult = -1; // Default value that does not match any result code.
@@ -71,9 +81,26 @@
         }
     }
 
+    private class MyResultReceiver extends ResultReceiver {
+        MyResultReceiver(Handler handler) {
+            super(handler);
+        }
+        private int mResult = -1; // Default value that does not match any result code.
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mResult = resultCode;
+        }
+
+        public void assertResult(int expected) {
+            assertEquals(expected, mResult);
+        }
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mUiAutomation =
+            InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mServiceTestRule = new ServiceTestRule();
         mMockServiceIntent = new Intent(
                 InstrumentationRegistry.getTargetContext(),
@@ -83,115 +110,364 @@
         mTetheringConnector = mockConnector.getTetheringConnector();
         final MockTetheringService service = mockConnector.getService();
         mTethering = service.getTethering();
-        when(mTethering.isTetheringSupported()).thenReturn(true);
     }
 
     @After
     public void tearDown() throws Exception {
         mServiceTestRule.unbindService();
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    private interface TestTetheringCall {
+        void runTetheringCall(TestTetheringResult result) throws Exception;
+    }
+
+    private void runAsNoPermission(final TestTetheringCall test) throws Exception {
+        runTetheringCall(test, new String[0]);
+    }
+
+    private void runAsTetherPrivileged(final TestTetheringCall test) throws Exception {
+        runTetheringCall(test, TETHER_PRIVILEGED);
+    }
+
+    private void runAsAccessNetworkState(final TestTetheringCall test) throws Exception {
+        runTetheringCall(test, ACCESS_NETWORK_STATE);
+    }
+
+    private void runAsWriteSettings(final TestTetheringCall test) throws Exception {
+        runTetheringCall(test, WRITE_SETTINGS);
+    }
+
+    private void runTetheringCall(final TestTetheringCall test, String... permissions)
+            throws Exception {
+        if (permissions.length > 0) mUiAutomation.adoptShellPermissionIdentity(permissions);
+        try {
+            when(mTethering.isTetheringSupported()).thenReturn(true);
+            test.runTetheringCall(new TestTetheringResult());
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    private void verifyNoMoreInteractionsForTethering() {
+        verifyNoMoreInteractions(mTethering);
+        verifyNoMoreInteractions(mITetheringEventCallback);
+        reset(mTethering, mITetheringEventCallback);
+    }
+
+    private void runTether(final TestTetheringResult result) throws Exception {
+        when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
+        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
+        verify(mTethering).isTetheringSupported();
+        verify(mTethering).tether(TEST_IFACE_NAME);
+        result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
     public void testTether() throws Exception {
-        when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                    result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runTether(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runTether(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runUnTether(final TestTetheringResult result) throws Exception {
+        when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
+        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                result);
         verify(mTethering).isTetheringSupported();
-        verify(mTethering).tether(TEST_IFACE_NAME);
-        verifyNoMoreInteractions(mTethering);
+        verify(mTethering).untether(TEST_IFACE_NAME);
         result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
     public void testUntether() throws Exception {
-        when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
-                result);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                    result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runUnTether(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runUnTether(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runSetUsbTethering(final TestTetheringResult result) throws Exception {
+        when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR);
+        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
+                TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).isTetheringSupported();
-        verify(mTethering).untether(TEST_IFACE_NAME);
-        verifyNoMoreInteractions(mTethering);
+        verify(mTethering).setUsbTethering(true /* enable */);
         result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
     public void testSetUsbTethering() throws Exception {
-        when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR);
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
-                TEST_ATTRIBUTION_TAG, result);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
+                    TEST_ATTRIBUTION_TAG, result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runSetUsbTethering(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runSetUsbTethering(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+
+    }
+
+    private void runStartTethering(final TestTetheringResult result,
+            final TetheringRequestParcel request) throws Exception {
+        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                result);
         verify(mTethering).isTetheringSupported();
-        verify(mTethering).setUsbTethering(true /* enable */);
-        verifyNoMoreInteractions(mTethering);
-        result.assertResult(TETHER_ERROR_NO_ERROR);
+        verify(mTethering).startTethering(eq(request), eq(result));
     }
 
     @Test
     public void testStartTethering() throws Exception {
-        final TestTetheringResult result = new TestTetheringResult();
         final TetheringRequestParcel request = new TetheringRequestParcel();
         request.tetheringType = TETHERING_WIFI;
-        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
-        verify(mTethering).isTetheringSupported();
-        verify(mTethering).startTethering(eq(request), eq(result));
-        verifyNoMoreInteractions(mTethering);
+
+        runAsNoPermission((result) -> {
+            mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                    result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runStartTethering(result, request);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runStartTethering(result, request);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
     }
 
     @Test
-    public void testStopTethering() throws Exception {
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
-                result);
+    public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception {
+        final TetheringRequestParcel request = new TetheringRequestParcel();
+        request.tetheringType = TETHERING_WIFI;
+        request.exemptFromEntitlementCheck = true;
+
+        runAsTetherPrivileged((result) -> {
+            runStartTethering(result, request);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                    result);
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runStopTethering(final TestTetheringResult result) throws Exception {
+        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG,
+                TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).isTetheringSupported();
         verify(mTethering).stopTethering(TETHERING_WIFI);
-        verifyNoMoreInteractions(mTethering);
         result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
-    public void testRequestLatestTetheringEntitlementResult() throws Exception {
-        final ResultReceiver result = new ResultReceiver(null);
+    public void testStopTethering() throws Exception {
+        runAsNoPermission((result) -> {
+            mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG,
+                    TEST_ATTRIBUTION_TAG, result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runStopTethering(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runStopTethering(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runRequestLatestTetheringEntitlementResult() throws Exception {
+        final MyResultReceiver result = new MyResultReceiver(null);
         mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
                 true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
         verify(mTethering).isTetheringSupported();
         verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
                 eq(result), eq(true) /* showEntitlementUi */);
+    }
+
+    @Test
+    public void testRequestLatestTetheringEntitlementResult() throws Exception {
+        // Run as no permission.
+        final MyResultReceiver result = new MyResultReceiver(null);
+        mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
+                true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
+        verify(mTethering).isTetherProvisioningRequired();
+        result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
         verifyNoMoreInteractions(mTethering);
+
+        runAsTetherPrivileged((none) -> {
+            runRequestLatestTetheringEntitlementResult();
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((none) -> {
+            runRequestLatestTetheringEntitlementResult();
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runRegisterTetheringEventCallback() throws Exception {
+        mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback,
+                TEST_CALLER_PKG);
+        verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback));
     }
 
     @Test
     public void testRegisterTetheringEventCallback() throws Exception {
-        mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback,
+        runAsNoPermission((result) -> {
+            mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback,
+                    TEST_CALLER_PKG);
+            verify(mITetheringEventCallback).onCallbackStopped(
+                    TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((none) -> {
+            runRegisterTetheringEventCallback();
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsAccessNetworkState((none) -> {
+            runRegisterTetheringEventCallback();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runUnregisterTetheringEventCallback() throws Exception {
+        mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback,
                 TEST_CALLER_PKG);
-        verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback));
-        verifyNoMoreInteractions(mTethering);
+        verify(mTethering).unregisterTetheringEventCallback(eq(mITetheringEventCallback));
     }
 
     @Test
     public void testUnregisterTetheringEventCallback() throws Exception {
-        mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback,
-                TEST_CALLER_PKG);
-        verify(mTethering).unregisterTetheringEventCallback(
-                eq(mITetheringEventCallback));
-        verifyNoMoreInteractions(mTethering);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback,
+                    TEST_CALLER_PKG);
+            verify(mITetheringEventCallback).onCallbackStopped(
+                    TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((none) -> {
+            runUnregisterTetheringEventCallback();
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsAccessNetworkState((none) -> {
+            runUnregisterTetheringEventCallback();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runStopAllTethering(final TestTetheringResult result) throws Exception {
+        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
+        verify(mTethering).isTetheringSupported();
+        verify(mTethering).untetherAll();
+        result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
     public void testStopAllTethering() throws Exception {
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runStopAllTethering(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runStopAllTethering(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
+    }
+
+    private void runIsTetheringSupported(final TestTetheringResult result) throws Exception {
+        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).isTetheringSupported();
-        verify(mTethering).untetherAll();
-        verifyNoMoreInteractions(mTethering);
         result.assertResult(TETHER_ERROR_NO_ERROR);
     }
 
     @Test
     public void testIsTetheringSupported() throws Exception {
-        final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
-        verify(mTethering).isTetheringSupported();
-        verifyNoMoreInteractions(mTethering);
-        result.assertResult(TETHER_ERROR_NO_ERROR);
+        runAsNoPermission((result) -> {
+            mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                    result);
+            verify(mTethering).isTetherProvisioningRequired();
+            result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsTetherPrivileged((result) -> {
+            runIsTetheringSupported(result);
+            verifyNoMoreInteractionsForTethering();
+        });
+
+        runAsWriteSettings((result) -> {
+            runIsTetheringSupported(result);
+            verify(mTethering).isTetherProvisioningRequired();
+            verifyNoMoreInteractionsForTethering();
+        });
     }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index b665acc..7734a3c 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -312,8 +312,8 @@
         }
 
         @Override
-        protected boolean getDeviceConfigBoolean(final String name) {
-            return false;
+        protected String getDeviceConfigProperty(final String name) {
+            return null;
         }
 
         @Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9a5349..74fddb2 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -28,7 +28,7 @@
         "android.hardware.power-V1.0-java",
         "android.hardware.tv.cec-V1.0-java",
         "android.hardware.vibrator-java",
-        "android.net.ipsec.ike.stubs.module_libs_api",
+        "android.net.ipsec.ike.stubs.module_lib",
         "app-compat-annotations",
         "framework-tethering-stubs-module_libs_api",
     ],
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 635f184..efa1f9a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3079,23 +3079,7 @@
 
         @Override
         public void notifyDataStallSuspected(DataStallReportParcelable p) {
-            final PersistableBundle extras = new PersistableBundle();
-            switch (p.detectionMethod) {
-                case DETECTION_METHOD_DNS_EVENTS:
-                    extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
-                    break;
-                case DETECTION_METHOD_TCP_METRICS:
-                    extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
-                    extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
-                            p.tcpMetricsCollectionPeriodMillis);
-                    break;
-                default:
-                    log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
-                    return;
-            }
-
-            proxyDataStallToConnectivityDiagnosticsHandler(
-                    p.detectionMethod, mNetId, p.timestampMillis, extras);
+            ConnectivityService.this.notifyDataStallSuspected(p, mNetId);
         }
 
         @Override
@@ -3109,11 +3093,31 @@
         }
     }
 
-    private void proxyDataStallToConnectivityDiagnosticsHandler(int detectionMethod, int netId,
-            long timestampMillis, @NonNull PersistableBundle extras) {
+    private void notifyDataStallSuspected(DataStallReportParcelable p, int netId) {
+        final PersistableBundle extras = new PersistableBundle();
+        switch (p.detectionMethod) {
+            case DETECTION_METHOD_DNS_EVENTS:
+                extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
+                break;
+            case DETECTION_METHOD_TCP_METRICS:
+                extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
+                extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
+                        p.tcpMetricsCollectionPeriodMillis);
+                break;
+            default:
+                // TODO(b/156294356): update for new data stall detection methods
+                log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
+                return;
+        }
+
+        notifyDataStallSuspected(p.detectionMethod, netId, p.timestampMillis, extras);
+    }
+
+    private void notifyDataStallSuspected(int detectionMethod, int netId, long timestampMillis,
+            @NonNull PersistableBundle extras) {
         final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
-                    ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
-                    detectionMethod, netId, timestampMillis);
+                ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId,
+                timestampMillis);
         msg.setData(new Bundle(extras));
 
         // NetworkStateTrackerHandler currently doesn't take any actions based on data
@@ -8181,7 +8185,6 @@
                 + "creators");
         }
 
-        proxyDataStallToConnectivityDiagnosticsHandler(
-                detectionMethod, network.netId, timestampMillis, extras);
+        notifyDataStallSuspected(detectionMethod, network.netId, timestampMillis, extras);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 0114b5b..730da28 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -65,6 +65,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkProvider;
+import android.net.NetworkRequest;
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.VpnManager;
@@ -2225,12 +2226,27 @@
 
         @Override
         public void run() {
-            // Explicitly use only the network that ConnectivityService thinks is the "best." In
-            // other words, only ever use the currently selected default network. This does mean
-            // that in both onLost() and onConnected(), any old sessions MUST be torn down. This
-            // does NOT include VPNs.
+            // Unless the profile is restricted to test networks, explicitly use only the network
+            // that ConnectivityService thinks is the "best." In other words, only ever use the
+            // currently selected default network. This does mean that in both onLost() and
+            // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs.
+            //
+            // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
+            // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
+            // this is considered safe.
             final ConnectivityManager cm = ConnectivityManager.from(mContext);
-            cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback);
+            final NetworkRequest req;
+
+            if (mProfile.isRestrictedToTestNetworks()) {
+                req = new NetworkRequest.Builder()
+                        .clearCapabilities()
+                        .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+                        .build();
+            } else {
+                req = cm.getDefaultRequest();
+            }
+
+            cm.requestNetwork(req, mNetworkCallback);
         }
 
         private boolean isActiveNetwork(@Nullable Network network) {
@@ -2868,6 +2884,11 @@
         verifyCallingUidAndPackage(packageName);
         enforceNotRestrictedUser();
 
+        if (profile.isRestrictedToTestNetworks) {
+            mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS,
+                    "Test-mode profiles require the MANAGE_TEST_NETWORKS permission");
+        }
+
         final byte[] encodedProfile = profile.encode();
         if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) {
             throw new IllegalArgumentException("Profile too big");
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 341a88d..4bb17a2 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -33,9 +33,9 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.sysprop.ApexProperties;
 import android.util.Slog;
 
@@ -73,12 +73,7 @@
      */
     static ApexManager create(Context systemContext) {
         if (ApexProperties.updatable().orElse(false)) {
-            try {
-                return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
-                        ServiceManager.getServiceOrThrow("apexservice")));
-            } catch (ServiceManager.ServiceNotFoundException e) {
-                throw new IllegalStateException("Required service apexservice not available");
-            }
+            return new ApexManagerImpl(systemContext);
         } else {
             return new ApexManagerFlattenedApex();
         }
@@ -247,8 +242,7 @@
      * APEX packages.
      */
     @VisibleForTesting
-    static class ApexManagerImpl extends ApexManager {
-        private final IApexService mApexService;
+    protected static class ApexManagerImpl extends ApexManager {
         private final Context mContext;
         private final Object mLock = new Object();
         /**
@@ -261,9 +255,8 @@
         @GuardedBy("mLock")
         private List<PackageInfo> mAllPackagesCache;
 
-        ApexManagerImpl(Context context, IApexService apexService) {
+        ApexManagerImpl(Context context) {
             mContext = context;
-            mApexService = apexService;
         }
 
         /**
@@ -286,10 +279,23 @@
             return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
         }
 
+        /**
+         * Retrieve the service from ServiceManager. If the service is not running, it will be
+         * started, and this function will block until it is ready.
+         */
+        @VisibleForTesting
+        protected IApexService waitForApexService() {
+            try {
+                return IApexService.Stub.asInterface(Binder.waitForService("apexservice"));
+            } catch (RemoteException e) {
+                throw new IllegalStateException("Required service apexservice not available");
+            }
+        }
+
         @Override
         List<ActiveApexInfo> getActiveApexInfos() {
             try {
-                return Arrays.stream(mApexService.getActivePackages())
+                return Arrays.stream(waitForApexService().getActivePackages())
                         .map(apexInfo -> new ActiveApexInfo(
                                 new File(
                                 Environment.getApexDirectory() + File.separator
@@ -324,7 +330,7 @@
                     mAllPackagesCache = new ArrayList<>();
                     HashSet<String> activePackagesSet = new HashSet<>();
                     HashSet<String> factoryPackagesSet = new HashSet<>();
-                    final ApexInfo[] allPkgs = mApexService.getAllPackages();
+                    final ApexInfo[] allPkgs = waitForApexService().getAllPackages();
                     for (ApexInfo ai : allPkgs) {
                         // If the device is using flattened APEX, don't report any APEX
                         // packages since they won't be managed or updated by PackageManager.
@@ -431,7 +437,8 @@
         @Override
         @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
             try {
-                ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
+                ApexSessionInfo apexSessionInfo =
+                        waitForApexService().getStagedSessionInfo(sessionId);
                 if (apexSessionInfo.isUnknown) {
                     return null;
                 }
@@ -450,7 +457,7 @@
                 ApexSessionParams params = new ApexSessionParams();
                 params.sessionId = sessionId;
                 params.childSessionIds = childSessionIds;
-                mApexService.submitStagedSession(params, apexInfoList);
+                waitForApexService().submitStagedSession(params, apexInfoList);
                 return apexInfoList;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
@@ -465,7 +472,7 @@
         @Override
         void markStagedSessionReady(int sessionId) throws PackageManagerException {
             try {
-                mApexService.markStagedSessionReady(sessionId);
+                waitForApexService().markStagedSessionReady(sessionId);
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
                 throw new RuntimeException(re);
@@ -479,7 +486,7 @@
         @Override
         void markStagedSessionSuccessful(int sessionId) {
             try {
-                mApexService.markStagedSessionSuccessful(sessionId);
+                waitForApexService().markStagedSessionSuccessful(sessionId);
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
                 throw new RuntimeException(re);
@@ -498,7 +505,7 @@
         @Override
         boolean revertActiveSessions() {
             try {
-                mApexService.revertActiveSessions();
+                waitForApexService().revertActiveSessions();
                 return true;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
@@ -512,7 +519,7 @@
         @Override
         boolean abortStagedSession(int sessionId) throws PackageManagerException {
             try {
-                mApexService.abortStagedSession(sessionId);
+                waitForApexService().abortStagedSession(sessionId);
                 return true;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
@@ -527,7 +534,7 @@
         @Override
         boolean uninstallApex(String apexPackagePath) {
             try {
-                mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
+                waitForApexService().unstagePackages(Collections.singletonList(apexPackagePath));
                 return true;
             } catch (Exception e) {
                 return false;
@@ -578,7 +585,7 @@
                 ipw.increaseIndent();
                 ipw.println("APEX session state:");
                 ipw.increaseIndent();
-                final ApexSessionInfo[] sessions = mApexService.getSessions();
+                final ApexSessionInfo[] sessions = waitForApexService().getSessions();
                 for (ApexSessionInfo si : sessions) {
                     ipw.println("Session ID: " + si.sessionId);
                     ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 72fc189..9d56263 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -28,12 +28,14 @@
 import android.graphics.Bitmap.Config;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.UserManagerInternal;
 import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.AtomicFile;
+import com.android.server.LocalServices;
 import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
 
 import java.io.File;
@@ -73,6 +75,7 @@
     private boolean mStarted;
     private final Object mLock = new Object();
     private final DirectoryResolver mDirectoryResolver;
+    private final UserManagerInternal mUserManagerInternal;
     private final float mReducedScale;
 
     /**
@@ -84,6 +87,7 @@
 
     TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
         mDirectoryResolver = resolver;
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         if (service.mLowRamTaskSnapshotsAndRecents) {
             // Use very low res snapshots if we are using Go version of recents.
             mReducedScale = LOW_RAM_RECENTS_REDUCED_SCALE;
@@ -172,7 +176,7 @@
                     return;
                 }
             }
-            SystemClock.sleep(100);
+            SystemClock.sleep(DELAY_MS);
         }
     }
 
@@ -218,7 +222,7 @@
 
     private boolean createDirectory(int userId) {
         final File dir = getDirectory(userId);
-        return dir.exists() || dir.mkdirs();
+        return dir.exists() || dir.mkdir();
     }
 
     private void deleteSnapshot(int taskId, int userId) {
@@ -243,18 +247,26 @@
             android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             while (true) {
                 WriteQueueItem next;
+                boolean isReadyToWrite = false;
                 synchronized (mLock) {
                     if (mPaused) {
                         next = null;
                     } else {
                         next = mWriteQueue.poll();
                         if (next != null) {
-                            next.onDequeuedLocked();
+                            if (next.isReady()) {
+                                isReadyToWrite = true;
+                                next.onDequeuedLocked();
+                            } else {
+                                mWriteQueue.addLast(next);
+                            }
                         }
                     }
                 }
                 if (next != null) {
-                    next.write();
+                    if (isReadyToWrite) {
+                        next.write();
+                    }
                     SystemClock.sleep(DELAY_MS);
                 }
                 synchronized (mLock) {
@@ -274,6 +286,13 @@
     };
 
     private abstract class WriteQueueItem {
+        /**
+         * @return {@code true} if item is ready to have {@link WriteQueueItem#write} called
+         */
+        boolean isReady() {
+            return true;
+        }
+
         abstract void write();
 
         /**
@@ -313,6 +332,11 @@
         }
 
         @Override
+        boolean isReady() {
+            return mUserManagerInternal.isUserUnlocked(mUserId);
+        }
+
+        @Override
         void write() {
             if (!createDirectory(mUserId)) {
                 Slog.e(TAG, "Unable to create snapshot directory for user dir="
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index e79612f..a99c0a3 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -40,6 +40,7 @@
 #include <linux/rtc.h>
 
 #include <array>
+#include <limits>
 #include <memory>
 
 namespace android {
@@ -213,22 +214,20 @@
 static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
 {
     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
-    struct timeval tv;
-    int ret;
 
-    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
+    if (millis <= 0 || millis / 1000LL >= std::numeric_limits<time_t>::max()) {
         return -1;
     }
 
-    tv.tv_sec = (time_t) (millis / 1000LL);
-    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
+    struct timeval tv;
+    tv.tv_sec = (millis / 1000LL);
+    tv.tv_usec = ((millis % 1000LL) * 1000LL);
 
-    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
+    ALOGD("Setting time of day to sec=%ld", tv.tv_sec);
 
-    ret = impl->setTime(&tv);
-
-    if(ret < 0) {
-        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
+    int ret = impl->setTime(&tv);
+    if (ret < 0) {
+        ALOGW("Unable to set rtc to %ld: %s", tv.tv_sec, strerror(errno));
         ret = -1;
     }
     return ret;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 30d1035..c086718 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -21,8 +21,10 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -68,7 +70,9 @@
     @Before
     public void setUp() throws RemoteException {
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
-        mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
+        ApexManager.ApexManagerImpl managerImpl = spy(new ApexManager.ApexManagerImpl(mContext));
+        doReturn(mApexService).when(managerImpl).waitForApexService();
+        mApexManager = managerImpl;
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index e004cd3..f25110f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -23,6 +23,9 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.ComponentName;
 import android.graphics.Canvas;
@@ -32,9 +35,14 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
+
+import com.android.server.LocalServices;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 
 import java.io.File;
 
@@ -50,10 +58,26 @@
     TaskSnapshotLoader mLoader;
     int mTestUserId;
 
+    @BeforeClass
+    public static void setUpOnce() {
+        final UserManagerInternal userManager = mock(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, userManager);
+    }
+
+    @AfterClass
+    public static void tearDownOnce() {
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+    }
+
     @Before
     public void setUp() {
         final UserManager um = UserManager.get(getInstrumentation().getTargetContext());
         mTestUserId = um.getUserHandle();
+
+        final UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+        when(userManagerInternal.isUserUnlocked(mTestUserId)).thenReturn(true);
+
         mPersister = new TaskSnapshotPersister(mWm, userId -> FILES_DIR);
         mLoader = new TaskSnapshotLoader(mPersister);
         mPersister.start();
diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
new file mode 100644
index 0000000..6c63755
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Telephony;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * This class provides utility functions related to CellBroadcast.
+ */
+public class CellBroadcastUtils {
+    private static final String TAG = "CellBroadcastUtils";
+    private static final boolean VDBG = false;
+
+    /**
+     * Utility method to query the default CBR's package name.
+     */
+    public static String getDefaultCellBroadcastReceiverPackageName(Context context) {
+        PackageManager packageManager = context.getPackageManager();
+        ResolveInfo resolveInfo = packageManager.resolveActivity(
+                new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION),
+                PackageManager.MATCH_SYSTEM_ONLY);
+        String packageName;
+
+        if (resolveInfo == null) {
+            Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: no package found");
+            return null;
+        }
+
+        packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+
+        if (VDBG) {
+            Log.d(TAG, "getDefaultCellBroadcastReceiverPackageName: found package: " + packageName);
+        }
+
+        if (TextUtils.isEmpty(packageName) || packageManager.checkPermission(
+                android.Manifest.permission.READ_CELL_BROADCASTS, packageName)
+                == PackageManager.PERMISSION_DENIED) {
+            Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: returning null; "
+                    + "permission check failed for : " + packageName);
+            return null;
+        }
+
+        return packageName;
+    }
+}
diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java
index 68c9d99..d9b5de5 100644
--- a/telephony/java/android/telephony/PinResult.java
+++ b/telephony/java/android/telephony/PinResult.java
@@ -37,6 +37,7 @@
             PIN_RESULT_TYPE_SUCCESS,
             PIN_RESULT_TYPE_INCORRECT,
             PIN_RESULT_TYPE_FAILURE,
+            PIN_RESULT_TYPE_ABORTED,
     })
     public @interface PinResultType {}
 
@@ -55,6 +56,11 @@
      */
     public static final int PIN_RESULT_TYPE_FAILURE = PhoneConstants.PIN_GENERAL_FAILURE;
 
+    /**
+     * Indicates that the pin attempt was aborted.
+     */
+    public static final int PIN_RESULT_TYPE_ABORTED = PhoneConstants.PIN_OPERATION_ABORTED;
+
     private static final PinResult sFailedResult =
             new PinResult(PinResult.PIN_RESULT_TYPE_FAILURE, -1);
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e57402d..7d1398b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10314,7 +10314,7 @@
      * <p>To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
      * carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android
      * platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
-     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
      *
      * <p>Apps which have carrier-specific configurations or business logic can use the carrier id
      * as an Android platform-wide identifier for carriers.
@@ -10376,7 +10376,7 @@
      *
      * <p>For carriers without fine-grained specific carrier ids, return {@link #getSimCarrierId()}
      * <p>Specific carrier ids are defined in the same way as carrier id
-     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
      * except each with a "parent" id linking to its top-level carrier id.
      *
      * @return Returns fine-grained carrier id of the current subscription.
@@ -10425,7 +10425,7 @@
      * This is used for fallback when configurations/logic for exact carrier id
      * {@link #getSimCarrierId()} are not found.
      *
-     * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+     * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
      * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
      * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
      * by default. After carrier id table update, a new carrier id was assigned. If apps don't
@@ -10452,7 +10452,7 @@
       * used for fallback when configurations/logic for exact carrier id {@link #getSimCarrierId()}
       * are not found.
       *
-      * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+      * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
       * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
       * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
       * by default. After carrier id table update, a new carrier id was assigned. If apps don't
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 6eea88f..db9fdf5 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -111,6 +111,7 @@
     public static final int PIN_RESULT_SUCCESS = 0;
     public static final int PIN_PASSWORD_INCORRECT = 1;
     public static final int PIN_GENERAL_FAILURE = 2;
+    public static final int PIN_OPERATION_ABORTED = 3;
 
     /**
      * Return codes for <code>enableApnType()</code>
diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp
new file mode 100644
index 0000000..648fd81
--- /dev/null
+++ b/tests/GamePerformance/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "GamePerformance",
+    // Don't include this package in any target
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    srcs: ["src/**/*.java"],
+    static_libs: ["android-support-test"],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/GamePerformance/Android.mk b/tests/GamePerformance/Android.mk
deleted file mode 100644
index 58654de..0000000
--- a/tests/GamePerformance/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-
-LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
-
-LOCAL_PACKAGE_NAME := GamePerformance
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-
-include $(BUILD_PACKAGE)
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
new file mode 100644
index 0000000..99248bf
--- /dev/null
+++ b/tests/NullHomeTest/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "NullHomeTest",
+    srcs: ["src/**/*.java"],
+    certificate: "platform",
+    platform_apis: true,
+    static_libs: ["android-support-test"],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/NullHomeTest/AndroidManifest.xml b/tests/NullHomeTest/AndroidManifest.xml
new file mode 100644
index 0000000..dc6402e
--- /dev/null
+++ b/tests/NullHomeTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.test.nullhome"
+    android:sharedUserId="android.uid.system" >
+
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.test.nullhome"
+        android:label="Check if no null Home exists/is enabled" />
+
+    <application android:label="Null Home Test">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
diff --git a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
new file mode 100644
index 0000000..1d77cdc5
--- /dev/null
+++ b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.test.nullhome;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * Check if NullHome/SystemUserHome activity does not exist/is disabled.
+ *
+ * SystemUserHome is only enabled in bootable CSI (csi_x86, csi_arm64)
+ * products and should not be enabled in other products.
+ *
+ * Shell's NullHome is empty and caused issues in sevaral manual GUI tests
+ * that try to select/use it, and should be removed.
+ *
+ * Settings' FallbackHome is fine because it's specially handled by Settings.
+ *
+ */
+
+@RunWith(JUnit4.class)
+public class NullHomeTest {
+    private static final String TAG = "NullHomeTest";
+    private Context mContext;
+    private PackageManager mPm;
+
+    @Before
+    public void before() {
+        Log.d(TAG, "beforeClass()");
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mPm = mContext.getPackageManager();
+    }
+
+    @Test
+    public void checkNullHome() {
+        final List<ResolveInfo> homeActivities = new ArrayList<>();
+
+        mPm.getHomeActivities(homeActivities);
+        for (ResolveInfo activity : homeActivities) {
+            Log.d(TAG, "Home activity: " + activity.activityInfo.packageName);
+            Assert.assertNotEquals(activity.activityInfo.packageName,
+                    "com.android.internal.app.SystemUserHomeActivity");
+            Assert.assertNotEquals(activity.activityInfo.packageName,
+                    "com.android.shell");
+        }
+    }
+}
diff --git a/tests/ProtoInputStreamTests/Android.bp b/tests/ProtoInputStreamTests/Android.bp
new file mode 100644
index 0000000..ecc40566
--- /dev/null
+++ b/tests/ProtoInputStreamTests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "ProtoInputStreamTests",
+    proto: {
+        type: "nano",
+    },
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.proto",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["device-tests"],
+    libs: ["android.test.runner"],
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "mockito-target-minus-junit4",
+    ],
+}
diff --git a/tests/ProtoInputStreamTests/Android.mk b/tests/ProtoInputStreamTests/Android.mk
deleted file mode 100644
index eb747cc..0000000
--- a/tests/ProtoInputStreamTests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := ProtoInputStreamTests
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_MODULE_TAGS := tests optional
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-proto-files-under, src)
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    frameworks-base-testutils \
-    mockito-target-minus-junit4
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index 09c0e48..f5a4234 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -16,50 +16,55 @@
  * limitations under the License.
  */
 -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.server.net.integrationtests">
+     package="com.android.server.net.integrationtests">
 
     <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
     <!-- PermissionMonitor sets network permissions for each user -->
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
     <!-- ConnectivityService sends notifications to BatteryStats -->
-    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
     <!-- Reading network status -->
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.NETWORK_FACTORY" />
-    <uses-permission android:name="android.permission.NETWORK_STACK" />
-    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.NETWORK_FACTORY"/>
+    <!-- Obtain LinkProperties callbacks with sensitive fields -->
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
+    <uses-permission android:name="android.permission.NETWORK_STACK"/>
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/>
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     <!-- Reading DeviceConfig flags -->
-    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner"/>
 
         <!-- This manifest is merged with the base manifest of the real NetworkStack app.
-             Remove the NetworkStackService from the base (real) manifest, and replace with a test
-             service that responds to the same intent -->
+                         Remove the NetworkStackService from the base (real) manifest, and replace with a test
+                         service that responds to the same intent -->
         <service android:name=".TestNetworkStackService"
-                 android:process="com.android.server.net.integrationtests.testnetworkstack">
+             android:process="com.android.server.net.integrationtests.testnetworkstack"
+             android:exported="true">
             <intent-filter>
                 <action android:name="android.net.INetworkStackConnector.Test"/>
             </intent-filter>
         </service>
         <service android:name=".NetworkStackInstrumentationService"
-                 android:process="com.android.server.net.integrationtests.testnetworkstack">
+             android:process="com.android.server.net.integrationtests.testnetworkstack"
+             android:exported="true">
             <intent-filter>
                 <action android:name=".INetworkStackInstrumentation"/>
             </intent-filter>
         </service>
         <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
-                 android:process="com.android.server.net.integrationtests.testnetworkstack"
-                 android:permission="android.permission.BIND_JOB_SERVICE"/>
+             android:process="com.android.server.net.integrationtests.testnetworkstack"
+             android:permission="android.permission.BIND_JOB_SERVICE"/>
 
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.server.net.integrationtests"
-                     android:label="Frameworks Net Integration Tests" />
+         android:targetPackage="com.android.server.net.integrationtests"
+         android:label="Frameworks Net Integration Tests"/>
 
 </manifest>
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index c4801aa..bc069e1 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -28,10 +28,13 @@
 import android.net.INetworkPolicyManager
 import android.net.INetworkStatsService
 import android.net.LinkProperties
+import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
 import android.net.NetworkRequest
 import android.net.TestNetworkStackClient
+import android.net.Uri
 import android.net.metrics.IpConnectivityLog
 import android.os.ConditionVariable
 import android.os.IBinder
@@ -64,6 +67,8 @@
 import org.mockito.MockitoAnnotations
 import org.mockito.Spy
 import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
 import kotlin.test.fail
 
@@ -110,6 +115,10 @@
         private val bindingCondition = ConditionVariable(false)
 
         private val realContext get() = InstrumentationRegistry.getInstrumentation().context
+        private val httpProbeUrl get() =
+            realContext.getResources().getString(R.string.config_captive_portal_http_url)
+        private val httpsProbeUrl get() =
+            realContext.getResources().getString(R.string.config_captive_portal_https_url)
 
         private class InstrumentationServiceConnection : ServiceConnection {
             override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
@@ -188,12 +197,8 @@
         val testCallback = TestableNetworkCallback()
 
         cm.registerNetworkCallback(request, testCallback)
-        nsInstrumentation.addHttpResponse(HttpResponse(
-                "http://test.android.com",
-                responseCode = 204, contentLength = 42, redirectUrl = null))
-        nsInstrumentation.addHttpResponse(HttpResponse(
-                "https://secure.test.android.com",
-                responseCode = 204, contentLength = 42, redirectUrl = null))
+        nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
+        nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
 
         val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context)
         networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
@@ -204,4 +209,52 @@
         testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
         assertEquals(2, nsInstrumentation.getRequestUrls().size)
     }
+
+    @Test
+    fun testCapportApi() {
+        val request = NetworkRequest.Builder()
+                .clearCapabilities()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build()
+        val testCb = TestableNetworkCallback()
+        val apiUrl = "https://capport.android.com"
+
+        cm.registerNetworkCallback(request, testCb)
+        nsInstrumentation.addHttpResponse(HttpResponse(
+                apiUrl,
+                """
+                    |{
+                    |  "captive": true,
+                    |  "user-portal-url": "https://login.capport.android.com",
+                    |  "venue-info-url": "https://venueinfo.capport.android.com"
+                    |}
+                """.trimMargin()))
+
+        // Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the
+        // HTTP probe as it should not be sent.
+        // Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence
+        // in that case.
+        nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
+
+        val lp = LinkProperties()
+        lp.captivePortalApiUrl = Uri.parse(apiUrl)
+        val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, context)
+        networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
+
+        na.addCapability(NET_CAPABILITY_INTERNET)
+        na.connect()
+
+        testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS)
+
+        val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) {
+            it.captivePortalData != null
+        }.lp.captivePortalData
+        assertNotNull(capportData)
+        assertTrue(capportData.isCaptive)
+        assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl)
+        assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl)
+
+        val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS)
+        assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED))
+    }
 }
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
index 45073d8..e206313 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
@@ -22,16 +22,21 @@
 data class HttpResponse(
     val requestUrl: String,
     val responseCode: Int,
-    val contentLength: Long,
-    val redirectUrl: String?
+    val content: String = "",
+    val redirectUrl: String? = null
 ) : Parcelable {
-    constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString())
+    constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString())
+    constructor(requestUrl: String, contentBody: String): this(
+            requestUrl,
+            responseCode = 200,
+            content = contentBody,
+            redirectUrl = null)
 
     override fun writeToParcel(dest: Parcel, flags: Int) {
         with(dest) {
             writeString(requestUrl)
             writeInt(responseCode)
-            writeLong(contentLength)
+            writeString(content)
             writeString(redirectUrl)
         }
     }
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
index 4827d29..e807952 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
@@ -65,6 +65,9 @@
          *
          * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
          * used to mock the query response.
+         *
+         * <p>All requests that are expected to be sent must have a mock response: if an unexpected
+         * request is seen, the test will fail.
          */
         override fun addHttpResponse(response: HttpResponse) {
             httpResponses.getValue(response.requestUrl).add(response)
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 8c2de40..a44ad1e0 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -33,9 +33,11 @@
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.spy
+import java.io.ByteArrayInputStream
 import java.net.HttpURLConnection
 import java.net.URL
 import java.net.URLConnection
+import java.nio.charset.StandardCharsets
 
 private const val TEST_NETID = 42
 
@@ -71,11 +73,13 @@
         private inner class TestNetwork(netId: Int) : Network(netId) {
             override fun openConnection(url: URL): URLConnection {
                 val response = InstrumentationConnector.processRequest(url)
+                val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8)
 
                 val connection = mock(HttpURLConnection::class.java)
                 doReturn(response.responseCode).`when`(connection).responseCode
-                doReturn(response.contentLength).`when`(connection).contentLengthLong
+                doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong
                 doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
+                doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream
                 return connection
             }
         }
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
index ceca6f0..e5daa71 100644
--- a/tests/net/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -33,7 +33,9 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /** Unit tests for {@link VpnProfile}. */
 @SmallTest
@@ -41,6 +43,9 @@
 public class VpnProfileTest {
     private static final String DUMMY_PROFILE_KEY = "Test";
 
+    private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
+    private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
+
     @Test
     public void testDefaults() throws Exception {
         final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
@@ -67,10 +72,11 @@
         assertFalse(p.isMetered);
         assertEquals(1360, p.maxMtu);
         assertFalse(p.areAuthParamsInline);
+        assertFalse(p.isRestrictedToTestNetworks);
     }
 
     private VpnProfile getSampleIkev2Profile(String key) {
-        final VpnProfile p = new VpnProfile(key);
+        final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
 
         p.name = "foo";
         p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
@@ -116,7 +122,7 @@
 
     @Test
     public void testParcelUnparcel() {
-        assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22);
+        assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
     }
 
     @Test
@@ -159,14 +165,41 @@
         assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
     }
 
+    private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
+        // Sort to ensure when we remove, we can do it from greatest first.
+        Arrays.sort(missingIndices);
+
+        final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
+        final List<String> parts =
+                new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
+
+        // Remove from back first to ensure indexing is consistent.
+        for (int i = missingIndices.length - 1; i >= 0; i--) {
+            parts.remove(missingIndices[i]);
+        }
+
+        return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
+    }
+
     @Test
     public void testEncodeDecodeInvalidNumberOfValues() {
-        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-        final String encoded = new String(profile.encode());
-        final byte[] tooFewValues =
-                encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes();
+        final String tooFewValues =
+                getEncodedDecodedIkev2ProfileMissingValues(
+                        ENCODED_INDEX_AUTH_PARAMS_INLINE,
+                        ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
 
-        assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues));
+        assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
+    }
+
+    @Test
+    public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
+        final String tooFewValues =
+                getEncodedDecodedIkev2ProfileMissingValues(
+                        ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
+
+        // Verify decoding without isRestrictedToTestNetworks defaults to false
+        final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+        assertFalse(decoded.isRestrictedToTestNetworks);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5e2ef04..e66e264 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -5494,6 +5494,8 @@
         assertFalse(nc.hasTransport(TRANSPORT_WIFI));
         // For safety reasons a VPN without underlying networks is considered metered.
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+        // A VPN without underlying networks is not suspended.
+        assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
 
         // Connect cell and use it as an underlying network.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 8d99ac7..7218ae3 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -222,6 +222,10 @@
         return sLoopers.get(test);
     }
 
+    public static void remove(Object test) {
+        sLoopers.remove(test);
+    }
+
     static class LooperFrameworkMethod extends FrameworkMethod {
         private HandlerThread mHandlerThread;