Merge changes from topic "sp26-networkstats-cts"

* changes:
  [SP26] add CTS for NetworkStats
  [SP26.2] add a method in NetworkStats that removes empty entries
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 6f0a4f9..9086d49 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -659,7 +659,8 @@
     public abstract static class ConnectivityDiagnosticsCallback {
         /**
          * Called when the platform completes a data connectivity check. This will also be invoked
-         * upon registration with the latest report.
+         * immediately upon registration for each network matching the request with the latest
+         * report, if a report has already been generated for that network.
          *
          * <p>The Network specified in the ConnectivityReport may not be active any more when this
          * method is invoked.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0f48ac2..6892a94 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -705,6 +705,36 @@
     @Deprecated
     public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
 
+    /**
+     * @deprecated Use {@link NetworkCapabilities} instead.
+     * @hide
+     */
+    @Deprecated
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "TYPE_" }, value = {
+                TYPE_NONE,
+                TYPE_MOBILE,
+                TYPE_WIFI,
+                TYPE_MOBILE_MMS,
+                TYPE_MOBILE_SUPL,
+                TYPE_MOBILE_DUN,
+                TYPE_MOBILE_HIPRI,
+                TYPE_WIMAX,
+                TYPE_BLUETOOTH,
+                TYPE_DUMMY,
+                TYPE_ETHERNET,
+                TYPE_MOBILE_FOTA,
+                TYPE_MOBILE_IMS,
+                TYPE_MOBILE_CBS,
+                TYPE_WIFI_P2P,
+                TYPE_MOBILE_IA,
+                TYPE_MOBILE_EMERGENCY,
+                TYPE_PROXY,
+                TYPE_VPN,
+                TYPE_TEST
+    })
+    public @interface LegacyNetworkType {}
+
     // Deprecated constants for return values of startUsingNetworkFeature. They used to live
     // in com.android.internal.telephony.PhoneConstants until they were made inaccessible.
     private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0;
diff --git a/core/java/android/net/InvalidPacketException.java b/core/java/android/net/InvalidPacketException.java
index 909998d..b3b0f11 100644
--- a/core/java/android/net/InvalidPacketException.java
+++ b/core/java/android/net/InvalidPacketException.java
@@ -28,7 +28,7 @@
  */
 @SystemApi
 public class InvalidPacketException extends Exception {
-    public final int error;
+    private final int mError;
 
     // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS.
     /** Invalid IP address. */
@@ -56,6 +56,11 @@
      * See the error code for details.
      */
     public InvalidPacketException(@ErrorCode final int error) {
-        this.error = error;
+        this.mError = error;
+    }
+
+    /** Get error code. */
+    public int getError() {
+        return mError;
     }
 }
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 6c0ba2f..e21cb44 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -19,6 +19,7 @@
 import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
 import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.net.util.IpUtils;
@@ -37,17 +38,17 @@
 
     /** Source IP address */
     @NonNull
-    public final InetAddress srcAddress;
+    private final InetAddress mSrcAddress;
 
     /** Destination IP address */
     @NonNull
-    public final InetAddress dstAddress;
+    private final InetAddress mDstAddress;
 
     /** Source port */
-    public final int srcPort;
+    private final int mSrcPort;
 
     /** Destination port */
-    public final int dstPort;
+    private final int mDstPort;
 
     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
     private final byte[] mPacket;
@@ -60,13 +61,14 @@
     /**
      * A holding class for data necessary to build a keepalive packet.
      */
-    protected KeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
-            @NonNull InetAddress dstAddress, int dstPort,
-                    @NonNull byte[] data) throws InvalidPacketException {
-        this.srcAddress = srcAddress;
-        this.dstAddress = dstAddress;
-        this.srcPort = srcPort;
-        this.dstPort = dstPort;
+    protected KeepalivePacketData(@NonNull InetAddress srcAddress,
+            @IntRange(from = 0, to = 65535) int srcPort, @NonNull InetAddress dstAddress,
+            @IntRange(from = 0, to = 65535) int dstPort,
+            @NonNull byte[] data) throws InvalidPacketException {
+        this.mSrcAddress = srcAddress;
+        this.mDstAddress = dstAddress;
+        this.mSrcPort = srcPort;
+        this.mDstPort = dstPort;
         this.mPacket = data;
 
         // Check we have two IP addresses of the same family.
@@ -83,6 +85,31 @@
         }
     }
 
+    /** Get source IP address. */
+    @NonNull
+    public InetAddress getSrcAddress() {
+        return mSrcAddress;
+    }
+
+    /** Get destination IP address. */
+    @NonNull
+    public InetAddress getDstAddress() {
+        return mDstAddress;
+    }
+
+    /** Get source port number. */
+    public int getSrcPort() {
+        return mSrcPort;
+    }
+
+    /** Get destination port number. */
+    public int getDstPort() {
+        return mDstPort;
+    }
+
+    /**
+     * Returns a byte array of the given packet data.
+     */
     @NonNull
     public byte[] getPacket() {
         return mPacket.clone();
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index 29da495..22288b6 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -94,10 +94,10 @@
 
     /** Write to parcel */
     public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeString(srcAddress.getHostAddress());
-        out.writeString(dstAddress.getHostAddress());
-        out.writeInt(srcPort);
-        out.writeInt(dstPort);
+        out.writeString(getSrcAddress().getHostAddress());
+        out.writeString(getDstAddress().getHostAddress());
+        out.writeInt(getSrcPort());
+        out.writeInt(getDstPort());
     }
 
     /** Parcelable Creator */
@@ -115,7 +115,7 @@
                                     dstAddress, dstPort);
                     } catch (InvalidPacketException e) {
                         throw new IllegalArgumentException(
-                                "Invalid NAT-T keepalive data: " + e.error);
+                                "Invalid NAT-T keepalive data: " + e.getError());
                     }
                 }
 
@@ -128,14 +128,16 @@
     public boolean equals(@Nullable final Object o) {
         if (!(o instanceof NattKeepalivePacketData)) return false;
         final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
-        return this.srcAddress.equals(other.srcAddress)
-            && this.dstAddress.equals(other.dstAddress)
-            && this.srcPort == other.srcPort
-            && this.dstPort == other.dstPort;
+        final InetAddress srcAddress = getSrcAddress();
+        final InetAddress dstAddress = getDstAddress();
+        return srcAddress.equals(other.getSrcAddress())
+            && dstAddress.equals(other.getDstAddress())
+            && getSrcPort() == other.getSrcPort()
+            && getDstPort() == other.getDstPort();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(srcAddress, dstAddress, srcPort, dstPort);
+        return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
     }
 }
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 5c754a1..8119df9 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -32,18 +34,52 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * A Utility class for handling for communicating between bearer-specific
+ * A utility class for handling for communicating between bearer-specific
  * code and ConnectivityService.
  *
+ * An agent manages the life cycle of a network. A network starts its
+ * life cycle when {@link register} is called on NetworkAgent. The network
+ * is then connecting. When full L3 connectivity has been established,
+ * the agent shoud call {@link setConnected} to inform the system that
+ * this network is ready to use. When the network disconnects its life
+ * ends and the agent should call {@link unregister}, at which point the
+ * system will clean up and free resources.
+ * Any reconnection becomes a new logical network, so after a network
+ * is disconnected the agent cannot be used any more. Network providers
+ * should create a new NetworkAgent instance to handle new connections.
+ *
  * A bearer may have more than one NetworkAgent if it can simultaneously
  * support separate networks (IMS / Internet / MMS Apns on cellular, or
  * perhaps connections with different SSID or P2P for Wi-Fi).
  *
+ * This class supports methods to start and stop sending keepalive packets.
+ * Keepalive packets are typically sent at periodic intervals over a network
+ * with NAT when there is no other traffic to avoid the network forcefully
+ * closing the connection. NetworkAgents that manage technologies that
+ * have hardware support for keepalive should implement the related
+ * methods to save battery life. NetworkAgent that cannot get support
+ * without waking up the CPU should not, as this would be prohibitive in
+ * terms of battery - these agents should simply not override the related
+ * methods, which results in the implementation returning
+ * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate.
+ *
+ * Keepalive packets need to be sent at relatively frequent intervals
+ * (a few seconds to a few minutes). As the contents of keepalive packets
+ * depend on the current network status, hardware needs to be configured
+ * to send them and has a limited amount of memory to do so. The HAL
+ * formalizes this as slots that an implementation can configure to send
+ * the correct packets. Devices typically have a small number of slots
+ * per radio technology, and the specific number of slots for each
+ * technology is specified in configuration files.
+ * {@see SocketKeepalive} for details.
+ *
  * @hide
  */
 @SystemApi
@@ -65,7 +101,7 @@
     private final String LOG_TAG;
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
-    private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
+    private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
     private volatile long mLastBwRefreshTime = 0;
     private static final long BW_REFRESH_MIN_WIN_MS = 500;
     private boolean mBandwidthUpdateScheduled = false;
@@ -74,6 +110,8 @@
     // into the internal API of ConnectivityService.
     @NonNull
     private NetworkInfo mNetworkInfo;
