Merge "Remove clearDefaultsForInactiveSubIds."
diff --git a/api/current.txt b/api/current.txt
index 766b6b3..262f4fc4c 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -100,7 +100,7 @@
     field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
     field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
-    field public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+    field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
     field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
     field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
     field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -27266,11 +27266,11 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    method public boolean contains(java.net.InetAddress);
+    method public boolean contains(@NonNull java.net.InetAddress);
     method public int describeContents();
-    method public java.net.InetAddress getAddress();
-    method public int getPrefixLength();
-    method public byte[] getRawAddress();
+    method @NonNull public java.net.InetAddress getAddress();
+    method @IntRange(from=0, to=128) public int getPrefixLength();
+    method @NonNull public byte[] getRawAddress();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
   }
@@ -27343,7 +27343,7 @@
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getFlags();
-    method public int getPrefixLength();
+    method @IntRange(from=0, to=128) public int getPrefixLength();
     method public int getScope();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
@@ -27612,9 +27612,9 @@
 
   public final class RouteInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.net.IpPrefix getDestination();
-    method public java.net.InetAddress getGateway();
-    method public String getInterface();
+    method @NonNull public android.net.IpPrefix getDestination();
+    method @Nullable public java.net.InetAddress getGateway();
+    method @Nullable public String getInterface();
     method public boolean hasGateway();
     method public boolean isDefaultRoute();
     method public boolean matches(java.net.InetAddress);
@@ -40465,6 +40465,7 @@
     method public static int getpid();
     method public static int getppid();
     method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method @NonNull public static android.system.StructTimeval getsockoptTimeval(@NonNull java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
     method public static int gettid();
     method public static int getuid();
     method public static byte[] getxattr(String, String) throws android.system.ErrnoException;
@@ -40515,6 +40516,7 @@
     method @Deprecated public static void setgid(int) throws android.system.ErrnoException;
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
+    method public static void setsockoptTimeval(@NonNull java.io.FileDescriptor, int, int, @NonNull android.system.StructTimeval) throws android.system.ErrnoException;
     method @Deprecated public static void setuid(int) throws android.system.ErrnoException;
     method public static void setxattr(String, String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
@@ -40720,6 +40722,10 @@
     field public static final int F_SETOWN;
     field public static final int F_UNLCK;
     field public static final int F_WRLCK;
+    field public static final int ICMP6_ECHO_REPLY;
+    field public static final int ICMP6_ECHO_REQUEST;
+    field public static final int ICMP_ECHO;
+    field public static final int ICMP_ECHOREPLY;
     field public static final int IFA_F_DADFAILED;
     field public static final int IFA_F_DEPRECATED;
     field public static final int IFA_F_HOMEADDRESS;
@@ -41092,6 +41098,13 @@
     field public final long tv_sec;
   }
 
+  public final class StructTimeval {
+    method @NonNull public static android.system.StructTimeval fromMillis(long);
+    method public long toMillis();
+    field public final long tv_sec;
+    field public final long tv_usec;
+  }
+
   public final class StructUtsname {
     ctor public StructUtsname(String, String, String, String, String);
     field public final String machine;
@@ -43009,7 +43022,6 @@
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -43249,7 +43261,7 @@
     field public static final int PHONE_TYPE_GSM = 1; // 0x1
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
-    field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+    field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
     field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
     field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 1717382..f0de579 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -745,9 +745,9 @@
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean getSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
@@ -756,7 +756,6 @@
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
     field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
-    field public static final String EXTRA_SILENCE_ENABLED = "android.bluetooth.device.extra.SILENCE_ENABLED";
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
@@ -3133,13 +3132,13 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
   }
 
   public class LinkAddress implements android.os.Parcelable {
-    ctor public LinkAddress(java.net.InetAddress, int, int, int);
-    ctor public LinkAddress(@NonNull java.net.InetAddress, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public LinkAddress(@NonNull String);
     ctor public LinkAddress(@NonNull String, int, int);
     method public boolean isGlobalPreferred();
@@ -3316,8 +3315,8 @@
   public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
     method public int describeContents();
-    method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
-    method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
+    method public static boolean getApfDrop8023Frames();
+    method @NonNull public static int[] getApfEtherTypeBlackList();
     method public boolean hasDataAccess();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
diff --git a/api/test-current.txt b/api/test-current.txt
index ca74109..7f86d5d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -616,7 +616,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
   }
 
@@ -625,8 +625,8 @@
   }
 
   public class LinkAddress implements android.os.Parcelable {
-    ctor public LinkAddress(java.net.InetAddress, int, int, int);
-    ctor public LinkAddress(@NonNull java.net.InetAddress, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public LinkAddress(@NonNull String);
     ctor public LinkAddress(@NonNull String, int, int);
     method public boolean isGlobalPreferred();
@@ -735,8 +735,8 @@
   public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
     method public int describeContents();
-    method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
-    method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
+    method public static boolean getApfDrop8023Frames();
+    method @NonNull public static int[] getApfEtherTypeBlackList();
     method public boolean hasDataAccess();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c4c14d1..6af1096 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -535,7 +535,6 @@
     /**
      * Intent to broadcast silence mode changed.
      * Alway contains the extra field {@link #EXTRA_DEVICE}
-     * Alway contains the extra field {@link #EXTRA_SILENCE_ENABLED}
      *
      * @hide
      */
@@ -545,16 +544,6 @@
             "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
 
     /**
-     * Used as an extra field in {@link #ACTION_SILENCE_MODE_CHANGED} intent,
-     * contains whether device is in silence mode as boolean.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final String EXTRA_SILENCE_ENABLED =
-            "android.bluetooth.device.extra.SILENCE_ENABLED";
-
-    /**
      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
      *
      * @hide
@@ -1615,7 +1604,8 @@
     }
 
     /**
-     * Set the Bluetooth device silence mode.
+     * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
+     * be routed to the {@link BluetoothDevice} if set to {@code true}.
      *
      * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
      * is an active device (for A2DP or HFP), the active device for that profile
@@ -1635,6 +1625,7 @@
      *
      * @param silence true to enter silence mode, false to exit
      * @return true on success, false on error.
+     * @throws IllegalStateException if Bluetooth is not turned ON.
      * @hide
      */
     @SystemApi
@@ -1642,12 +1633,9 @@
     public boolean setSilenceMode(boolean silence) {
         final IBluetooth service = sService;
         if (service == null) {
-            return false;
+            throw new IllegalStateException("Bluetooth is not turned ON");
         }
         try {
-            if (getSilenceMode() == silence) {
-                return true;
-            }
             return service.setSilenceMode(this, silence);
         } catch (RemoteException e) {
             Log.e(TAG, "setSilenceMode fail", e);
@@ -1656,24 +1644,25 @@
     }
 
     /**
-     * Get the device silence mode status
+     * Check whether the {@link BluetoothDevice} is in silence mode
      *
      * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
      *
      * @return true on device in silence mode, otherwise false.
+     * @throws IllegalStateException if Bluetooth is not turned ON.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean getSilenceMode() {
+    public boolean isInSilenceMode() {
         final IBluetooth service = sService;
         if (service == null) {
-            return false;
+            throw new IllegalStateException("Bluetooth is not turned ON");
         }
         try {
             return service.getSilenceMode(this);
         } catch (RemoteException e) {
-            Log.e(TAG, "getSilenceMode fail", e);
+            Log.e(TAG, "isInSilenceMode fail", e);
             return false;
         }
     }
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b4f3a28..416157c 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -71,7 +72,7 @@
      *
      * @hide
      */
-    public IpPrefix(@NonNull byte[] address, int prefixLength) {
+    public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) {
         this.address = address.clone();
         this.prefixLength = prefixLength;
         checkAndMaskAddressAndPrefixLength();
@@ -88,7 +89,7 @@
      */
     @SystemApi
     @TestApi
-    public IpPrefix(@NonNull InetAddress address, int prefixLength) {
+    public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
         // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
         // which is unnecessary because getAddress() already returns a clone.
         this.address = address.getAddress();
@@ -150,13 +151,13 @@
      *
      * @return the address in the form of a byte array.
      */
-    public InetAddress getAddress() {
+    public @NonNull InetAddress getAddress() {
         try {
             return InetAddress.getByAddress(address);
         } catch (UnknownHostException e) {
             // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
             // array is the wrong length, but we check that in the constructor.
-            return null;
+            throw new IllegalArgumentException("Address is invalid");
         }
     }
 
@@ -166,7 +167,7 @@
      *
      * @return the address in the form of a byte array.
      */
-    public byte[] getRawAddress() {
+    public @NonNull byte[] getRawAddress() {
         return address.clone();
     }
 
@@ -175,6 +176,7 @@
      *
      * @return the prefix length.
      */
+    @IntRange(from = 0, to = 128)
     public int getPrefixLength() {
         return prefixLength;
     }
@@ -183,10 +185,10 @@
      * Determines whether the prefix contains the specified address.
      *
      * @param address An {@link InetAddress} to test.
-     * @return {@code true} if the prefix covers the given address.
+     * @return {@code true} if the prefix covers the given address. {@code false} otherwise.
      */
-    public boolean contains(InetAddress address) {
-        byte[] addrBytes = (address == null) ? null : address.getAddress();
+    public boolean contains(@NonNull InetAddress address) {
+        byte[] addrBytes = address.getAddress();
         if (addrBytes == null || addrBytes.length != this.address.length) {
             return false;
         }
@@ -201,7 +203,7 @@
      * @param otherPrefix the prefix to test
      * @hide
      */
-    public boolean containsPrefix(IpPrefix otherPrefix) {
+    public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
         if (otherPrefix.getPrefixLength() < prefixLength) return false;
         final byte[] otherAddress = otherPrefix.getRawAddress();
         NetworkUtils.maskRawAddress(otherAddress, prefixLength);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 78b4665..f17adea 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -25,6 +25,7 @@
 import static android.system.OsConstants.RT_SCOPE_SITE;
 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -170,7 +171,7 @@
      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
      * the specified flags and scope. Flags and scope are not checked for validity.
      * @param address The IP address.
-     * @param prefixLength The prefix length.
+     * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
      * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
      * @param scope An integer defining the scope in which the address is unique (e.g.,
      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
@@ -178,7 +179,8 @@
      */
     @SystemApi
     @TestApi
-    public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
+    public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
+            int flags, int scope) {
         init(address, prefixLength, flags, scope);
     }
 
@@ -186,12 +188,13 @@
      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
      * The flags are set to zero and the scope is determined from the address.
      * @param address The IP address.
-     * @param prefixLength The prefix length.
+     * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
      * @hide
      */
     @SystemApi
     @TestApi
-    public LinkAddress(@NonNull InetAddress address, int prefixLength) {
+    public LinkAddress(@NonNull InetAddress address,
+            @IntRange(from = 0, to = 128) int prefixLength) {
         this(address, prefixLength, 0, 0);
         this.scope = scopeForUnicastAddress(address);
     }
@@ -202,7 +205,7 @@
      * @param interfaceAddress The interface address.
      * @hide
      */
-    public LinkAddress(InterfaceAddress interfaceAddress) {
+    public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
         this(interfaceAddress.getAddress(),
              interfaceAddress.getNetworkPrefixLength());
     }
@@ -306,6 +309,7 @@
     /**
      * Returns the prefix length of this {@code LinkAddress}.
      */
+    @IntRange(from = 0, to = 128)
     public int getPrefixLength() {
         return prefixLength;
     }
@@ -316,6 +320,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @IntRange(from = 0, to = 128)
     public int getNetworkPrefixLength() {
         return getPrefixLength();
     }
diff --git a/core/java/android/net/NetworkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl
index cd7d71c..01d3286 100644
--- a/core/java/android/net/NetworkCapabilities.aidl
+++ b/core/java/android/net/NetworkCapabilities.aidl
@@ -17,5 +17,5 @@
 
 package android.net;
 
-parcelable NetworkCapabilities;
+@JavaOnlyStableParcelable parcelable NetworkCapabilities;
 
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 24d9b8e..fdd904a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -24,6 +26,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -51,20 +55,32 @@
  * (IPv4 or IPv6).
  */
 public final class RouteInfo implements Parcelable {
+    /** @hide */
+    @IntDef(value = {
+            RTN_UNICAST,
+            RTN_UNREACHABLE,
+            RTN_THROW,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RouteType {}
+
     /**
      * The IP destination address for this route.
      */
+    @NonNull
     private final IpPrefix mDestination;
 
     /**
      * The gateway address for this route.
      */
     @UnsupportedAppUsage
+    @Nullable
     private final InetAddress mGateway;
 
     /**
      * The interface for this route.
      */
+    @Nullable
     private final String mInterface;
 
 
@@ -108,13 +124,14 @@
      * @param destination the destination prefix
      * @param gateway the IP address to route packets through
      * @param iface the interface name to send packets on
+     * @param type the type of this route
      *
      * @hide
      */
     @SystemApi
     @TestApi
     public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
-            @Nullable String iface, int type) {
+            @Nullable String iface, @RouteType int type) {
         switch (type) {
             case RTN_UNICAST:
             case RTN_UNREACHABLE:
@@ -173,10 +190,24 @@
     }
 
     /**
-     *  @hide
+     * Constructs a {@code RouteInfo} object.
+     *
+     * If destination is null, then gateway must be specified and the
+     * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+     * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+     * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+     * <p>
+     * Destination and gateway may not both be null.
+     *
+     * @param destination the destination address and prefix in an {@link IpPrefix}
+     * @param gateway the {@link InetAddress} to route packets through
+     * @param iface the interface name to send packets on
+     *
+     * @hide
      */
     @UnsupportedAppUsage
-    public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+    public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+            @Nullable String iface) {
         this(destination, gateway, iface, RTN_UNICAST);
     }
 
@@ -184,7 +215,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
+    public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
+            @Nullable String iface) {
         this(destination == null ? null :
                 new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
                 gateway, iface);
@@ -205,7 +237,7 @@
      *
      * @hide
      */
-    public RouteInfo(IpPrefix destination, InetAddress gateway) {
+    public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
         this(destination, gateway, null);
     }
 
@@ -215,7 +247,7 @@
      * TODO: Remove this.
      */
     @UnsupportedAppUsage
-    public RouteInfo(LinkAddress destination, InetAddress gateway) {
+    public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
         this(destination, gateway, null);
     }
 
@@ -227,7 +259,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public RouteInfo(InetAddress gateway) {
+    public RouteInfo(@NonNull InetAddress gateway) {
         this((IpPrefix) null, gateway, null);
     }
 
@@ -239,35 +271,36 @@
      *
      * @hide
      */
-    public RouteInfo(IpPrefix destination) {
+    public RouteInfo(@NonNull IpPrefix destination) {
         this(destination, null, null);
     }
 
     /**
      * @hide
      */
-    public RouteInfo(LinkAddress destination) {
+    public RouteInfo(@NonNull LinkAddress destination) {
         this(destination, null, null);
     }
 
     /**
      * @hide
      */
-    public RouteInfo(IpPrefix destination, int type) {
+    public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
         this(destination, null, null, type);
     }
 
     /**
      * @hide
      */
-    public static RouteInfo makeHostRoute(InetAddress host, String iface) {
+    public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
         return makeHostRoute(host, null, iface);
     }
 
     /**
      * @hide
      */
-    public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
+    public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
+            @Nullable String iface) {
         if (host == null) return null;
 
         if (host instanceof Inet4Address) {
@@ -290,6 +323,7 @@
      *
      * @return {@link IpPrefix} specifying the destination.  This is never {@code null}.
      */
+    @NonNull
     public IpPrefix getDestination() {
         return mDestination;
     }
@@ -298,6 +332,7 @@
      * TODO: Convert callers to use IpPrefix and then remove.
      * @hide
      */
+    @NonNull
     public LinkAddress getDestinationLinkAddress() {
         return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
     }
@@ -308,6 +343,7 @@
      * @return {@link InetAddress} specifying the gateway or next hop.  This may be
      *                             {@code null} for a directly-connected route."
      */
+    @Nullable
     public InetAddress getGateway() {
         return mGateway;
     }
@@ -317,6 +353,7 @@
      *
      * @return The name of the interface used for this route.
      */
+    @Nullable
     public String getInterface() {
         return mInterface;
     }
@@ -330,6 +367,7 @@
      */
     @TestApi
     @SystemApi
+    @RouteType
     public int getType() {
         return mType;
     }
@@ -401,6 +439,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @Nullable
     public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
         if ((routes == null) || (dest == null)) return null;
 
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 17a03c7c..4dd2ace 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,14 +19,17 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.content.Context;
+import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.internal.R;
 
 /**
- * APF program support capabilities.
+ * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
+ * way to drop unwanted network packets to save power.
+ *
+ * See documentation at hardware/google/apf/apf.h
  *
  * This class is immutable.
  * @hide
@@ -104,10 +107,11 @@
     }
 
     /**
-     * Returns true if the APF interpreter advertises support for the data buffer access opcodes
-     * LDDW and STDW.
+     * Determines whether the APF interpreter advertises support for the data buffer access opcodes
+     * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
+     * STDW (STore Data Word) support is present from APFv4 on.
      *
-     * Full LDDW and STDW support is present from APFv4 on.
+     * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported.
      */
     public boolean hasDataAccess() {
         return apfVersionSupported >= 4;
@@ -116,14 +120,14 @@
     /**
      * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
      */
-    public static boolean getApfDrop8023Frames(@NonNull Context context) {
-        return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
+    public static boolean getApfDrop8023Frames() {
+        return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
     }
 
     /**
      * @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped.
      */
-    public static @NonNull int[] getApfEthTypeBlackList(@NonNull Context context) {
-        return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+    public static @NonNull int[] getApfEtherTypeBlackList() {
+        return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
     }
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9aedb76..f562dca 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -915,6 +915,9 @@
          call with the option to redirect the call to a different number or
          abort the call altogether.
          <p>Protection level: dangerous
+
+         @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
+         of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
     -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
         android:permissionGroup="android.permission-group.CALL_LOG"
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d44f5a9..28099a1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -261,6 +261,7 @@
         <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
+        <permission name="android.permission.NETWORK_SCAN"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
         <!-- Needed for test only -->
         <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b0a7923..3fc1e98 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,21 @@
           package="com.android.networkstack"
           android:sharedUserId="android.uid.networkstack">
     <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+    <!-- Permissions must be defined here, and not in the base manifest, as the network stack
+         running in the system server process does not need any permission, and having privileged
+         permissions added would cause crashes on startup unless they are also added to the
+         privileged permissions whitelist for that package. -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <!-- Send latency broadcast as current user -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
     <application>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index f69e4b2..69a4da4 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,15 +20,6 @@
           package="com.android.networkstack"
           android:versionCode="11"
           android:versionName="Q-initial">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <!-- Send latency broadcast as current user -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <application
         android:label="NetworkStack"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 7a06af4..c1f178a 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -1389,8 +1389,8 @@
             apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
             apfConfig.multicastFilter = mMulticastFiltering;
             // Get the Configuration for ApfFilter from Context
-            apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames(mContext);
-            apfConfig.ethTypeBlackList = ApfCapabilities.getApfEthTypeBlackList(mContext);
+            apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
+            apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
             mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
             // rest of this IP configuration startup.
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index fedb8d1..670563c 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -17,6 +17,7 @@
 package android.net.util;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.SparseArray;
 
 import java.io.FileDescriptor;
@@ -81,4 +82,19 @@
         }
         return false;
     }
+
+    /**
+     * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
+     * @param namespace The namespace containing the property to look up.
+     * @param name The name of the property to look up.
+     * @param defaultValue The value to return if the property does not exist or has no non-null
+     *                     value.
+     * @return the corresponding value, or defaultValue if none exists.
+     */
+    @Nullable
+    public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
+            @Nullable String defaultValue) {
+        // TODO: Link to DeviceConfig API once it is ready.
+        return defaultValue;
+    }
 }
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 19e9108..63f057c 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -35,7 +35,9 @@
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkStackConnector;
+import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.PrivateDnsConfigParcel;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
@@ -307,9 +309,9 @@
         }
 
         @Override
-        public void notifyNetworkConnected() {
+        public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
             checkNetworkStackCallingPermission();
-            mNm.notifyNetworkConnected();
+            mNm.notifyNetworkConnected(lp, nc);
         }
 
         @Override
@@ -319,15 +321,15 @@
         }
 
         @Override
-        public void notifyLinkPropertiesChanged() {
+        public void notifyLinkPropertiesChanged(LinkProperties lp) {
             checkNetworkStackCallingPermission();
-            mNm.notifyLinkPropertiesChanged();
+            mNm.notifyLinkPropertiesChanged(lp);
         }
 
         @Override
-        public void notifyNetworkCapabilitiesChanged() {
+        public void notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) {
             checkNetworkStackCallingPermission();
-            mNm.notifyNetworkCapabilitiesChanged();
+            mNm.notifyNetworkCapabilitiesChanged(nc);
         }
     }
 }
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index f3476ed..c000fc6 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -78,6 +78,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.RingBufferIndices;
@@ -221,19 +222,31 @@
      * Message to self indicating captive portal detection is completed.
      * obj = CaptivePortalProbeResult for detection result;
      */
-    public static final int CMD_PROBE_COMPLETE = 16;
+    private static final int CMD_PROBE_COMPLETE = 16;
 
     /**
      * ConnectivityService notifies NetworkMonitor of DNS query responses event.
      * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query.
      */
-    public static final int EVENT_DNS_NOTIFICATION = 17;
+    private static final int EVENT_DNS_NOTIFICATION = 17;
 
     /**
      * ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
      * NetworkMonitor should ignore the https probe.
      */
-    public static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
+    private static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
+
+    /**
+     * ConnectivityService notifies NetworkMonitor of changed LinkProperties.
+     * obj = new LinkProperties.
+     */
+    private static final int EVENT_LINK_PROPERTIES_CHANGED = 19;
+
+    /**
+     * ConnectivityService notifies NetworkMonitor of changed NetworkCapabilities.
+     * obj = new NetworkCapabilities.
+     */
+    private static final int EVENT_NETWORK_CAPABILITIES_CHANGED = 20;
 
     // Start mReevaluateDelayMs at this value and double.
     private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
@@ -379,10 +392,8 @@
         mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
         mDataStallEvaluationType = getDataStallEvalutionType();
 
-        // mLinkProperties and mNetworkCapbilities must never be null or we will NPE.
-        // Provide empty objects in case we are started and the network disconnects before
-        // we can ever fetch them.
-        // TODO: Delete ASAP.
+        // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
+        // even before notifyNetworkConnected.
         mLinkProperties = new LinkProperties();
         mNetworkCapabilities = new NetworkCapabilities(null);
     }
@@ -434,8 +445,16 @@
     /**
      * Send a notification to NetworkMonitor indicating that the network is now connected.
      */
-    public void notifyNetworkConnected() {
-        sendMessage(CMD_NETWORK_CONNECTED);
+    public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
+        sendMessage(CMD_NETWORK_CONNECTED, new Pair<>(
+                new LinkProperties(lp), new NetworkCapabilities(nc)));
+    }
+
+    private void updateConnectedNetworkAttributes(Message connectedMsg) {
+        final Pair<LinkProperties, NetworkCapabilities> attrs =
+                (Pair<LinkProperties, NetworkCapabilities>) connectedMsg.obj;
+        mLinkProperties = attrs.first;
+        mNetworkCapabilities = attrs.second;
     }
 
     /**
@@ -448,37 +467,15 @@
     /**
      * Send a notification to NetworkMonitor indicating that link properties have changed.
      */
-    public void notifyLinkPropertiesChanged() {
-        getHandler().post(() -> {
-            updateLinkProperties();
-        });
-    }
-
-    private void updateLinkProperties() {
-        final LinkProperties lp = mCm.getLinkProperties(mNetwork);
-        // If null, we should soon get a message that the network was disconnected, and will stop.
-        if (lp != null) {
-            // TODO: send LinkProperties parceled in notifyLinkPropertiesChanged() and start().
-            mLinkProperties = lp;
-        }
+    public void notifyLinkPropertiesChanged(final LinkProperties lp) {
+        sendMessage(EVENT_LINK_PROPERTIES_CHANGED, new LinkProperties(lp));
     }
 
     /**
      * Send a notification to NetworkMonitor indicating that network capabilities have changed.
      */
-    public void notifyNetworkCapabilitiesChanged() {
-        getHandler().post(() -> {
-            updateNetworkCapabilities();
-        });
-    }
-
-    private void updateNetworkCapabilities() {
-        final NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
-        // If null, we should soon get a message that the network was disconnected, and will stop.
-        if (nc != null) {
-            // TODO: send NetworkCapabilities parceled in notifyNetworkCapsChanged() and start().
-            mNetworkCapabilities = nc;
-        }
+    public void notifyNetworkCapabilitiesChanged(final NetworkCapabilities nc) {
+        sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilities(nc));
     }
 
     /**
@@ -547,16 +544,10 @@
     // does not entail any real state (hence no enter() or exit() routines).
     private class DefaultState extends State {
         @Override
-        public void enter() {
-            // TODO: have those passed parceled in start() and remove this
-            updateLinkProperties();
-            updateNetworkCapabilities();
-        }
-
-        @Override
         public boolean processMessage(Message message) {
             switch (message.what) {
                 case CMD_NETWORK_CONNECTED:
+                    updateConnectedNetworkAttributes(message);
                     logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
                     transitionTo(mEvaluatingState);
                     return HANDLED;
@@ -660,6 +651,12 @@
                 case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
                     mAcceptPartialConnectivity = true;
                     break;
+                case EVENT_LINK_PROPERTIES_CHANGED:
+                    mLinkProperties = (LinkProperties) message.obj;
+                    break;
+                case EVENT_NETWORK_CAPABILITIES_CHANGED:
+                    mNetworkCapabilities = (NetworkCapabilities) message.obj;
+                    break;
                 default:
                     break;
             }
@@ -684,6 +681,7 @@
         public boolean processMessage(Message message) {
             switch (message.what) {
                 case CMD_NETWORK_CONNECTED:
+                    updateConnectedNetworkAttributes(message);
                     transitionTo(mValidatedState);
                     break;
                 case CMD_EVALUATE_PRIVATE_DNS:
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index 4d4ceed..b4eeefd 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -72,6 +72,10 @@
         public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
         public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
 
+        public static final String COLNAME_ASSIGNEDV4ADDRESSEXPIRY = "assignedV4AddressExpiry";
+        // The lease expiry timestamp in uint of milliseconds
+        public static final String COLTYPE_ASSIGNEDV4ADDRESSEXPIRY = "BIGINT";
+
         // Please note that the group hint is only a *hint*, hence its name. The client can offer
         // this information to nudge the grouping in the decision it thinks is right, but it can't
         // decide for the memory store what is the same L3 network.
@@ -86,13 +90,14 @@
         public static final String COLTYPE_MTU = "INTEGER DEFAULT -1";
 
         public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
-                + TABLENAME                 + " ("
-                + COLNAME_L2KEY             + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
-                + COLNAME_EXPIRYDATE        + " " + COLTYPE_EXPIRYDATE        + ", "
-                + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
-                + COLNAME_GROUPHINT         + " " + COLTYPE_GROUPHINT         + ", "
-                + COLNAME_DNSADDRESSES      + " " + COLTYPE_DNSADDRESSES      + ", "
-                + COLNAME_MTU               + " " + COLTYPE_MTU               + ")";
+                + TABLENAME                       + " ("
+                + COLNAME_L2KEY                   + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+                + COLNAME_EXPIRYDATE              + " " + COLTYPE_EXPIRYDATE              + ", "
+                + COLNAME_ASSIGNEDV4ADDRESS       + " " + COLTYPE_ASSIGNEDV4ADDRESS       + ", "
+                + COLNAME_ASSIGNEDV4ADDRESSEXPIRY + " " + COLTYPE_ASSIGNEDV4ADDRESSEXPIRY + ", "
+                + COLNAME_GROUPHINT               + " " + COLTYPE_GROUPHINT               + ", "
+                + COLNAME_DNSADDRESSES            + " " + COLTYPE_DNSADDRESSES            + ", "
+                + COLNAME_MTU                     + " " + COLTYPE_MTU                     + ")";
         public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
     }
 
@@ -134,7 +139,7 @@
     /** The SQLite DB helper */
     public static class DbHelper extends SQLiteOpenHelper {
         // Update this whenever changing the schema.
-        private static final int SCHEMA_VERSION = 2;
+        private static final int SCHEMA_VERSION = 3;
         private static final String DATABASE_FILENAME = "IpMemoryStore.db";
 
         public DbHelper(@NonNull final Context context) {
@@ -153,10 +158,27 @@
         @Override
         public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
                 final int newVersion) {
-            // No upgrade supported yet.
-            db.execSQL(NetworkAttributesContract.DROP_TABLE);
-            db.execSQL(PrivateDataContract.DROP_TABLE);
-            onCreate(db);
+            try {
+                if (oldVersion < 2) {
+                    // upgrade from version 1 to version 2
+                    // since we starts from version 2, do nothing here
+                }
+
+                if (oldVersion < 3) {
+                    // upgrade from version 2 to version 3
+                    final String sqlUpgradeAddressExpiry = "alter table"
+                            + " " + NetworkAttributesContract.TABLENAME + " ADD"
+                            + " " + NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY
+                            + " " + NetworkAttributesContract.COLTYPE_ASSIGNEDV4ADDRESSEXPIRY;
+                    db.execSQL(sqlUpgradeAddressExpiry);
+                }
+            } catch (SQLiteException e) {
+                Log.e(TAG, "Could not upgrade to the new version", e);
+                // create database with new version
+                db.execSQL(NetworkAttributesContract.DROP_TABLE);
+                db.execSQL(PrivateDataContract.DROP_TABLE);
+                onCreate(db);
+            }
         }
 
         /** Called when the database is downgraded */
@@ -204,6 +226,10 @@
             values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
                     inet4AddressToIntHTH(attributes.assignedV4Address));
         }
+        if (null != attributes.assignedV4AddressExpiry) {
+            values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY,
+                    attributes.assignedV4AddressExpiry);
+        }
         if (null != attributes.groupHint) {
             values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
         }
@@ -251,6 +277,8 @@
         final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
         final int assignedV4AddressInt = getInt(cursor,
                 NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
+        final long assignedV4AddressExpiry = getLong(cursor,
+                NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY, 0);
         final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
         final byte[] dnsAddressesBlob =
                 getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
@@ -258,6 +286,9 @@
         if (0 != assignedV4AddressInt) {
             builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt));
         }
+        if (0 != assignedV4AddressExpiry) {
+            builder.setAssignedV4AddressExpiry(assignedV4AddressExpiry);
+        }
         builder.setGroupHint(groupHint);
         if (null != dnsAddressesBlob) {
             builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d732c4e..6665aae 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -26,6 +26,8 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -60,6 +62,7 @@
 import android.os.Bundle;
 import android.os.ConditionVariable;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.telephony.CellSignalStrength;
@@ -73,6 +76,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
@@ -107,6 +111,7 @@
     private @Spy Network mNetwork = new Network(TEST_NETID);
     private @Mock DataStallStatsUtils mDataStallStatsUtils;
     private @Mock WifiInfo mWifiInfo;
+    private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
 
     private static final int TEST_NETID = 4242;
 
@@ -122,7 +127,7 @@
 
     private static final int HANDLER_TIMEOUT_MS = 1000;
 
-    private static final LinkProperties TEST_LINKPROPERTIES = new LinkProperties();
+    private static final LinkProperties TEST_LINK_PROPERTIES = new LinkProperties();
 
     private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
             .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -182,10 +187,6 @@
                 InetAddresses.parseNumericAddress("192.168.0.0")
         }).when(mNetwork).getAllByName(any());
 
-        // Default values. Individual tests can override these.
-        when(mCm.getLinkProperties(any())).thenReturn(TEST_LINKPROPERTIES);
-        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
-
         setMinDataStallEvaluateInterval(500);
         setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
         setValidDataStallDnsTimeThreshold(500);
@@ -195,10 +196,9 @@
     private class WrappedNetworkMonitor extends NetworkMonitor {
         private long mProbeTime = 0;
 
-        WrappedNetworkMonitor(Context context, Network network, IpConnectivityLog logger,
-                Dependencies deps, DataStallStatsUtils statsUtils) {
-                super(context, mCallbacks, network, logger,
-                        new SharedLog("test_nm"), deps, statsUtils);
+        WrappedNetworkMonitor() {
+                super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger, mDependencies,
+                        mDataStallStatsUtils);
         }
 
         @Override
@@ -216,33 +216,30 @@
         }
     }
 
-    private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
-        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
-                mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
-        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+    private WrappedNetworkMonitor makeMonitor() {
+        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
         nm.start();
         waitForIdle(nm.getHandler());
         return nm;
     }
 
-    private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
-        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
-                mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
-        when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
-        nm.start();
-        waitForIdle(nm.getHandler());
+    private WrappedNetworkMonitor makeMeteredNetworkMonitor() {
+        final WrappedNetworkMonitor nm = makeMonitor();
+        setNetworkCapabilities(nm, METERED_CAPABILITIES);
         return nm;
     }
 
-    private NetworkMonitor makeMonitor() {
-        final NetworkMonitor nm = new NetworkMonitor(
-                mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
-                mDependencies, mDataStallStatsUtils);
-        nm.start();
-        waitForIdle(nm.getHandler());
+    private WrappedNetworkMonitor makeNotMeteredNetworkMonitor() {
+        final WrappedNetworkMonitor nm = makeMonitor();
+        setNetworkCapabilities(nm, NOT_METERED_CAPABILITIES);
         return nm;
     }
 
+    private void setNetworkCapabilities(NetworkMonitor nm, NetworkCapabilities nc) {
+        nm.notifyNetworkCapabilitiesChanged(nc);
+        waitForIdle(nm.getHandler());
+    }
+
     private void waitForIdle(Handler handler) {
         final ConditionVariable cv = new ConditionVariable(false);
         handler.post(cv::open);
@@ -256,7 +253,7 @@
         setSslException(mHttpsConnection);
         setPortal302(mHttpConnection);
 
-        assertPortal(makeMonitor().isCaptivePortal());
+        runPortalNetworkTest();
     }
 
     @Test
@@ -264,17 +261,7 @@
         setStatus(mHttpsConnection, 204);
         setStatus(mHttpConnection, 500);
 
-        assertNotPortal(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpsProbeFailedHttpSuccessNotUsed() throws IOException {
-        setSslException(mHttpsConnection);
-        // Even if HTTP returns a 204, do not use the result unless HTTPS succeeded
-        setStatus(mHttpConnection, 204);
-        setStatus(mFallbackConnection, 500);
-
-        assertFailed(makeMonitor().isCaptivePortal());
+        runNotPortalNetworkTest();
     }
 
     @Test
@@ -283,17 +270,17 @@
         setStatus(mHttpConnection, 500);
         setPortal302(mFallbackConnection);
 
-        assertPortal(makeMonitor().isCaptivePortal());
+        runPortalNetworkTest();
     }
 
     @Test
     public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
         setSslException(mHttpsConnection);
         setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 204);
+        setStatus(mFallbackConnection, 500);
 
         // Fallback probe did not see portal, HTTPS failed -> inconclusive
-        assertFailed(makeMonitor().isCaptivePortal());
+        runFailedNetworkTest();
     }
 
     @Test
@@ -310,15 +297,15 @@
         // TEST_OTHER_FALLBACK_URL is third
         when(mRandom.nextInt()).thenReturn(2);
 
-        final NetworkMonitor monitor = makeMonitor();
-
         // First check always uses the first fallback URL: inconclusive
-        assertFailed(monitor.isCaptivePortal());
+        final NetworkMonitor monitor = runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
         verify(mFallbackConnection, times(1)).getResponseCode();
         verify(mOtherFallbackConnection, never()).getResponseCode();
 
         // Second check uses the URL chosen by Random
-        assertPortal(monitor.isCaptivePortal());
+        final CaptivePortalProbeResult result = monitor.isCaptivePortal();
+        assertTrue(result.isPortal());
         verify(mOtherFallbackConnection, times(1)).getResponseCode();
     }
 
@@ -328,7 +315,7 @@
         setStatus(mHttpConnection, 500);
         setStatus(mFallbackConnection, 404);
 
-        assertFailed(makeMonitor().isCaptivePortal());
+        runFailedNetworkTest();
         verify(mFallbackConnection, times(1)).getResponseCode();
         verify(mOtherFallbackConnection, never()).getResponseCode();
     }
@@ -342,7 +329,7 @@
         setStatus(mHttpConnection, 500);
         setPortal302(mOtherFallbackConnection);
 
-        assertPortal(makeMonitor().isCaptivePortal());
+        runPortalNetworkTest();
         verify(mOtherFallbackConnection, times(1)).getResponseCode();
         verify(mFallbackConnection, never()).getResponseCode();
     }
@@ -360,12 +347,12 @@
     }
 
     @Test
-    public void testIsCaptivePortal_FallbackSpecIsNotPortal() throws IOException {
+    public void testIsCaptivePortal_FallbackSpecIsPartial() throws IOException {
         setupFallbackSpec();
         set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
 
-        // HTTPS failed, fallback spec did not see a portal -> inconclusive
-        assertFailed(makeMonitor().isCaptivePortal());
+        // HTTPS failed, fallback spec went through -> partial connectivity
+        runPartialConnectivityNetworkTest();
         verify(mOtherFallbackConnection, times(1)).getResponseCode();
         verify(mFallbackConnection, never()).getResponseCode();
     }
@@ -375,7 +362,7 @@
         setupFallbackSpec();
         set302(mOtherFallbackConnection, "http://login.portal.example.com");
 
-        assertPortal(makeMonitor().isCaptivePortal());
+        runPortalNetworkTest();
     }
 
     @Test
@@ -384,20 +371,20 @@
         setSslException(mHttpsConnection);
         setPortal302(mHttpConnection);
 
-        assertNotPortal(makeMonitor().isCaptivePortal());
+        runNotPortalNetworkTest();
     }
 
     @Test
     public void testIsDataStall_EvaluationDisabled() {
         setDataStallEvaluationType(0);
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
         assertFalse(wrappedMonitor.isDataStall());
     }
 
     @Test
     public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
         makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertTrue(wrappedMonitor.isDataStall());
@@ -405,7 +392,7 @@
 
     @Test
     public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
         assertFalse(wrappedMonitor.isDataStall());
 
@@ -416,7 +403,7 @@
 
     @Test
     public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         makeDnsTimeoutEvent(wrappedMonitor, 3);
         assertFalse(wrappedMonitor.isDataStall());
@@ -430,7 +417,7 @@
 
         // Set the value to larger than the default dns log size.
         setConsecutiveDnsTimeoutThreshold(51);
-        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         makeDnsTimeoutEvent(wrappedMonitor, 50);
         assertFalse(wrappedMonitor.isDataStall());
@@ -442,7 +429,7 @@
     @Test
     public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
         // Test dns events happened in valid dns time threshold.
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
         makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertFalse(wrappedMonitor.isDataStall());
@@ -451,7 +438,7 @@
 
         // Test dns events happened before valid dns time threshold.
         setValidDataStallDnsTimeThreshold(0);
-        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor = makeMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
         makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
         assertFalse(wrappedMonitor.isDataStall());
@@ -464,24 +451,13 @@
         setSslException(mHttpsConnection);
         setStatus(mHttpConnection, 500);
         setStatus(mFallbackConnection, 404);
-        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
 
-        final NetworkMonitor nm = makeMonitor();
-        nm.notifyNetworkConnected();
-
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+        runFailedNetworkTest();
     }
 
     @Test
     public void testNoInternetCapabilityValidated() throws Exception {
-        when(mCm.getNetworkCapabilities(any())).thenReturn(NO_INTERNET_CAPABILITIES);
-
-        final NetworkMonitor nm = makeMonitor();
-        nm.notifyNetworkConnected();
-
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+        runNetworkTest(NO_INTERNET_CAPABILITIES, NETWORK_TEST_RESULT_VALID);
         verify(mNetwork, never()).openConnection(any());
     }
 
@@ -491,7 +467,7 @@
         setPortal302(mHttpConnection);
 
         final NetworkMonitor nm = makeMonitor();
-        nm.notifyNetworkConnected();
+        nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
 
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
                 .showProvisioningNotification(any(), any());
@@ -522,7 +498,7 @@
 
     @Test
     public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         makeDnsTimeoutEvent(wrappedMonitor, 5);
         assertTrue(wrappedMonitor.isDataStall());
@@ -531,7 +507,7 @@
 
     @Test
     public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
         wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
         makeDnsTimeoutEvent(wrappedMonitor, 3);
         assertFalse(wrappedMonitor.isDataStall());
@@ -540,7 +516,7 @@
 
     @Test
     public void testCollectDataStallMetrics() {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
 
         when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
         when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
@@ -578,14 +554,11 @@
         setSslException(mHttpsConnection);
         setStatus(mHttpConnection, 204);
 
-        final NetworkMonitor nm = makeMonitor();
-        nm.notifyNetworkConnected();
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY, null);
+        final NetworkMonitor nm = runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
 
         nm.setAcceptPartialConnectivity();
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+                .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), any());
     }
 
     @Test