+    @NonNull
+    private final Object mRegisterLock = new Object();
 
     /**
      * The ID of the {@link NetworkProvider} that created this object, or
@@ -158,6 +196,14 @@
      */
     public static final int VALIDATION_STATUS_NOT_VALID = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "VALIDATION_STATUS_" }, value = {
+            VALIDATION_STATUS_VALID,
+            VALIDATION_STATUS_NOT_VALID
+    })
+    public @interface ValidationStatus {}
+
     // TODO: remove.
     /** @hide */
     public static final int VALID_NETWORK = 1;
@@ -202,7 +248,7 @@
      * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent
      * periodically on the given interval.
      *
-     *   arg1 = the slot number of the keepalive to start
+     *   arg1 = the hardware slot number of the keepalive to start
      *   arg2 = interval in seconds
      *   obj = KeepalivePacketData object describing the data to be sent
      *
@@ -214,7 +260,7 @@
     /**
      * Requests that the specified keepalive packet be stopped.
      *
-     * arg1 = slot number of the keepalive to stop.
+     * arg1 = hardware slot number of the keepalive to stop.
      *
      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
      * @hide
@@ -229,7 +275,7 @@
      * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive},
      * so that the app's {@link SocketKeepalive.Callback} methods can be called.
      *
-     * arg1 = slot number of the keepalive
+     * arg1 = hardware slot number of the keepalive
      * arg2 = error code
      * @hide
      */
@@ -259,7 +305,7 @@
      * remote site will send ACK packets in response to the keepalive packets, the firmware also
      * needs to be configured to properly filter the ACKs to prevent the system from waking up.
      * This does not happen with UDP, so this message is TCP-specific.
-     * arg1 = slot number of the keepalive to filter for.
+     * arg1 = hardware slot number of the keepalive to filter for.
      * obj = the keepalive packet to send repeatedly.
      * @hide
      */
@@ -268,7 +314,7 @@
     /**
      * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See
      * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}.
-     * arg1 = slot number of the keepalive packet filter to remove.
+     * arg1 = hardware slot number of the keepalive packet filter to remove.
      * @hide
      */
     public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
@@ -441,7 +487,15 @@
                                 + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ")
                                 + redirectUrl);
                     }
-                    onValidationStatus(msg.arg1 /* status */, redirectUrl);
+                    Uri uri = null;
+                    try {
+                        if (null != redirectUrl) {
+                            uri = Uri.parse(redirectUrl);
+                        }
+                    } catch (Exception e) {
+                        Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e);
+                    }
+                    onValidationStatus(msg.arg1 /* status */, uri);
                     break;
                 }
                 case CMD_SAVE_ACCEPT_UNVALIDATED: {
@@ -489,19 +543,29 @@
 
     /**
      * Register this network agent with ConnectivityService.
+     *
+     * This method can only be called once per network agent.
+     *
      * @return the Network associated with this network agent (which can also be obtained later
      *         by calling getNetwork() on this agent).
+     * @throws IllegalStateException thrown by the system server if this network agent is
+     *         already registered.
      */
     @NonNull
     public Network register() {
         if (VDBG) log("Registering NetworkAgent");
         final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
                 .getSystemService(Context.CONNECTIVITY_SERVICE);
-        mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
-                new NetworkInfo(mInitialConfiguration.info),
-                mInitialConfiguration.properties, mInitialConfiguration.capabilities,
-                mInitialConfiguration.score, mInitialConfiguration.config, providerId);
-        mInitialConfiguration = null; // All this memory can now be GC'd
+        synchronized (mRegisterLock) {
+            if (mNetwork != null) {
+                throw new IllegalStateException("Agent already registered");
+            }
+            mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
+                    new NetworkInfo(mInitialConfiguration.info),
+                    mInitialConfiguration.properties, mInitialConfiguration.capabilities,
+                    mInitialConfiguration.score, mInitialConfiguration.config, providerId);
+            mInitialConfiguration = null; // All this memory can now be GC'd
+        }
         return mNetwork;
     }
 
@@ -544,13 +608,14 @@
      * Must be called by the agent when the network's {@link LinkProperties} change.
      * @param linkProperties the new LinkProperties.
      */
-    public void sendLinkProperties(@NonNull LinkProperties linkProperties) {
+    public final void sendLinkProperties(@NonNull LinkProperties linkProperties) {
         Objects.requireNonNull(linkProperties);
         queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
     }
 
     /**
      * Inform ConnectivityService that this agent has now connected.
+     * Call {@link #unregister} to disconnect.
      */
     public void setConnected() {
         if (mIsLegacy) {
@@ -569,8 +634,7 @@
      */
     public void unregister() {
         if (mIsLegacy) {
-            throw new UnsupportedOperationException(
-                    "Legacy agents can't call unregister.");
+            throw new UnsupportedOperationException("Legacy agents can't call unregister.");
         }
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
@@ -626,7 +690,7 @@
      * @hide TODO: expose something better.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public void sendNetworkInfo(NetworkInfo networkInfo) {
+    public final void sendNetworkInfo(NetworkInfo networkInfo) {
         if (!mIsLegacy) {
             throw new UnsupportedOperationException("Only legacy agents can call sendNetworkInfo.");
         }
@@ -637,7 +701,7 @@
      * Must be called by the agent when the network's {@link NetworkCapabilities} change.
      * @param networkCapabilities the new NetworkCapabilities.
      */
-    public void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+    public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
         Objects.requireNonNull(networkCapabilities);
         mBandwidthUpdatePending.set(false);
         mLastBwRefreshTime = System.currentTimeMillis();
@@ -647,9 +711,10 @@
 
     /**
      * Must be called by the agent to update the score of this network.
-     * @param score the new score.
+     *
+     * @param score the new score, between 0 and 99.
      */
-    public void sendNetworkScore(int score) {
+    public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) {
         if (score < 0) {
             throw new IllegalArgumentException("Score must be >= 0");
         }
@@ -737,11 +802,11 @@
      * subsequent attempts to validate connectivity that fail.
      *
      * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}.
-     * @param redirectUrl If Internet connectivity is being redirected (e.g., on a captive portal),
+     * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal),
      *        this is the destination the probes are being redirected to, otherwise {@code null}.
      */
-    public void onValidationStatus(int status, @Nullable String redirectUrl) {
-        networkStatus(status, redirectUrl);
+    public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) {
+        networkStatus(status, redirectUri.toString());
     }
     /** @hide TODO delete once subclasses have moved to onValidationStatus */
     protected void networkStatus(int status, String redirectUrl) {
@@ -770,7 +835,12 @@
      * @param intervalSeconds the interval between packets
      * @param packet the packet to send.
      */
-    public void onStartSocketKeepalive(int slot, int intervalSeconds,
+    // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should
+    // not be exposed as constants because they may change in the future (API guideline 4.8)
+    // and should have getters if exposed at all. Getters can't be used in the annotation,
+    // so the values unfortunately need to be copied.
+    public void onStartSocketKeepalive(int slot,
+            @IntRange(from = 10, to = 3600) int intervalSeconds,
             @NonNull KeepalivePacketData packet) {
         Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, intervalSeconds,
                 packet);
@@ -801,9 +871,11 @@
      * Must be called by the agent when a socket keepalive event occurs.
      *
      * @param slot the hardware slot on which the event occurred.
-     * @param event the event that occurred.
+     * @param event the event that occurred, as one of the SocketKeepalive.ERROR_*
+     *              or SocketKeepalive.SUCCESS constants.
      */
-    public void sendSocketKeepaliveEvent(int slot, int event) {
+    public final void sendSocketKeepaliveEvent(int slot,
+            @SocketKeepalive.KeepaliveEvent int event) {
         queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event);
     }
     /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */
@@ -845,9 +917,18 @@
     }
 
     /**
-     * Called by ConnectivityService to inform this network transport of signal strength thresholds
+     * Called by ConnectivityService to inform this network agent of signal strength thresholds
      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
      *
+     * When the system updates the list of thresholds that should wake up the CPU for a
+     * given agent it will call this method on the agent. The agent that implement this
+     * should implement it in hardware so as to ensure the CPU will be woken up on breach.
+     * Agents are expected to react to a breach by sending an updated NetworkCapabilities
+     * object with the appropriate signal strength to sendNetworkCapabilities.
+     *
+     * The specific units are bearer-dependent. See details on the units and requests in
+     * {@link NetworkCapabilities.Builder#setSignalStrength}.
+     *
      * @param thresholds the array of thresholds that should trigger wakeups.
      */
     public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index ca9328a..fee868a 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -155,6 +155,7 @@
     /**
      * @return the legacy type
      */
+    @ConnectivityManager.LegacyNetworkType
     public int getLegacyType() {
         return legacyType;
     }
@@ -206,7 +207,7 @@
     /**
      * Builder class to facilitate constructing {@link NetworkAgentConfig} objects.
      */
-    public static class Builder {
+    public static final class Builder {
         private final NetworkAgentConfig mConfig = new NetworkAgentConfig();
 
         /**
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 64e9350..995cb72 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -16,9 +16,12 @@
 
 package android.net;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -32,6 +35,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.Preconditions;
 
@@ -86,6 +90,7 @@
     /**
      * Completely clears the contents of this object, removing even the capabilities that are set
      * by default when the object is constructed.
+     * @hide
      */
     public void clearAll() {
         mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
@@ -115,7 +120,7 @@
         mTransportInfo = nc.mTransportInfo;
         mSignalStrength = nc.mSignalStrength;
         setUids(nc.mUids); // Will make the defensive copy
-        setAdministratorUids(nc.mAdministratorUids);
+        setAdministratorUids(nc.getAdministratorUids());
         mOwnerUid = nc.mOwnerUid;
         mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
         mSSID = nc.mSSID;
@@ -427,11 +432,12 @@
 
     /**
      * Adds the given capability to this {@code NetworkCapability} instance.
-     * Multiple capabilities may be applied sequentially.  Note that when searching
-     * for a network to satisfy a request, all capabilities requested must be satisfied.
+     * Note that when searching for a network to satisfy a request, all capabilities
+     * requested must be satisfied.
      *
      * @param capability the capability to be added.
      * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
      */
     public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
         // If the given capability was previously added to the list of unwanted capabilities
@@ -446,9 +452,9 @@
 
     /**
      * Adds the given capability to the list of unwanted capabilities of this
-     * {@code NetworkCapability} instance.  Multiple unwanted capabilities may be applied
-     * sequentially.  Note that when searching for a network to satisfy a request, the network
-     * must not contain any capability from unwanted capability list.
+     * {@code NetworkCapability} instance. Note that when searching for a network to
+     * satisfy a request, the network must not contain any capability from unwanted capability
+     * list.
      * <p>
      * If the capability was previously added to the list of required capabilities (for
      * example, it was there by default or added using {@link #addCapability(int)} method), then
@@ -468,6 +474,7 @@
      *
      * @param capability the capability to be removed.
      * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
      */
     public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
         // Note that this method removes capabilities that were added via addCapability(int),
@@ -482,7 +489,7 @@
     /**
      * Sets (or clears) the given capability on this {@link NetworkCapabilities}
      * instance.
-     *
+     * @hide
      */
     public @NonNull NetworkCapabilities setCapability(@NetCapability int capability,
             boolean value) {
@@ -757,7 +764,7 @@
 
     /**
      * Adds the given transport type to this {@code NetworkCapability} instance.
-     * Multiple transports may be applied sequentially.  Note that when searching
+     * Multiple transports may be applied.  Note that when searching
      * for a network to satisfy a request, any listed in the request will satisfy the request.
      * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
      * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
@@ -766,6 +773,7 @@
      *
      * @param transportType the transport type to be added.
      * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
      */
     public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) {
         checkValidTransportType(transportType);
@@ -878,6 +886,7 @@
 
     /**
      * Set the UID of the owner app.
+     * @hide
      */
     public @NonNull NetworkCapabilities setOwnerUid(final int uid) {
         mOwnerUid = uid;
@@ -895,6 +904,8 @@
      *   <li>The user's location toggle is on
      * </ol>
      *
+     * Instances of NetworkCapabilities sent to apps without the appropriate permissions will
+     * have this field cleared out.
      */
     public int getOwnerUid() {
         return mOwnerUid;
@@ -910,18 +921,22 @@
      * <p>For NetworkCapability instances being sent from the System Server, this value MUST be
      * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
      * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
+     *
+     * <p>When received from an app in a NetworkRequest this is always cleared out by the system
+     * server. This field is never used for matching NetworkRequests to NetworkAgents.
      */
-    private int[] mAdministratorUids = new int[0];
+    @NonNull private int[] mAdministratorUids = new int[0];
 
     /**
      * Sets the int[] of UIDs that are administrators of this network.
      *
      * <p>UIDs included in administratorUids gain administrator privileges over this Network.
      * Examples of UIDs that should be included in administratorUids are:
+     *
      * <ul>
-     *     <li>Carrier apps with privileges for the relevant subscription
-     *     <li>Active VPN apps
-     *     <li>Other application groups with a particular Network-related role
+     *   <li>Carrier apps with privileges for the relevant subscription
+     *   <li>Active VPN apps
+     *   <li>Other application groups with a particular Network-related role
      * </ul>
      *
      * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
@@ -929,29 +944,78 @@
      * <p>An app is granted owner privileges over Networks that it supplies. The owner UID MUST
      * always be included in administratorUids.
      *
+     * <p>The administrator UIDs are set by network agents.
+     *
      * @param administratorUids the UIDs to be set as administrators of this Network.
+     * @throws IllegalArgumentException if duplicate UIDs are contained in administratorUids
+     * @see #mAdministratorUids
      * @hide
      */
     @NonNull
-    @SystemApi
     public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) {
         mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
+        Arrays.sort(mAdministratorUids);
+        for (int i = 0; i < mAdministratorUids.length - 1; i++) {
+            if (mAdministratorUids[i] >= mAdministratorUids[i + 1]) {
+                throw new IllegalArgumentException("All administrator UIDs must be unique");
+            }
+        }
         return this;
     }
 
     /**
      * Retrieves the UIDs that are administrators of this Network.
      *
+     * <p>This is only populated in NetworkCapabilities objects that come from network agents for
+     * networks that are managed by specific apps on the system, such as carrier privileged apps or
+     * wifi suggestion apps. This will include the network owner.
+     *
      * @return the int[] of UIDs that are administrators of this Network
+     * @see #mAdministratorUids
      * @hide
      */
     @NonNull
     @SystemApi
+    @TestApi
     public int[] getAdministratorUids() {
         return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length);
     }
 
     /**
+     * Tests if the set of administrator UIDs of this network is the same as that of the passed one.
+     *
+     * <p>The administrator UIDs must be in sorted order.
+     *
+     * <p>nc is assumed non-null. Else, NPE.
+     *
+     * @hide
+     */
+    @VisibleForTesting(visibility = PRIVATE)
+    public boolean equalsAdministratorUids(@NonNull final NetworkCapabilities nc) {
+        return Arrays.equals(mAdministratorUids, nc.mAdministratorUids);
+    }
+
+    /**
+     * Combine the administrator UIDs of the capabilities.
+     *
+     * <p>This is only legal if either of the administrators lists are empty, or if they are equal.
+     * Combining administrator UIDs is only possible for combining non-overlapping sets of UIDs.
+     *
+     * <p>If both administrator lists are non-empty but not equal, they conflict with each other. In
+     * this case, it would not make sense to add them together.
+     */
+    private void combineAdministratorUids(@NonNull final NetworkCapabilities nc) {
+        if (nc.mAdministratorUids.length == 0) return;
+        if (mAdministratorUids.length == 0) {
+            mAdministratorUids = Arrays.copyOf(nc.mAdministratorUids, nc.mAdministratorUids.length);
+            return;
+        }
+        if (!equalsAdministratorUids(nc)) {
+            throw new IllegalStateException("Can't combine two different administrator UID lists");
+        }
+    }
+
+    /**
      * Value indicating that link bandwidth is unspecified.
      * @hide
      */
@@ -969,15 +1033,10 @@
      * Sets the upstream bandwidth for this network in Kbps.  This always only refers to
      * the estimated first hop transport bandwidth.
      * <p>
-     * Note that when used to request a network, this specifies the minimum acceptable.
-     * When received as the state of an existing network this specifies the typical
-     * first hop bandwidth expected.  This is never measured, but rather is inferred
-     * from technology type and other link parameters.  It could be used to differentiate
-     * between very slow 1xRTT cellular links and other faster networks or even between
-     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
-     * fast backhauls and slow backhauls.
+     * {@see Builder#setLinkUpstreamBandwidthKbps}
      *
      * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+     * @hide
      */
     public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
         mLinkUpBandwidthKbps = upKbps;
@@ -998,15 +1057,10 @@
      * Sets the downstream bandwidth for this network in Kbps.  This always only refers to
      * the estimated first hop transport bandwidth.
      * <p>
-     * Note that when used to request a network, this specifies the minimum acceptable.
-     * When received as the state of an existing network this specifies the typical
-     * first hop bandwidth expected.  This is never measured, but rather is inferred
-     * from technology type and other link parameters.  It could be used to differentiate
-     * between very slow 1xRTT cellular links and other faster networks or even between
-     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
-     * fast backhauls and slow backhauls.
+     * {@see Builder#setLinkUpstreamBandwidthKbps}
      *
      * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+     * @hide
      */
     public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
         mLinkDownBandwidthKbps = downKbps;
@@ -1065,6 +1119,7 @@
      * @param networkSpecifier A concrete, parcelable framework class that extends
      *                         NetworkSpecifier.
      * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
      */
     public @NonNull NetworkCapabilities setNetworkSpecifier(
             @NonNull NetworkSpecifier networkSpecifier) {
@@ -1086,7 +1141,6 @@
      * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
-    @SystemApi
     public @NonNull NetworkCapabilities setTransportInfo(@NonNull TransportInfo transportInfo) {
         mTransportInfo = transportInfo;
         return this;
@@ -1096,7 +1150,7 @@
      * Gets the optional bearer specific network specifier. May be {@code null} if not set.
      *
      * @return The optional {@link NetworkSpecifier} specifying the bearer specific network
-     *         specifier or {@code null}. See {@link #setNetworkSpecifier}.
+     *         specifier or {@code null}.
      */
     public @Nullable NetworkSpecifier getNetworkSpecifier() {
         return mNetworkSpecifier;
@@ -1166,6 +1220,7 @@
      * effect when requesting a callback.
      *
      * @param signalStrength the bearer-specific signal strength.
+     * @hide
      */
     public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) {
         mSignalStrength = signalStrength;
@@ -1392,7 +1447,6 @@
      * Sets the SSID of this network.
      * @hide
      */
-    @SystemApi
     public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) {
         mSSID = ssid;
         return this;
@@ -1403,7 +1457,8 @@
      * @hide
      */
     @SystemApi
-    public @Nullable String getSSID() {
+    @TestApi
+    public @Nullable String getSsid() {
         return mSSID;
     }
 
@@ -1455,6 +1510,7 @@
         combineUids(nc);
         combineSSIDs(nc);
         combineRequestor(nc);
+        combineAdministratorUids(nc);
     }
 
     /**
@@ -1568,7 +1624,8 @@
                 && equalsUids(that)
                 && equalsSSID(that)
                 && equalsPrivateDnsBroken(that)
-                && equalsRequestor(that);
+                && equalsRequestor(that)
+                && equalsAdministratorUids(that);
     }
 
     @Override
@@ -1588,7 +1645,8 @@
                 + Objects.hashCode(mTransportInfo) * 41
                 + Objects.hashCode(mPrivateDnsBroken) * 43
                 + Objects.hashCode(mRequestorUid) * 47
-                + Objects.hashCode(mRequestorPackageName) * 53;
+                + Objects.hashCode(mRequestorPackageName) * 53
+                + Arrays.hashCode(mAdministratorUids) * 59;
     }
 
     @Override
@@ -1609,7 +1667,7 @@
         dest.writeArraySet(mUids);
         dest.writeString(mSSID);
         dest.writeBoolean(mPrivateDnsBroken);
-        dest.writeIntArray(mAdministratorUids);
+        dest.writeIntArray(getAdministratorUids());
         dest.writeInt(mOwnerUid);
         dest.writeInt(mRequestorUid);
         dest.writeString(mRequestorPackageName);
@@ -1883,25 +1941,32 @@
     }
 
     /**
-     * Set the uid of the app making the request.
+     * Set the UID of the app making the request.
      *
-     * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
-     * via the public {@link ConnectivityManager} API's will have this field overwritten.
+     * For instances of NetworkCapabilities representing a request, sets the
+     * UID of the app making the request. For a network created by the system,
+     * sets the UID of the only app whose requests can match this network.
+     * This can be set to {@link Process#INVALID_UID} if there is no such app,
+     * or if this instance of NetworkCapabilities is about to be sent to a
+     * party that should not learn about this.
      *
      * @param uid UID of the app.
      * @hide
      */
-    @SystemApi
     public @NonNull NetworkCapabilities setRequestorUid(int uid) {
         mRequestorUid = uid;
         return this;
     }
 
     /**
-     * @return the uid of the app making the request.
+     * Returns the UID of the app making the request.
      *
-     * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest}
-     * object was not obtained from {@link ConnectivityManager}.
+     * For a NetworkRequest being made by an app, contains the app's UID. For a network
+     * created by the system, contains the UID of the only app whose requests can match
+     * this network, or {@link Process#INVALID_UID} if none or if the
+     * caller does not have permission to learn about this.
+     *
+     * @return the uid of the app making the request.
      * @hide
      */
     public int getRequestorUid() {
@@ -1911,23 +1976,29 @@
     /**
      * Set the package name of the app making the request.
      *
-     * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
-     * via the public {@link ConnectivityManager} API's will have this field overwritten.
+     * For instances of NetworkCapabilities representing a request, sets the
+     * package name of the app making the request. For a network created by the system,
+     * sets the package name of the only app whose requests can match this network.
+     * This can be set to null if there is no such app, or if this instance of
+     * NetworkCapabilities is about to be sent to a party that should not learn about this.
      *
      * @param packageName package name of the app.
      * @hide
      */
-    @SystemApi
     public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) {
         mRequestorPackageName = packageName;
         return this;
     }
 
     /**
-     * @return the package name of the app making the request.
+     * Returns the package name of the app making the request.
      *
-     * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
-     * from {@link ConnectivityManager}.
+     * For a NetworkRequest being made by an app, contains the app's package name. For a
+     * network created by the system, contains the package name of the only app whose
+     * requests can match this network, or null if none or if the caller does not have
+     * permission to learn about this.
+     *
+     * @return the package name of the app making the request.
      * @hide
      */
     @Nullable
@@ -1936,9 +2007,9 @@
     }
 
     /**
-     * Set the uid and package name of the app making the request.
+     * Set the uid and package name of the app causing this network to exist.
      *
-     * Note: This is intended to be only invoked from within connectivitiy service.
+     * {@see #setRequestorUid} and {@link #setRequestorPackageName}
      *
      * @param uid UID of the app.
      * @param packageName package name of the app.
@@ -1997,4 +2068,316 @@
         return mRequestorUid == nc.mRequestorUid
                 && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
     }
+
+    /**
+     * Builder class for NetworkCapabilities.
+     *
+     * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
+     * the built class require holding a signature permission to use - mostly
+     * {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific
+     * description of each setter. As this class lives entirely in app space it does not
+     * enforce these restrictions itself but the system server clears out the relevant
+     * fields when receiving a NetworkCapabilities object from a caller without the
+     * appropriate permission.
+     *
+     * Apps don't use this builder directly. Instead, they use {@link NetworkRequest} via
+     * its builder object.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static class Builder {
+        private final NetworkCapabilities mCaps;
+
+        /**
+         * Creates a new Builder to construct NetworkCapabilities objects.
+         */
+        public Builder() {
+            mCaps = new NetworkCapabilities();
+        }
+
+        /**
+         * Creates a new Builder of NetworkCapabilities from an existing instance.
+         */
+        public Builder(@NonNull final NetworkCapabilities nc) {
+            Objects.requireNonNull(nc);
+            mCaps = new NetworkCapabilities(nc);
+        }
+
+        /**
+         * Adds the given transport type.
+         *
+         * Multiple transports may be added. Note that when searching for a network to satisfy a
+         * request, satisfying any of the transports listed in the request will satisfy the request.
+         * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
+         * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
+         * to be selected. This is logically different than
+         * {@code NetworkCapabilities.NET_CAPABILITY_*}.
+         *
+         * @param transportType the transport type to be added or removed.
+         * @return this builder
+         */
+        @NonNull
+        public Builder addTransportType(@Transport int transportType) {
+            checkValidTransportType(transportType);
+            mCaps.addTransportType(transportType);
+            return this;
+        }
+
+        /**
+         * Removes the given transport type.
+         *
+         * {@see #addTransportType}.
+         *
+         * @param transportType the transport type to be added or removed.
+         * @return this builder
+         */
+        @NonNull
+        public Builder removeTransportType(@Transport int transportType) {
+            checkValidTransportType(transportType);
+            mCaps.removeTransportType(transportType);
+            return this;
+        }
+
+        /**
+         * Adds the given capability.
+         *
+         * @param capability the capability
+         * @return this builder
+         */
+        @NonNull
+        public Builder addCapability(@NetCapability final int capability) {
+            mCaps.setCapability(capability, true);
+            return this;
+        }
+
+        /**
+         * Removes the given capability.
+         *
+         * @param capability the capability
+         * @return this builder
+         */
+        @NonNull
+        public Builder removeCapability(@NetCapability final int capability) {
+            mCaps.setCapability(capability, false);
+            return this;
+        }
+
+        /**
+         * Sets the owner UID.
+         *
+         * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
+         *
+         * Note: for security the system will clear out this field when received from a
+         * non-privileged source.
+         *
+         * @param ownerUid the owner UID
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+        public Builder setOwnerUid(final int ownerUid) {
+            mCaps.setOwnerUid(ownerUid);
+            return this;
+        }
+
+        /**
+         * Sets the list of UIDs that are administrators of this network.
+         *
+         * <p>UIDs included in administratorUids gain administrator privileges over this
+         * Network. Examples of UIDs that should be included in administratorUids are:
+         * <ul>
+         *     <li>Carrier apps with privileges for the relevant subscription
+         *     <li>Active VPN apps
+         *     <li>Other application groups with a particular Network-related role
+         * </ul>
+         *
+         * <p>In general, user-supplied networks (such as WiFi networks) do not have
+         * administrators.
+         *
+         * <p>An app is granted owner privileges over Networks that it supplies. The owner
+         * UID MUST always be included in administratorUids.
+         *
+         * The default value is the empty array. Pass an empty array to reset.
+         *
+         * Note: for security the system will clear out this field when received from a
+         * non-privileged source, such as an app using reflection to call this or
+         * mutate the member in the built object.
+         *
+         * @param administratorUids the UIDs to be set as administrators of this Network.
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+        public Builder setAdministratorUids(@NonNull final int[] administratorUids) {
+            Objects.requireNonNull(administratorUids);
+            mCaps.setAdministratorUids(administratorUids);
+            return this;
+        }
+
+        /**
+         * Sets the upstream bandwidth of the link.
+         *
+         * Sets the upstream bandwidth for this network in Kbps. This always only refers to
+         * the estimated first hop transport bandwidth.
+         * <p>
+         * Note that when used to request a network, this specifies the minimum acceptable.
+         * When received as the state of an existing network this specifies the typical
+         * first hop bandwidth expected. This is never measured, but rather is inferred
+         * from technology type and other link parameters. It could be used to differentiate
+         * between very slow 1xRTT cellular links and other faster networks or even between
+         * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+         * fast backhauls and slow backhauls.
+         *
+         * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setLinkUpstreamBandwidthKbps(final int upKbps) {
+            mCaps.setLinkUpstreamBandwidthKbps(upKbps);
+            return this;
+        }
+
+        /**
+         * Sets the downstream bandwidth for this network in Kbps. This always only refers to
+         * the estimated first hop transport bandwidth.
+         * <p>
+         * Note that when used to request a network, this specifies the minimum acceptable.
+         * When received as the state of an existing network this specifies the typical
+         * first hop bandwidth expected. This is never measured, but rather is inferred
+         * from technology type and other link parameters. It could be used to differentiate
+         * between very slow 1xRTT cellular links and other faster networks or even between
+         * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+         * fast backhauls and slow backhauls.
+         *
+         * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setLinkDownstreamBandwidthKbps(final int downKbps) {
+            mCaps.setLinkDownstreamBandwidthKbps(downKbps);
+            return this;
+        }
+
+        /**
+         * Sets the optional bearer specific network specifier.
+         * This has no meaning if a single transport is also not specified, so calling
+         * this without a single transport set will generate an exception, as will
+         * subsequently adding or removing transports after this is set.
+         * </p>
+         *
+         * @param specifier a concrete, parcelable framework class that extends NetworkSpecifier,
+         *        or null to clear it.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setNetworkSpecifier(@Nullable final NetworkSpecifier specifier) {
+            mCaps.setNetworkSpecifier(specifier);
+            return this;
+        }
+
+        /**
+         * Sets the optional transport specific information.
+         *
+         * @param info A concrete, parcelable framework class that extends {@link TransportInfo},
+         *             or null to clear it.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setTransportInfo(@Nullable final TransportInfo info) {
+            mCaps.setTransportInfo(info);
+            return this;
+        }
+
+        /**
+         * Sets the signal strength. This is a signed integer, with higher values indicating a
+         * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the
+         * same RSSI units reported by wifi code.
+         * <p>
+         * Note that when used to register a network callback, this specifies the minimum
+         * acceptable signal strength. When received as the state of an existing network it
+         * specifies the current value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means
+         * no value when received and has no effect when requesting a callback.
+         *
+         * Note: for security the system will throw if it receives a NetworkRequest where
+         * the underlying NetworkCapabilities has this member set from a source that does
+         * not hold the {@link android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP}
+         * permission. Apps with this permission can use this indirectly through
+         * {@link android.net.NetworkRequest}.
+         *
+         * @param signalStrength the bearer-specific signal strength.
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
+        public Builder setSignalStrength(final int signalStrength) {
+            mCaps.setSignalStrength(signalStrength);
+            return this;
+        }
+
+        /**
+         * Sets the SSID of this network.
+         *
+         * Note: for security the system will clear out this field when received from a
+         * non-privileged source, like an app using reflection to set this.
+         *
+         * @param ssid the SSID, or null to clear it.
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+        public Builder setSsid(@Nullable final String ssid) {
+            mCaps.setSSID(ssid);
+            return this;
+        }
+
+        /**
+         * Set the uid of the app causing this network to exist.
+         *
+         * Note: for security the system will clear out this field when received from a
+         * non-privileged source.
+         *
+         * @param uid UID of the app.
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+        public Builder setRequestorUid(final int uid) {
+            mCaps.setRequestorUid(uid);
+            return this;
+        }
+
+        /**
+         * Set the package name of the app causing this network to exist.
+         *
+         * Note: for security the system will clear out this field when received from a
+         * non-privileged source.
+         *
+         * @param packageName package name of the app, or null to clear it.
+         * @return this builder
+         */
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+        public Builder setRequestorPackageName(@Nullable final String packageName) {
+            mCaps.setRequestorPackageName(packageName);
+            return this;
+        }
+
+        /**
+         * Builds the instance of the capabilities.
+         *
+         * @return the built instance of NetworkCapabilities.
+         */
+        @NonNull
+        public NetworkCapabilities build() {
+            if (mCaps.getOwnerUid() != Process.INVALID_UID) {
+                if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
+                    throw new IllegalStateException("The owner UID must be included in "
+                            + " administrator UIDs.");
+                }
+            }
+            return new NetworkCapabilities(mCaps);
+        }
+    }
 }
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index 418d691..75086cf 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -33,8 +34,8 @@
  * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
  * with via networking APIs such as {@link ConnectivityManager}.
  *
- * Subclasses should implement {@link #onNetworkRequested} and {@link #onRequestWithdrawn} to
- * receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
+ * Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn}
+ * to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
  * best (highest-scoring) network for any request is generally not used by the system, and torn
  * down.
  *
@@ -77,7 +78,7 @@
      * Constructs a new NetworkProvider.
      *
      * @param looper the Looper on which to run {@link #onNetworkRequested} and
-     *               {@link #onRequestWithdrawn}.
+     *               {@link #onNetworkRequestWithdrawn}.
      * @param name the name of the listener, used only for debugging.
      *
      * @hide
@@ -94,7 +95,7 @@
                         onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2);
                         break;
                     case CMD_CANCEL_REQUEST:
-                        onRequestWithdrawn((NetworkRequest) m.obj);
+                        onNetworkRequestWithdrawn((NetworkRequest) m.obj);
                         break;
                     default:
                         Log.e(mName, "Unhandled message: " + m.what);
@@ -142,14 +143,15 @@
      *  @hide
      */
     @SystemApi
-    public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {}
+    public void onNetworkRequested(@NonNull NetworkRequest request,
+            @IntRange(from = 0, to = 99) int score, int providerId) {}
 
     /**
      *  Called when a NetworkRequest is withdrawn.
      *  @hide
      */
     @SystemApi
-    public void onRequestWithdrawn(@NonNull NetworkRequest request) {}
+    public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {}
 
     /**
      * Asserts that no provider will ever be able to satisfy the specified request. The provider
@@ -157,7 +159,7 @@
      * satisfying this request, and that the request cannot be satisfied. The application filing the
      * request will receive an {@link NetworkCallback#onUnavailable()} callback.
      *
-     * @param request the request that cannot be fulfilled
+     * @param request the request that permanently cannot be fulfilled
      * @hide
      */
     @SystemApi
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index b0bf64e..75fe6b1 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -473,9 +473,7 @@
      *
      * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not
      *           satisfy any request.
-     * @hide
      */
-    @SystemApi
     public boolean satisfiedBy(@Nullable NetworkCapabilities nc) {
         return networkCapabilities.satisfiedByNetworkCapabilities(nc);
     }
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index fc9a8f6..8ff8f4c 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -109,6 +109,16 @@
     })
     public @interface ErrorCode {}
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            SUCCESS,
+            ERROR_INVALID_LENGTH,
+            ERROR_UNSUPPORTED,
+            ERROR_INSUFFICIENT_RESOURCES
+    })
+    public @interface KeepaliveEvent {}
+
     /**
      * The minimum interval in seconds between keepalive packet transmissions.
      *
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1309740..0b024e7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -49,8 +49,6 @@
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import static java.util.Map.Entry;
 
 import android.Manifest;
@@ -65,6 +63,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.net.CaptivePortal;
@@ -654,8 +653,8 @@
     final MultipathPolicyTracker mMultipathPolicyTracker;
 
     @VisibleForTesting
-    final Map<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo>
-            mConnectivityDiagnosticsCallbacks = new HashMap<>();
+    final Map<IBinder, ConnectivityDiagnosticsCallbackInfo> mConnectivityDiagnosticsCallbacks =
+            new HashMap<>();
 
     /**
      * Implements support for the legacy "one network per network type" model.
@@ -929,7 +928,7 @@
          * @see IpConnectivityMetrics.Logger
          */
         public IpConnectivityMetrics.Logger getMetricsLogger() {
-            return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+            return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
                     "no IpConnectivityMetrics service");
         }
 
@@ -958,10 +957,10 @@
             IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
-        mDeps = checkNotNull(deps, "missing Dependencies");
+        mDeps = Objects.requireNonNull(deps, "missing Dependencies");
         mSystemProperties = mDeps.getSystemProperties();
         mNetIdManager = mDeps.makeNetIdManager();
-        mContext = checkNotNull(context, "missing Context");
+        mContext = Objects.requireNonNull(context, "missing Context");
 
         mMetricsLog = logger;
         mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -991,13 +990,13 @@
 
         mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
 
-        mNMS = checkNotNull(netManager, "missing INetworkManagementService");
-        mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
-        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
-        mPolicyManagerInternal = checkNotNull(
+        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
+        mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
+        mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
+        mPolicyManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
-        mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
+        mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
@@ -5333,7 +5332,7 @@
     // specific SSID/SignalStrength, or the calling app has permission to do so.
     private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
             int callerPid, int callerUid, String callerPackageName) {
-        if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
+        if (null != nc.getSsid() && !checkSettingsPermission(callerPid, callerUid)) {
             throw new SecurityException("Insufficient permissions to request a specific SSID");
         }
 
@@ -5398,12 +5397,25 @@
         }
     }
 
+    private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
+        final PackageManager pm = mContext.getPackageManager();
+        final int userId = UserHandle.getCallingUserId();
+        try {
+            final int callingVersion = pm.getApplicationInfoAsUser(
+                    callingPackageName, 0 /* flags */, userId).targetSdkVersion;
+            if (callingVersion < version) return false;
+        } catch (PackageManager.NameNotFoundException e) { }
+        return true;
+    }
+
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             Messenger messenger, int timeoutMs, IBinder binder, int legacyType,
             @NonNull String callingPackageName) {
         if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
-            throw new SecurityException("Insufficient permissions to specify legacy type");
+            if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
+                throw new SecurityException("Insufficient permissions to specify legacy type");
+            }
         }
         final int callingUid = Binder.getCallingUid();
         final NetworkRequest.Type type = (networkCapabilities == null)
@@ -5508,7 +5520,7 @@
     @Override
     public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
             PendingIntent operation, @NonNull String callingPackageName) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         final int callingUid = Binder.getCallingUid();
         networkCapabilities = new NetworkCapabilities(networkCapabilities);
         enforceNetworkRequestPermissions(networkCapabilities);
@@ -5537,7 +5549,7 @@
 
     @Override
     public void releasePendingNetworkRequest(PendingIntent operation) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
                 getCallingUid(), 0, operation));
     }
@@ -5596,7 +5608,7 @@
     @Override
     public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
             PendingIntent operation, @NonNull String callingPackageName) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         final int callingUid = Binder.getCallingUid();
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
@@ -5805,7 +5817,7 @@
         nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
         final String extraInfo = networkInfo.getExtraInfo();
         final String name = TextUtils.isEmpty(extraInfo)