@@ -593,12 +566,12 @@
         setStatus(mHttpsConnection, 500);
         setStatus(mHttpConnection, 204);
         setStatus(mFallbackConnection, 500);
-        assertPartialConnectivity(makeMonitor().isCaptivePortal());
+        runPartialConnectivityNetworkTest();
 
         setStatus(mHttpsConnection, 500);
         setStatus(mHttpConnection, 500);
         setStatus(mFallbackConnection, 204);
-        assertPartialConnectivity(makeMonitor().isCaptivePortal());
+        runPartialConnectivityNetworkTest();
     }
 
     private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
@@ -660,26 +633,41 @@
                 eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
     }
 
-    private void assertPortal(CaptivePortalProbeResult result) {
-        assertTrue(result.isPortal());
-        assertFalse(result.isFailed());
-        assertFalse(result.isSuccessful());
+    private void runPortalNetworkTest() {
+        runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+        assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
-    private void assertNotPortal(CaptivePortalProbeResult result) {
-        assertFalse(result.isPortal());
-        assertFalse(result.isFailed());
-        assertTrue(result.isSuccessful());
+    private void runNotPortalNetworkTest() {
+        runNetworkTest(NETWORK_TEST_RESULT_VALID);
+        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
-    private void assertFailed(CaptivePortalProbeResult result) {
-        assertFalse(result.isPortal());
-        assertTrue(result.isFailed());
-        assertFalse(result.isSuccessful());
+    private void runFailedNetworkTest() {
+        runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
     }
 
-    private void assertPartialConnectivity(CaptivePortalProbeResult result) {
-        assertTrue(result.isPartialConnectivity());
+    private void runPartialConnectivityNetworkTest() {
+        runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
+        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
+    }
+
+    private NetworkMonitor runNetworkTest(int testResult) {
+        return runNetworkTest(METERED_CAPABILITIES, testResult);
+    }
+
+    private NetworkMonitor runNetworkTest(NetworkCapabilities nc, int testResult) {
+        final NetworkMonitor monitor = makeMonitor();
+        monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
+        try {
+            verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                    .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
+        } catch (RemoteException e) {
+            fail("Unexpected exception: " + e);
+        }
+
+        return monitor;
     }
 
     private void setSslException(HttpURLConnection connection) throws IOException {
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index d0e58b8..071ff26 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -228,6 +228,7 @@
     public void testNetworkAttributes() throws UnknownHostException {
         final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
         na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        na.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
         na.setGroupHint("hint1");
         na.setMtu(219);
         final String l2Key = FAKE_KEYS[0];
@@ -257,6 +258,8 @@
                                     + status.resultCode, status.isSuccess());
                             assertEquals(l2Key, key);
                             assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
+                            assertEquals(attributes.assignedV4AddressExpiry,
+                                    attr.assignedV4AddressExpiry);
                             assertEquals(attributes.groupHint, attr.groupHint);
                             assertEquals(attributes.mtu, attr.mtu);
                             assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
@@ -278,7 +281,7 @@
         // Verify that this test does not miss any new field added later.
         // If any field is added to NetworkAttributes it must be tested here for storing
         // and retrieving.
-        assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+        assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
                 .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
     }
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8778e30..7804498 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -118,6 +118,8 @@
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <!-- Shell only holds android.permission.NETWORK_SCAN in order to to enable CTS testing -->
+    <uses-permission android:name="android.permission.NETWORK_SCAN" />
     <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
     <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
     <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 699cf60..971dd23 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5392,7 +5392,7 @@
                 mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
                 mNMS, factorySerialNumber);
         // Make sure the network capabilities reflect what the agent info says.
-        nai.networkCapabilities = mixInCapabilities(nai, nc);
+        nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
         final String extraInfo = networkInfo.getExtraInfo();
         final String name = TextUtils.isEmpty(extraInfo)
                 ? nai.networkCapabilities.getSSID() : extraInfo;
@@ -5485,12 +5485,12 @@
             // Start or stop DNS64 detection and 464xlat according to network state.
             networkAgent.clatd.update();
             notifyIfacesChangedForNetworkStats();
+            try {
+                networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             if (networkAgent.everConnected) {
-                try {
-                    networkAgent.networkMonitor().notifyLinkPropertiesChanged();
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
-                }
                 notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
             }
         }
@@ -5718,7 +5718,7 @@
         final NetworkCapabilities prevNc;
         synchronized (nai) {
             prevNc = nai.networkCapabilities;
-            nai.networkCapabilities = newNc;
+            nai.setNetworkCapabilities(newNc);
         }
 
         updateUids(nai, prevNc, newNc);
@@ -5733,11 +5733,6 @@
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests(nai, oldScore);
-            try {
-                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -5996,11 +5991,6 @@
         }
 
         if (capabilitiesChanged) {
-            try {
-                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -6409,7 +6399,8 @@
                 if (networkAgent.networkMisc.acceptPartialConnectivity) {
                     networkAgent.networkMonitor().setAcceptPartialConnectivity();
                 }
-                networkAgent.networkMonitor().notifyNetworkConnected();
+                networkAgent.networkMonitor().notifyNetworkConnected(
+                        networkAgent.linkProperties, networkAgent.networkCapabilities);
             } catch (RemoteException e) {
                 e.rethrowFromSystemServer();
             }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index e3fdbe8..cfa9131 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.Messenger;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
@@ -121,7 +122,8 @@
     // This Network object is always valid.
     public final Network network;
     public LinkProperties linkProperties;
-    // This should only be modified via ConnectivityService.updateCapabilities().
+    // This should only be modified by ConnectivityService, via setNetworkCapabilities().
+    // TODO: make this private with a getter.
     public NetworkCapabilities networkCapabilities;
     public final NetworkMisc networkMisc;
     // Indicates if netd has been told to create this Network. From this point on the appropriate
@@ -279,6 +281,25 @@
         mNetworkMonitor = networkMonitor;
     }
 
+    /**
+     * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor
+     * of the new capabilities, if NetworkMonitor has been created.
+     *
+     * <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails,
+     * the exception is logged but not reported to callers.
+     */
+    public void setNetworkCapabilities(NetworkCapabilities nc) {
+        networkCapabilities = nc;
+        final INetworkMonitor nm = mNetworkMonitor;
+        if (nm != null) {
+            try {
+                nm.notifyNetworkCapabilitiesChanged(nc);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error notifying NetworkMonitor of updated NetworkCapabilities", e);
+            }
+        }
+    }
+
     public ConnectivityService connService() {
         return mConnService;
     }
diff --git a/services/net/java/android/net/INetworkMonitor.aidl b/services/net/java/android/net/INetworkMonitor.aidl
index 1b0e1d7..3ed4640 100644
--- a/services/net/java/android/net/INetworkMonitor.aidl
+++ b/services/net/java/android/net/INetworkMonitor.aidl
@@ -15,6 +15,8 @@
  */
 package android.net;
 
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.net.PrivateDnsConfigParcel;
 
 /** @hide */
@@ -46,8 +48,8 @@
     void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
     void notifyDnsResponse(int returnCode);
     void notifySystemReady();
-    void notifyNetworkConnected();
+    void notifyNetworkConnected(in LinkProperties lp, in NetworkCapabilities nc);
     void notifyNetworkDisconnected();
-    void notifyLinkPropertiesChanged();
-    void notifyNetworkCapabilitiesChanged();
+    void notifyLinkPropertiesChanged(in LinkProperties lp);
+    void notifyNetworkCapabilitiesChanged(in NetworkCapabilities nc);
 }
\ No newline at end of file
diff --git a/services/net/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
index 6a9eae0..e769769 100644
--- a/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
+++ b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -60,6 +60,13 @@
     public final Inet4Address assignedV4Address;
     private static final float WEIGHT_ASSIGNEDV4ADDR = 300.0f;
 
+    // The lease expiry timestamp of v4 address allocated from DHCP server, in milliseconds.
+    @Nullable
+    public final Long assignedV4AddressExpiry;
+    // lease expiry doesn't imply any correlation between "the same lease expiry value" and "the
+    // same L3 network".
+    private static final float WEIGHT_ASSIGNEDV4ADDREXPIRY = 0.0f;
+
     // Optionally supplied by the client if it has an opinion on L3 network. For example, this
     // could be a hash of the SSID + security type on WiFi.
     @Nullable
@@ -81,6 +88,7 @@
     /** @hide */
     @VisibleForTesting
     public static final float TOTAL_WEIGHT = WEIGHT_ASSIGNEDV4ADDR
+            + WEIGHT_ASSIGNEDV4ADDREXPIRY
             + WEIGHT_GROUPHINT
             + WEIGHT_DNSADDRESSES
             + WEIGHT_MTU;
@@ -89,11 +97,16 @@
     @VisibleForTesting
     public NetworkAttributes(
             @Nullable final Inet4Address assignedV4Address,
+            @Nullable final Long assignedV4AddressExpiry,
             @Nullable final String groupHint,
             @Nullable final List<InetAddress> dnsAddresses,
             @Nullable final Integer mtu) {
         if (mtu != null && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+        if (assignedV4AddressExpiry != null && assignedV4AddressExpiry <= 0) {
+            throw new IllegalArgumentException("lease expiry can't be negative or zero");
+        }
         this.assignedV4Address = assignedV4Address;
+        this.assignedV4AddressExpiry = assignedV4AddressExpiry;
         this.groupHint = groupHint;
         this.dnsAddresses = null == dnsAddresses ? null :
                 Collections.unmodifiableList(new ArrayList<>(dnsAddresses));
@@ -105,6 +118,8 @@
         // The call to the other constructor must be the first statement of this constructor,
         // so everything has to be inline
         this((Inet4Address) getByAddressOrNull(parcelable.assignedV4Address),
+                parcelable.assignedV4AddressExpiry > 0
+                        ? parcelable.assignedV4AddressExpiry : null,
                 parcelable.groupHint,
                 blobArrayToInetAddressList(parcelable.dnsAddresses),
                 parcelable.mtu >= 0 ? parcelable.mtu : null);
@@ -150,6 +165,8 @@
         final NetworkAttributesParcelable parcelable = new NetworkAttributesParcelable();
         parcelable.assignedV4Address =
                 (null == assignedV4Address) ? null : assignedV4Address.getAddress();
+        parcelable.assignedV4AddressExpiry =
+                (null == assignedV4AddressExpiry) ? 0 : assignedV4AddressExpiry;
         parcelable.groupHint = groupHint;
         parcelable.dnsAddresses = inetAddressListToBlobArray(dnsAddresses);
         parcelable.mtu = (null == mtu) ? -1 : mtu;
@@ -168,6 +185,8 @@
     public float getNetworkGroupSamenessConfidence(@NonNull final NetworkAttributes o) {
         final float samenessScore =
                 samenessContribution(WEIGHT_ASSIGNEDV4ADDR, assignedV4Address, o.assignedV4Address)
+                + samenessContribution(WEIGHT_ASSIGNEDV4ADDREXPIRY, assignedV4AddressExpiry,
+                      o.assignedV4AddressExpiry)
                 + samenessContribution(WEIGHT_GROUPHINT, groupHint, o.groupHint)
                 + samenessContribution(WEIGHT_DNSADDRESSES, dnsAddresses, o.dnsAddresses)
                 + samenessContribution(WEIGHT_MTU, mtu, o.mtu);
@@ -189,6 +208,8 @@
         @Nullable
         private Inet4Address mAssignedAddress;
         @Nullable
+        private Long mAssignedAddressExpiry;
+        @Nullable
         private String mGroupHint;
         @Nullable
         private List<InetAddress> mDnsAddresses;
@@ -206,6 +227,20 @@
         }
 
         /**
+         * Set the lease expiry timestamp of assigned v4 address.
+         * @param assignedV4AddressExpiry The lease expiry timestamp of assigned v4 address.
+         * @return This builder.
+         */
+        public Builder setAssignedV4AddressExpiry(
+                @Nullable final Long assignedV4AddressExpiry) {
+            if (null != assignedV4AddressExpiry && assignedV4AddressExpiry <= 0) {
+                throw new IllegalArgumentException("lease expiry can't be negative or zero");
+            }
+            mAssignedAddressExpiry = assignedV4AddressExpiry;
+            return this;
+        }
+
+        /**
          * Set the group hint.
          * @param groupHint The group hint.
          * @return This builder.
@@ -248,14 +283,15 @@
          * @return The built NetworkAttributes object.
          */
         public NetworkAttributes build() {
-            return new NetworkAttributes(mAssignedAddress, mGroupHint, mDnsAddresses, mMtu);
+            return new NetworkAttributes(mAssignedAddress, mAssignedAddressExpiry,
+                  mGroupHint, mDnsAddresses, mMtu);
         }
     }
 
     /** @hide */
     public boolean isEmpty() {
-        return (null == assignedV4Address) && (null == groupHint)
-                && (null == dnsAddresses) && (null == mtu);
+        return (null == assignedV4Address) && (null == assignedV4AddressExpiry)
+                && (null == groupHint) && (null == dnsAddresses) && (null == mtu);
     }
 
     @Override
@@ -263,6 +299,7 @@
         if (!(o instanceof NetworkAttributes)) return false;
         final NetworkAttributes other = (NetworkAttributes) o;
         return Objects.equals(assignedV4Address, other.assignedV4Address)
+                && Objects.equals(assignedV4AddressExpiry, other.assignedV4AddressExpiry)
                 && Objects.equals(groupHint, other.groupHint)
                 && Objects.equals(dnsAddresses, other.dnsAddresses)
                 && Objects.equals(mtu, other.mtu);
@@ -270,7 +307,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
+        return Objects.hash(assignedV4Address, assignedV4AddressExpiry,
+                groupHint, dnsAddresses, mtu);
     }
 
     /** Pretty print */
@@ -286,6 +324,13 @@
             nullFields.add("assignedV4Addr");
         }
 
+        if (null != assignedV4AddressExpiry) {
+            resultJoiner.add("assignedV4AddressExpiry :");
+            resultJoiner.add(assignedV4AddressExpiry.toString());
+        } else {
+            nullFields.add("assignedV4AddressExpiry");
+        }
+
         if (null != groupHint) {
             resultJoiner.add("groupHint :");
             resultJoiner.add(groupHint);
diff --git a/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
index 0894d72..997eb2b 100644
--- a/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
+++ b/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -30,6 +30,7 @@
  */
 parcelable NetworkAttributesParcelable {
     byte[] assignedV4Address;
+    long assignedV4AddressExpiry;
     String groupHint;
     Blob[] dnsAddresses;
     int mtu;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4776aa1..ecde850 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2915,14 +2915,14 @@
         sDefaults.putBoolean(KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL, true);
         sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
+        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -118);
-        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_POOR */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -128);
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118);
+        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
         /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 10);
-        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_POOR */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, -30);
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
         /* Default value is 1024 kbps */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024);
         /* Default value is 10 seconds */
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index bda8812..3728de2 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -110,6 +110,22 @@
     }
 
     /**
+     * @return MCC or null for CDMA
+     * @hide
+     */
+    public String getMccString() {
+        return mMccStr;
+    }
+
+    /**
+     * @return MNC or null for CDMA
+     * @hide
+     */
+    public String getMncString() {
+        return mMncStr;
+    }
+
+    /**
      * Returns the channel number of the cell identity.
      *
      * @hide
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index fa19867..637f49d 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -109,6 +109,13 @@
         return new CellIdentityCdma(this);
     }
 
+    /** @hide */
+    public CellIdentityCdma sanitizeLocationInfo() {
+        return new CellIdentityCdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                mAlphaLong, mAlphaShort);
+    }
+
     /**
      * Take the latitude and longitude in 1/4 seconds and see if
      * the reported location is on Null Island.
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 9a24e47..6c1048f 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -97,6 +97,12 @@
         return new CellIdentityGsm(this);
     }
 
+    /** @hide */
+    public CellIdentityGsm sanitizeLocationInfo() {
+        return new CellIdentityGsm(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+    }
+
     /**
      * @return 3-digit Mobile Country Code, 0..999,
      *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 51393b9..824fbc5 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -113,6 +113,13 @@
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
     }
 
+    /** @hide */
+    public CellIdentityLte sanitizeLocationInfo() {
+        return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+    }
+
     CellIdentityLte copy() {
         return new CellIdentityLte(this);
     }
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 771e7b9..44896e2 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -46,7 +46,7 @@
      *
      * @hide
      */
-    public CellIdentityNr(int pci, int tac, int nrArfcn,  String mccStr, String mncStr,
+    public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
             long nci, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
         mPci = pci;
@@ -55,6 +55,12 @@
         mNci = nci;
     }
 
+    /** @hide */
+    public CellIdentityNr sanitizeLocationInfo() {
+        return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
+    }
+
     /**
      * @return a CellLocation object for this CellIdentity.
      * @hide
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 19b11b6..a591bd1 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -90,6 +90,12 @@
                 cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
     }
 
+    /** @hide */
+    public CellIdentityTdscdma sanitizeLocationInfo() {
+        return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
+    }
+
     CellIdentityTdscdma copy() {
         return new CellIdentityTdscdma(this);
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 6e09784..3a1772f 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -91,6 +91,13 @@
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
     }
 
+    /** @hide */
+    public CellIdentityWcdma sanitizeLocationInfo() {
+        return new CellIdentityWcdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr,
+                mAlphaLong, mAlphaShort);
+    }
+
     CellIdentityWcdma copy() {
         return new CellIdentityWcdma(this);
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index cdaf6ed..2142feb 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -197,6 +197,11 @@
     @NonNull
     public abstract CellSignalStrength getCellSignalStrength();
 
+    /** @hide */
+    public CellInfo sanitizeLocationInfo() {
+        return null;
+    }
+
     /**
      * Gets the connection status of this cell.
      *
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 359c8be..d9f44b8 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -90,6 +90,15 @@
     public CellSignalStrengthCdma getCellSignalStrength() {
         return mCellSignalStrengthCdma;
     }
+
+    /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        CellInfoCdma result = new CellInfoCdma(this);
+        result.mCellIdentityCdma = mCellIdentityCdma.sanitizeLocationInfo();
+        return result;
+    }
+
     /** @hide */
     public void setCellSignalStrength(CellSignalStrengthCdma css) {
         mCellSignalStrengthCdma = css;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index dc2779f..1cecbc6 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -84,6 +84,15 @@
     public CellSignalStrengthGsm getCellSignalStrength() {
         return mCellSignalStrengthGsm;
     }
+
+    /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        CellInfoGsm result = new CellInfoGsm(this);
+        result.mCellIdentityGsm = mCellIdentityGsm.sanitizeLocationInfo();
+        return result;
+    }
+
     /** @hide */
     public void setCellSignalStrength(CellSignalStrengthGsm css) {
         mCellSignalStrengthGsm = css;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 0e9623d..45f4b1d 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -96,6 +96,15 @@
         if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte);
         return mCellSignalStrengthLte;
     }