-                ? nai.networkCapabilities.getSSID() : extraInfo;
+                ? nai.networkCapabilities.getSsid() : extraInfo;
         if (DBG) log("registerNetworkAgent " + nai);
         final long token = Binder.clearCallingIdentity();
         try {
@@ -7814,11 +7826,12 @@
         ensureRunningOnConnectivityServiceThread();
 
         final IConnectivityDiagnosticsCallback cb = cbInfo.mCb;
+        final IBinder iCb = cb.asBinder();
         final NetworkRequestInfo nri = cbInfo.mRequestInfo;
 
         // This means that the client registered the same callback multiple times. Do
         // not override the previous entry, and exit silently.
-        if (mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
+        if (mConnectivityDiagnosticsCallbacks.containsKey(iCb)) {
             if (VDBG) log("Diagnostics callback is already registered");
 
             // Decrement the reference count for this NetworkRequestInfo. The reference count is
@@ -7828,40 +7841,75 @@
             return;
         }
 
-        mConnectivityDiagnosticsCallbacks.put(cb, cbInfo);
+        mConnectivityDiagnosticsCallbacks.put(iCb, cbInfo);
 
         try {
-            cb.asBinder().linkToDeath(cbInfo, 0);
+            iCb.linkToDeath(cbInfo, 0);
         } catch (RemoteException e) {
             cbInfo.binderDied();
+            return;
+        }
+
+        // Once registered, provide ConnectivityReports for matching Networks
+        final List<NetworkAgentInfo> matchingNetworks = new ArrayList<>();
+        synchronized (mNetworkForNetId) {
+            for (int i = 0; i < mNetworkForNetId.size(); i++) {
+                final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
+                if (nai.satisfies(nri.request)) {
+                    matchingNetworks.add(nai);
+                }
+            }
+        }
+        for (final NetworkAgentInfo nai : matchingNetworks) {
+            final ConnectivityReport report = nai.getConnectivityReport();
+            if (report == null) {
+                continue;
+            }
+            if (!checkConnectivityDiagnosticsPermissions(
+                    nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
+                continue;
+            }
+
+            try {
+                cb.onConnectivityReportAvailable(report);
+            } catch (RemoteException e) {
+                // Exception while sending the ConnectivityReport. Move on to the next network.
+            }
         }
     }
 
     private void handleUnregisterConnectivityDiagnosticsCallback(
             @NonNull IConnectivityDiagnosticsCallback cb, int uid) {
         ensureRunningOnConnectivityServiceThread();
+        final IBinder iCb = cb.asBinder();
 
-        if (!mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
+        final ConnectivityDiagnosticsCallbackInfo cbInfo =
+                mConnectivityDiagnosticsCallbacks.remove(iCb);
+        if (cbInfo == null) {
             if (VDBG) log("Removing diagnostics callback that is not currently registered");
             return;
         }
 
-        final NetworkRequestInfo nri = mConnectivityDiagnosticsCallbacks.get(cb).mRequestInfo;
+        final NetworkRequestInfo nri = cbInfo.mRequestInfo;
 
         if (uid != nri.mUid) {
             if (VDBG) loge("Different uid than registrant attempting to unregister cb");
             return;
         }
 
-        cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0);
+        // Decrement the reference count for this NetworkRequestInfo. The reference count is
+        // incremented when the NetworkRequestInfo is created as part of
+        // enforceRequestCountLimit().
+        decrementNetworkRequestPerUidCount(nri);
+
+        iCb.unlinkToDeath(cbInfo, 0);
     }
 
     private void handleNetworkTestedWithExtras(
             @NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) {
         final NetworkAgentInfo nai = reportEvent.mNai;
         final NetworkCapabilities networkCapabilities =
-                new NetworkCapabilities(nai.networkCapabilities);
-        clearNetworkCapabilitiesUids(networkCapabilities);
+                getNetworkCapabilitiesWithoutUids(nai.networkCapabilities);
         final ConnectivityReport report =
                 new ConnectivityReport(
                         reportEvent.mNai.network,
@@ -7869,6 +7917,7 @@
                         nai.linkProperties,
                         networkCapabilities,
                         extras);
+        nai.setConnectivityReport(report);
         final List<IConnectivityDiagnosticsCallback> results =
                 getMatchingPermissionedCallbacks(nai);
         for (final IConnectivityDiagnosticsCallback cb : results) {
@@ -7884,8 +7933,7 @@
             @NonNull NetworkAgentInfo nai, long timestampMillis, int detectionMethod,
             @NonNull PersistableBundle extras) {
         final NetworkCapabilities networkCapabilities =
-                new NetworkCapabilities(nai.networkCapabilities);
-        clearNetworkCapabilitiesUids(networkCapabilities);
+                getNetworkCapabilitiesWithoutUids(nai.networkCapabilities);
         final DataStallReport report =
                 new DataStallReport(
                         nai.network,
@@ -7918,23 +7966,25 @@
         }
     }
 
-    private void clearNetworkCapabilitiesUids(@NonNull NetworkCapabilities nc) {
-        nc.setUids(null);
-        nc.setAdministratorUids(new int[0]);
-        nc.setOwnerUid(Process.INVALID_UID);
+    private NetworkCapabilities getNetworkCapabilitiesWithoutUids(@NonNull NetworkCapabilities nc) {
+        final NetworkCapabilities sanitized = new NetworkCapabilities(nc);
+        sanitized.setUids(null);
+        sanitized.setAdministratorUids(new int[0]);
+        sanitized.setOwnerUid(Process.INVALID_UID);
+        return sanitized;
     }
 
     private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
             @NonNull NetworkAgentInfo nai) {
         final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
-        for (Entry<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo> entry :
+        for (Entry<IBinder, ConnectivityDiagnosticsCallbackInfo> entry :
                 mConnectivityDiagnosticsCallbacks.entrySet()) {
             final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
             final NetworkRequestInfo nri = cbInfo.mRequestInfo;
             if (nai.satisfies(nri.request)) {
                 if (checkConnectivityDiagnosticsPermissions(
                         nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
-                    results.add(entry.getKey());
+                    results.add(entry.getValue().mCb);
                 }
             }
         }
@@ -7971,11 +8021,7 @@
 
         // Administrator UIDs also contains the Owner UID
         final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
-        for (final int uid : administratorUids) {
-            if (uid == callbackUid) return true;
-        }
-
-        return false;
+        return ArrayUtils.contains(administratorUids, callbackUid);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 5059a48..7c8fb5a 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -220,9 +220,9 @@
                     + " network=" + mNai.network
                     + " startedState=" + startedStateString(mStartedState)
                     + " "
-                    + IpUtils.addressAndPortToString(mPacket.srcAddress, mPacket.srcPort)
+                    + IpUtils.addressAndPortToString(mPacket.getSrcAddress(), mPacket.getSrcPort())
                     + "->"
-                    + IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort)
+                    + IpUtils.addressAndPortToString(mPacket.getDstAddress(), mPacket.getDstPort())
                     + " interval=" + mInterval
                     + " uid=" + mUid + " pid=" + mPid + " privileged=" + mPrivileged
                     + " packetData=" + HexDump.toHexString(mPacket.getPacket())
@@ -250,7 +250,7 @@
         private int checkSourceAddress() {
             // Check that we have the source address.
             for (InetAddress address : mNai.linkProperties.getAddresses()) {
-                if (address.equals(mPacket.srcAddress)) {
+                if (address.equals(mPacket.getSrcAddress())) {
                     return SUCCESS;
                 }
             }
@@ -619,7 +619,7 @@
             packet = NattKeepalivePacketData.nattKeepalivePacket(
                     srcAddress, srcPort, dstAddress, NATT_PORT);
         } catch (InvalidPacketException e) {
-            notifyErrorCallback(cb, e.error);
+            notifyErrorCallback(cb, e.getError());
             return;
         }
         KeepaliveInfo ki = null;
@@ -662,7 +662,7 @@
             notifyErrorCallback(cb, e.error);
             return;
         } catch (InvalidPacketException e) {
-            notifyErrorCallback(cb, e.error);
+            notifyErrorCallback(cb, e.getError());
             return;
         }
         KeepaliveInfo ki = null;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index f844844..2d1f553 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
 import static android.net.NetworkCapabilities.transportNamesOf;
 
 import android.annotation.NonNull;
@@ -243,6 +244,10 @@
     // How many of the satisfied requests are of type BACKGROUND_REQUEST.
     private int mNumBackgroundNetworkRequests = 0;
 
+    // The last ConnectivityReport made available for this network. This value is only null before a
+    // report is generated. Once non-null, it will never be null again.
+    @Nullable private ConnectivityReport mConnectivityReport;
+
     public final Messenger messenger;
     public final AsyncChannel asyncChannel;
 
@@ -621,6 +626,32 @@
         for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
     }
 
+    /**
+     * Sets the most recent ConnectivityReport for this network.
+     *
+     * <p>This should only be called from the ConnectivityService thread.
+     *
+     * @hide
+     */
+    public void setConnectivityReport(@NonNull ConnectivityReport connectivityReport) {
+        mConnectivityReport = connectivityReport;
+    }
+
+    /**
+     * Returns the most recent ConnectivityReport for this network, or null if none have been
+     * reported yet.
+     *
+     * <p>This should only be called from the ConnectivityService thread.
+     *
+     * @hide
+     */
+    @Nullable
+    public ConnectivityReport getConnectivityReport() {
+        return mConnectivityReport;
+    }
+
+    // TODO: Print shorter members first and only print the boolean variable which value is true
+    // to improve readability.
     public String toString() {
         return "NetworkAgentInfo{"
                 + "network{" + network + "}  handle{" + network.getNetworkHandle() + "}  ni{"
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0925de8..34b0aa2 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -150,7 +150,7 @@
         if (nai != null) {
             transportType = approximateTransportType(nai);
             final String extraInfo = nai.networkInfo.getExtraInfo();
-            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
+            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSsid() : extraInfo;
             // Only notify for Internet-capable networks.
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
         } else {
@@ -183,14 +183,14 @@
         int icon = getIcon(transportType);
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
             details = r.getString(R.string.wifi_no_internet_detailed);
         } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
             if (transportType == TRANSPORT_CELLULAR) {
                 title = r.getString(R.string.mobile_no_internet);
             } else if (transportType == TRANSPORT_WIFI) {
                 title = r.getString(R.string.wifi_no_internet,
-                        WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+                        WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
             } else {
                 title = r.getString(R.string.other_networks_no_internet);
             }
@@ -198,19 +198,19 @@
         } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
                 && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.network_partial_connectivity,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
             details = r.getString(R.string.network_partial_connectivity_detailed);
         } else if (notifyType == NotificationType.LOST_INTERNET &&
                 transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet,
-                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+                    WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
             details = r.getString(R.string.wifi_no_internet_detailed);
         } else if (notifyType == NotificationType.SIGN_IN) {
             switch (transportType) {
                 case TRANSPORT_WIFI:
                     title = r.getString(R.string.wifi_available_sign_in, 0);
                     details = r.getString(R.string.network_available_sign_in_detailed,
-                            WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+                            WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
                     break;
                 case TRANSPORT_CELLULAR:
                     title = r.getString(R.string.network_available_sign_in, 0);
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 2b5720a..8de27e8 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -445,14 +445,20 @@
         // Check comparisons work.
         LinkProperties lp2 = new LinkProperties(lp);
         assertAllRoutesHaveInterface("wlan0", lp2);
-        assertEquals(0, lp.compareAllRoutes(lp2).added.size());
-        assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
+        // LinkProperties#compareAllRoutes exists both in R and before R, but the return type
+        // changed in R, so a test compiled with the R version of LinkProperties cannot run on Q.
+        if (isAtLeastR()) {
+            assertEquals(0, lp.compareAllRoutes(lp2).added.size());
+            assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
+        }
 
         lp2.setInterfaceName("p2p0");
         assertAllRoutesHaveInterface("p2p0", lp2);
         assertAllRoutesNotHaveInterface("wlan0", lp2);
-        assertEquals(3, lp.compareAllRoutes(lp2).added.size());
-        assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
+        if (isAtLeastR()) {
+            assertEquals(3, lp.compareAllRoutes(lp2).added.size());
+            assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
+        }
 
         // Remove route with incorrect interface, no route removed.
         lp.removeRoute(new RouteInfo(prefix2, null, null));
@@ -480,6 +486,8 @@
         assertEquals(1, rmnet0.getLinkAddresses().size());
         assertEquals(1, rmnet0.getAllAddresses().size());
         assertEquals(1, rmnet0.getAllLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllInterfaceNames().size());
+        assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
 
         rmnet0.addStackedLink(clat4);
         assertEquals(1, rmnet0.getStackedLinks().size());
@@ -487,6 +495,9 @@
         assertEquals(1, rmnet0.getLinkAddresses().size());
         assertEquals(2, rmnet0.getAllAddresses().size());
         assertEquals(2, rmnet0.getAllLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllInterfaceNames().size());
+        assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
+        assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
 
         rmnet0.addStackedLink(clat4);
         assertEquals(1, rmnet0.getStackedLinks().size());
@@ -494,6 +505,9 @@
         assertEquals(1, rmnet0.getLinkAddresses().size());
         assertEquals(2, rmnet0.getAllAddresses().size());
         assertEquals(2, rmnet0.getAllLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllInterfaceNames().size());
+        assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
+        assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
 
         assertEquals(0, clat4.getStackedLinks().size());
 
@@ -513,6 +527,8 @@
         assertEquals(1, rmnet0.getLinkAddresses().size());
         assertEquals(1, rmnet0.getAllAddresses().size());
         assertEquals(1, rmnet0.getAllLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllInterfaceNames().size());
+        assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
 
         assertFalse(rmnet0.removeStackedLink("clat4"));
     }
@@ -936,7 +952,7 @@
 
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testCompareResult() {
         // Either adding or removing items
         compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
@@ -1197,4 +1213,48 @@
         lp.clear();
         assertNull(lp.getCaptivePortalData());
     }
+
+    private LinkProperties makeIpv4LinkProperties() {
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(NAME);
+        linkProperties.addLinkAddress(LINKADDRV4);
+        linkProperties.addDnsServer(DNS1);
+        linkProperties.addRoute(new RouteInfo(GATEWAY1));
+        linkProperties.addRoute(new RouteInfo(GATEWAY2));
+        return linkProperties;
+    }
+
+    private LinkProperties makeIpv6LinkProperties() {
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(NAME);
+        linkProperties.addLinkAddress(LINKADDRV6);
+        linkProperties.addDnsServer(DNS6);
+        linkProperties.addRoute(new RouteInfo(GATEWAY61));
+        linkProperties.addRoute(new RouteInfo(GATEWAY62));
+        return linkProperties;
+    }
+
+    @Test
+    public void testHasIpv4DefaultRoute() {
+        final LinkProperties Ipv4 = makeIpv4LinkProperties();
+        assertTrue(Ipv4.hasIpv4DefaultRoute());
+        final LinkProperties Ipv6 = makeIpv6LinkProperties();
+        assertFalse(Ipv6.hasIpv4DefaultRoute());
+    }
+
+    @Test
+    public void testHasIpv4DnsServer() {
+        final LinkProperties Ipv4 = makeIpv4LinkProperties();
+        assertTrue(Ipv4.hasIpv4DnsServer());
+        final LinkProperties Ipv6 = makeIpv6LinkProperties();
+        assertFalse(Ipv6.hasIpv4DnsServer());
+    }
+
+    @Test
+    public void testHasIpv6DnsServer() {
+        final LinkProperties Ipv4 = makeIpv4LinkProperties();
+        assertFalse(Ipv4.hasIpv6DnsServer());
+        final LinkProperties Ipv6 = makeIpv6LinkProperties();
+        assertTrue(Ipv6.hasIpv6DnsServer());
+    }
 }
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
new file mode 100644
index 0000000..ef15b66
--- /dev/null
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import android.net.wifi.aware.DiscoverySession
+import android.net.wifi.aware.PeerHandle
+import android.net.wifi.aware.WifiAwareNetworkSpecifier
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+
+import com.android.testutils.assertParcelSane
+
+import java.lang.IllegalStateException
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MatchAllNetworkSpecifierTest {
+    @Test
+    fun testParcel() {
+        assertParcelSane(MatchAllNetworkSpecifier(), 0)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun testSatisfiedBy() {
+        val specifier = MatchAllNetworkSpecifier()
+        val discoverySession = Mockito.mock(DiscoverySession::class.java)
+        val peerHandle = Mockito.mock(PeerHandle::class.java)
+        val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
+                peerHandle).build()
+        specifier.satisfiedBy(wifiAwareNetworkSpecifier)
+    }
+}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 9fe1883..316a83a 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -58,6 +58,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
 import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
@@ -280,6 +281,7 @@
             .addCapability(NET_CAPABILITY_NOT_METERED);
         if (isAtLeastR()) {
             netCap.setOwnerUid(123);
+            netCap.setAdministratorUids(new int[] {5, 11});
         }
         assertParcelingIsLossless(netCap);
         netCap.setSSID(TEST_SSID);
@@ -440,6 +442,23 @@
     }
 
     @Test
+    public void testSetAdministratorUids() {
+        NetworkCapabilities nc =
+                new NetworkCapabilities().setAdministratorUids(new int[] {2, 1, 3});
+
+        assertArrayEquals(new int[] {1, 2, 3}, nc.getAdministratorUids());
+    }
+
+    @Test
+    public void testSetAdministratorUidsWithDuplicates() {
+        try {
+            new NetworkCapabilities().setAdministratorUids(new int[] {1, 1});
+            fail("Expected IllegalArgumentException for duplicate uids");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
     public void testCombineCapabilities() {
         NetworkCapabilities nc1 = new NetworkCapabilities();
         NetworkCapabilities nc2 = new NetworkCapabilities();
@@ -463,7 +482,9 @@
 
         nc1.setSSID(TEST_SSID);
         nc2.combineCapabilities(nc1);
-        assertTrue(TEST_SSID.equals(nc2.getSSID()));
+        if (isAtLeastR()) {
+            assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        }
 
         // Because they now have the same SSID, the following call should not throw
         nc2.combineCapabilities(nc1);
@@ -489,6 +510,25 @@
         assertFalse(nc2.appliesToUid(12));
         assertTrue(nc1.appliesToUid(22));
         assertTrue(nc2.appliesToUid(22));
+
+        final int[] adminUids = {3, 6, 12};
+        nc1.setAdministratorUids(adminUids);
+        nc2.combineCapabilities(nc1);
+        assertTrue(nc2.equalsAdministratorUids(nc1));
+        assertArrayEquals(nc2.getAdministratorUids(), adminUids);
+
+        final int[] adminUidsOtherOrder = {3, 12, 6};
+        nc1.setAdministratorUids(adminUids);
+        assertTrue(nc2.equalsAdministratorUids(nc1));
+
+        final int[] adminUids2 = {11, 1, 12, 3, 6};
+        nc1.setAdministratorUids(adminUids2);
+        assertFalse(nc2.equalsAdministratorUids(nc1));
+        assertFalse(Arrays.equals(nc2.getAdministratorUids(), adminUids2));
+        try {
+            nc2.combineCapabilities(nc1);
+            fail("Shouldn't be able to combine different lists of admin UIDs");
+        } catch (IllegalStateException expected) { }
     }
 
     @Test
@@ -601,12 +641,16 @@
         // from nc2.
         assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
         assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
-        assertTrue(TEST_SSID.equals(nc2.getSSID()));
+        if (isAtLeastR()) {
+            assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        }
 
         nc1.setSSID(DIFFERENT_TEST_SSID);
         nc2.set(nc1);
         assertEquals(nc1, nc2);
-        assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSSID()));
+        if (isAtLeastR()) {
+            assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
+        }
 
         nc1.setUids(uidRange(10, 13));
         nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 23caf49..eec3cdb 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -24,7 +24,6 @@
 import android.net.metrics.IpConnectivityLog
 import android.net.util.SharedLog
 import android.os.IBinder
-import com.android.networkstack.metrics.DataStallStatsUtils
 import com.android.networkstack.netlink.TcpSocketTracker
 import com.android.server.NetworkStackService
 import com.android.server.NetworkStackService.NetworkMonitorConnector
@@ -91,7 +90,6 @@
                     mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
                     mock(NetworkStackService.NetworkStackServiceManager::class.java),
                     NetworkMonitorDeps(privateDnsBypassNetwork),
-                    mock(DataStallStatsUtils::class.java),
                     mock(TcpSocketTracker::class.java))
             cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
         }
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index e632aaf..cea8c57 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -66,10 +66,10 @@
             fail("InvalidPacketException: " + e);
         }
 
-        assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.srcAddress);
-        assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.dstAddress);
-        assertEquals(testInfo.srcPort, resultData.srcPort);
-        assertEquals(testInfo.dstPort, resultData.dstPort);
+        assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
+        assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
+        assertEquals(testInfo.srcPort, resultData.getSrcPort());
+        assertEquals(testInfo.dstPort, resultData.getDstPort());
         assertEquals(testInfo.seq, resultData.tcpSeq);
         assertEquals(testInfo.ack, resultData.tcpAck);
         assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