+
+    /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        CellInfoLte result = new CellInfoLte(this);
+        result.mCellIdentityLte = mCellIdentityLte.sanitizeLocationInfo();
+        return result;
+    }
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setCellSignalStrength(CellSignalStrengthLte css) {
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index 7f7902c..2a8b067 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -36,6 +36,13 @@
         mCellSignalStrength = CellSignalStrengthNr.CREATOR.createFromParcel(in);
     }
 
+    private CellInfoNr(CellInfoNr other, boolean sanitizeLocationInfo) {
+        super(other);
+        mCellIdentity = sanitizeLocationInfo ? other.mCellIdentity.sanitizeLocationInfo()
+                : other.mCellIdentity;
+        mCellSignalStrength = other.mCellSignalStrength;
+    }
+
     @Override
     @NonNull
     public CellIdentity getCellIdentity() {
@@ -48,6 +55,12 @@
         return mCellSignalStrength;
     }
 
+    /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        return new CellInfoNr(this, true);
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(), mCellIdentity, mCellSignalStrength);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 1830086..ccafda6 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -91,6 +91,14 @@
     }
 
     /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        CellInfoTdscdma result = new CellInfoTdscdma(this);
+        result.mCellIdentityTdscdma = mCellIdentityTdscdma.sanitizeLocationInfo();
+        return result;
+    }
+
+    /** @hide */
     public void setCellSignalStrength(CellSignalStrengthTdscdma css) {
         mCellSignalStrengthTdscdma = css;
     }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index fe06c78..81fc7bb 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -84,6 +84,15 @@
     public CellSignalStrengthWcdma getCellSignalStrength() {
         return mCellSignalStrengthWcdma;
     }
+
+    /** @hide */
+    @Override
+    public CellInfo sanitizeLocationInfo() {
+        CellInfoWcdma result = new CellInfoWcdma(this);
+        result.mCellIdentityWcdma = mCellIdentityWcdma.sanitizeLocationInfo();
+        return result;
+    }
+
     /** @hide */
     public void setCellSignalStrength(CellSignalStrengthWcdma css) {
         mCellSignalStrengthWcdma = css;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 4d1b89c..def7fbe 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -941,8 +941,7 @@
      * @return associated subscription id
      */
     public int getSubscriptionId() {
-        final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
-                ? getDefaultSmsSubscriptionId() : mSubId;
+        final int subId = getSubIdOrDefault();
         boolean isSmsSimPickActivityNeeded = false;
         final Context context = ActivityThread.currentApplication().getApplicationContext();
         try {
@@ -975,6 +974,17 @@
     }
 
     /**
+     * @return the subscription ID associated with this {@link SmsManager} or the default set by the
+     * user if this instance was created using {@link SmsManager#getDefault}.
+     *
+     * If there is no default set by the user, this method returns
+     * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+     */
+    private int getSubIdOrDefault() {
+        return (mSubId == DEFAULT_SUBSCRIPTION_ID) ? getDefaultSmsSubscriptionId() : mSubId;
+    }
+
+    /**
      * Returns the ISms service, or throws an UnsupportedOperationException if
      * the service does not exist.
      */
@@ -1141,8 +1151,9 @@
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
-                success = iSms.enableCellBroadcastForSubscriber(
-                        getSubscriptionId(), messageIdentifier, ranType);
+                // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+                success = iSms.enableCellBroadcastForSubscriber(getSubIdOrDefault(),
+                        messageIdentifier, ranType);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1177,8 +1188,9 @@
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
-                success = iSms.disableCellBroadcastForSubscriber(
-                        getSubscriptionId(), messageIdentifier, ranType);
+                // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+                success = iSms.disableCellBroadcastForSubscriber(getSubIdOrDefault(),
+                        messageIdentifier, ranType);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1220,7 +1232,8 @@
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
-                success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+                // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+                success = iSms.enableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
                         startMessageId, endMessageId, ranType);
             }
         } catch (RemoteException ex) {
@@ -1263,7 +1276,8 @@
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
-                success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+                // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+                success = iSms.disableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
                         startMessageId, endMessageId, ranType);
             }
         } catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b781b10..a404ad8 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -161,11 +161,6 @@
     private String mGroupUUID;
 
     /**
-     *  A property in opportunistic subscription to indicate whether it is metered or not.
-     */
-    private boolean mIsMetered;
-
-    /**
      * Whether group of the subscription is disabled.
      * This is only useful if it's a grouped opportunistic subscription. In this case, if all
      * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM
@@ -197,7 +192,7 @@
             @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
-                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+                false, null, TelephonyManager.UNKNOWN_CARRIER_ID,
                 SubscriptionManager.PROFILE_CLASS_DEFAULT);
     }
 
@@ -208,10 +203,10 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
+            @Nullable String groupUUID, int carrierId, int profileClass) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
-                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+                isOpportunistic, groupUUID, false, carrierId, profileClass,
                 SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
     }
 
@@ -222,7 +217,7 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
-            boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+            boolean isOpportunistic, @Nullable String groupUUID,
             boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
         this.mId = id;
         this.mIccId = iccId;
@@ -243,7 +238,6 @@
         this.mCardId = cardId;
         this.mIsOpportunistic = isOpportunistic;
         this.mGroupUUID = groupUUID;
-        this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
         this.mCarrierId = carrierId;
         this.mProfileClass = profileClass;
@@ -472,18 +466,6 @@
     }
 
     /**
-     * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's
-     * metered or not.This is one of the factors when deciding to switch to the subscription.
-     * (a non-metered subscription, for example, would likely be preferred over a metered one).
-     *
-     * @return whether subscription is metered.
-     * @hide
-     */
-    public boolean isMetered() {
-        return mIsMetered;
-    }
-
-    /**
      * @return the profile class of this subscription.
      * @hide
      */