index 8a4b533..ceca6f0 100644
--- a/tests/net/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -65,7 +65,7 @@
         assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
         assertFalse(p.isBypassable);
         assertFalse(p.isMetered);
-        assertEquals(1400, p.maxMtu);
+        assertEquals(1360, p.maxMtu);
         assertFalse(p.areAuthParamsInline);
     }
 
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 83399b8..7b9d2bd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -316,6 +316,8 @@
     private static final String TEST_PACKAGE_NAME = "com.android.test.package";
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
+    private static final String INTERFACE_NAME = "interface";
+
     private MockContext mServiceContext;
     private HandlerThread mCsHandlerThread;
     private ConnectivityService mService;
@@ -6742,16 +6744,12 @@
 
         verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
         verify(mConnectivityDiagnosticsCallback).asBinder();
-        assertTrue(
-                mService.mConnectivityDiagnosticsCallbacks.containsKey(
-                        mConnectivityDiagnosticsCallback));
+        assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
 
         mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
         verify(mIBinder, timeout(TIMEOUT_MS))
                 .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
-        assertFalse(
-                mService.mConnectivityDiagnosticsCallbacks.containsKey(
-                        mConnectivityDiagnosticsCallback));
+        assertFalse(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
         verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
     }
 
@@ -6769,9 +6767,7 @@
 
         verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
         verify(mConnectivityDiagnosticsCallback).asBinder();