@@ -623,7 +605,6 @@
             int cardId = source.readInt();
             boolean isOpportunistic = source.readBoolean();
             String groupUUID = source.readString();
-            boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
             int carrierid = source.readInt();
             int profileClass = source.readInt();
@@ -632,7 +613,7 @@
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                     isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isMetered, isGroupDisabled, carrierid, profileClass, subType);
+                    isGroupDisabled, carrierid, profileClass, subType);
         }
 
         @Override
@@ -662,7 +643,6 @@
         dest.writeInt(mCardId);
         dest.writeBoolean(mIsOpportunistic);
         dest.writeString(mGroupUUID);
-        dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
         dest.writeInt(mProfileClass);
@@ -702,7 +682,7 @@
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
-                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+                + " mIsGroupDisabled=" + mIsGroupDisabled
                 + " profileClass=" + mProfileClass
                 + " subscriptionType=" + mSubscriptionType + "}";
     }
@@ -710,7 +690,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
-                mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
+                mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
                 mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
                 mIsGroupDisabled, mCarrierId, mProfileClass);
     }
@@ -736,7 +716,6 @@
                 && mIsOpportunistic == toCompare.mIsOpportunistic
                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
                 && mCarrierId == toCompare.mCarrierId
-                && mIsMetered == toCompare.mIsMetered
                 && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
                 && Objects.equals(mIccId, toCompare.mIccId)
                 && Objects.equals(mNumber, toCompare.mNumber)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 6963176..92ac619 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2578,7 +2578,9 @@
      *              {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
      *              it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *              is used to determine which modem is preferred.
-     * @param needValidation whether validation is needed before switch happens.
+     * @param needValidation whether Telephony will wait until the network is validated by
+     *              connectivity service before switching data to it. More details see
+     *              {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
      * @param executor The executor of where the callback will execute.
      * @param callback Callback will be triggered once it succeeds or failed.
      *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
@@ -2836,29 +2838,6 @@
     }
 
     /**
-     * Set if a subscription is metered or not. Similar to Wi-Fi, metered means
-     * user may be charged more if more data is used.
-     *
-     * By default all Cellular networks are considered metered. System or carrier privileged apps
-     * can set a subscription un-metered which will be considered when system switches data between
-     * primary subscription and opportunistic subscription.
-     *
-     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
-     * privilege permission of the subscription.
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return {@code true} if the operation is succeed, {@code false} otherwise.
-     */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setMetered(boolean isMetered, int subId) {
-        if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId);
-        return setSubscriptionPropertyHelper(subId, "setIsMetered",
-                (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1;
-    }
-
-    /**
      * Whether a subscription is visible to API caller. If it's a bundled opportunistic
      * subscription, it should be hidden anywhere in Settings, dialer, status bar etc.
      * Exception is if caller owns carrier privilege, in which case they will
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index feed813..3d3ef98 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6928,6 +6928,17 @@
      * app has carrier privileges (see {@link #hasCarrierPrivileges})
      * and {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
      *
+     * If the system-wide location switch is off, apps may still call this API, with the
+     * following constraints:
+     * <ol>
+     *     <li>The app must hold the {@code android.permission.NETWORK_SCAN} permission.</li>
+     *     <li>The app must not supply any specific bands or channels to scan.</li>
+     *     <li>The app must only specify MCC/MNC pairs that are
+     *     associated to a SIM in the device.</li>
+     *     <li>Returned results will have no meaningful info other than signal strength
+     *     and MCC/MNC info.</li>
+     * </ol>
+     *
      * @param request Contains all the RAT with bands/channels that need to be scanned.
      * @param executor The executor through which the callback should be invoked. Since the scan
      *        request may trigger multiple callbacks and they must be invoked in the same order as
@@ -10398,7 +10409,7 @@
     @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
             SET_OPPORTUNISTIC_SUB_SUCCESS,
             SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
-            SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+            SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
     public @interface SetOpportunisticSubscriptionResult {}
 
     /**
@@ -10412,9 +10423,9 @@
     public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
 
     /**
-     * The parameter passed in is invalid.
+     * The subscription is not valid. It must be an active opportunistic subscription.
      */
-    public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+    public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 91f74b8..28747da 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -53,6 +53,11 @@
     public static final int CALLBACK_SCAN_ERROR = 2;
     /** @hide */
     public static final int CALLBACK_SCAN_COMPLETE = 3;
+    /** @hide */
+    public static final int CALLBACK_RESTRICTED_SCAN_RESULTS = 4;
+
+    /** @hide */
+    public static final int INVALID_SCAN_ID = -1;
 
     /**
      * The caller of
@@ -129,6 +134,7 @@
                 }
 
                 switch (message.what) {
+                    case CALLBACK_RESTRICTED_SCAN_RESULTS:
                     case CALLBACK_SCAN_RESULTS:
                         try {
                             final Bundle b = message.getData();
@@ -137,9 +143,9 @@
                             for (int i = 0; i < parcelables.length; i++) {
                                 ci[i] = (CellInfo) parcelables[i];
                             }
-                            executor.execute(() ->{
+                            executor.execute(() -> {
                                 Rlog.d(TAG, "onResults: " + ci.toString());
-                                callback.onResults((List<CellInfo>) Arrays.asList(ci));
+                                callback.onResults(Arrays.asList(ci));
                             });
                         } catch (Exception e) {
                             Rlog.e(TAG, "Exception in networkscan callback onResults", e);
@@ -200,6 +206,10 @@
             if (telephony != null) {
                 int scanId = telephony.requestNetworkScan(
                         subId, request, mMessenger, new Binder(), callingPackage);
+                if (scanId == INVALID_SCAN_ID) {
+                    Rlog.e(TAG, "Failed to initiate network scan");
+                    return null;
+                }
                 saveScanInfo(scanId, request, executor, callback);
                 return new NetworkScan(scanId, subId);
             }
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 50d372e..daea9d5 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -205,15 +205,6 @@
     String setSubscriptionGroup(in int[] subIdList, String callingPackage);
 
     /**
-     * Set whether a subscription is metered
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return the number of records updated
-     */
-    int setMetered(boolean isMetered, int subId, String callingPackage);
-
-    /**
      * Set which subscription is preferred for cellular data. It's
      * designed to overwrite default data subscription temporarily.
      *
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
index 76cccc9..1a3ea609 100644
--- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -44,6 +44,8 @@
         assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
 
         builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        // lease will expire in two hours
+        builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
         // groupHint stays null this time around
         builder.setDnsAddresses(Collections.emptyList());
         builder.setMtu(18);
@@ -51,6 +53,7 @@
         assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
 
         builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
+        builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
         builder.setGroupHint("groupHint");
         builder.setDnsAddresses(Arrays.asList(
                 InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
@@ -66,7 +69,7 @@
         // Verify that this test does not miss any new field added later.
         // If any field is added to NetworkAttributes it must be tested here for parceling
         // roundtrip.
-        assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+        assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
                 .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
     }
 
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index afefd5e..46a8955 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -499,7 +499,7 @@
             };
 
             try {
-                doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
+                doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
                 doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
             } catch (RemoteException e) {
                 fail(e.getMessage());
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
index dc20185..fb84611 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -57,6 +57,7 @@
         final NetworkAttributes na =
                 new NetworkAttributes(
                         (Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
+                        System.currentTimeMillis() + 7_200_000,
                         "some hint",
                         Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
                                 Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),