-        assertTrue(
-                mService.mConnectivityDiagnosticsCallbacks.containsKey(
-                        mConnectivityDiagnosticsCallback));
+        assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
 
         // Register the same callback again
         mService.registerConnectivityDiagnosticsCallback(
@@ -6780,9 +6776,7 @@
         // Block until all other events are done processing.
         HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
 
-        assertTrue(
-                mService.mConnectivityDiagnosticsCallbacks.containsKey(
-                        mConnectivityDiagnosticsCallback));
+        assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
     }
 
     @Test
@@ -6909,6 +6903,38 @@
                         mContext.getOpPackageName()));
     }
 
+    @Test
+    public void testRegisterConnectivityDiagnosticsCallbackCallsOnConnectivityReport()
+            throws Exception {
+        // Set up the Network, which leads to a ConnectivityReport being cached for the network.
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(callback);
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(INTERFACE_NAME);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties);
+        mCellNetworkAgent.connect(true);
+        callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        callback.assertNoCallback();
+
+        final NetworkRequest request = new NetworkRequest.Builder().build();
+        when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
+
+        mServiceContext.setPermission(
+                android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
+
+        mService.registerConnectivityDiagnosticsCallback(
+                mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
+
+        // Block until all other events are done processing.
+        HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+        verify(mConnectivityDiagnosticsCallback)
+                .onConnectivityReportAvailable(argThat(report -> {
+                    return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName())
+                            && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR);
+                }));
+    }
+
     private void setUpConnectivityDiagnosticsCallback() throws Exception {
         final NetworkRequest request = new NetworkRequest.Builder().build();
         when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);