Make sure listen requests from VPN apps see their own networks

Test: runtest frameworks-net
Test: CTS pass, including with the next patch which is what this
      actually matters for

Change-Id: I09a94042acbefa24ab884f95326e30d6ab280b82
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index d0f6f9b..6e80f02 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -49,6 +49,7 @@
  */
 public final class NetworkCapabilities implements Parcelable {
     private static final String TAG = "NetworkCapabilities";
+    private static final int INVALID_UID = -1;
 
     /**
      * @hide
@@ -67,6 +68,7 @@
             mNetworkSpecifier = nc.mNetworkSpecifier;
             mSignalStrength = nc.mSignalStrength;
             mUids = nc.mUids;
+            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
         }
     }
 
@@ -81,6 +83,7 @@
         mNetworkSpecifier = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
         mUids = null;
+        mEstablishingVpnAppUid = INVALID_UID;
     }
 
     /**
@@ -623,6 +626,29 @@
     }
 
     /**
+     * UID of the app that manages this network, or INVALID_UID if none/unknown.
+     *
+     * This field keeps track of the UID of the app that created this network and is in charge
+     * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
+     * accordingly, but it may be renamed if other mechanisms are offered for third party apps
+     * to create networks.
+     *
+     * Because this field is only used in the services side (and to avoid apps being able to
+     * set this to whatever they want), this field is not parcelled and will not be conserved
+     * across the IPC boundary.
+     * @hide
+     */
+    private int mEstablishingVpnAppUid = INVALID_UID;
+
+    /**
+     * Set the UID of the managing app.
+     * @hide
+     */
+    public void setEstablishingVpnAppUid(final int uid) {
+        mEstablishingVpnAppUid = uid;
+    }
+
+    /**
      * Value indicating that link bandwidth is unspecified.
      * @hide
      */
@@ -848,6 +874,10 @@
      * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
      * member is null, then the network is not restricted by app UID. If it's an empty list, then
      * it means nobody can use it.
+     * As a special exception, the app managing this network (as identified by its UID stored in
+     * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
+     * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
+     * to the app that manages it as determined by #appliesToUid.
      * <p>
      * Please note that in principle a single app can be associated with multiple UIDs because
      * each app will have a different UID when it's run as a different (macro-)user. A single
@@ -935,9 +965,17 @@
     /**
      * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require.
      *
-     * This is called on the NetworkCapabilities embedded in a request with the capabilities
-     * of an available network.
-     * nc is assumed nonnull.
+     * This method is called on the NetworkCapabilities embedded in a request with the
+     * capabilities of an available network. It checks whether all the UIDs from this listen
+     * (representing the UIDs that must have access to the network) are satisfied by the UIDs
+     * in the passed nc (representing the UIDs that this network is available to).
+     * <p>
+     * As a special exception, the UID that created the passed network (as represented by its
+     * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
+     * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
+     * can see its own network when it listens for it.
+     * <p>
+     * nc is assumed nonnull. Else, NPE.
      * @see #appliesToUid
      * @hide
      */
@@ -945,6 +983,7 @@
         if (null == nc.mUids) return true; // The network satisfies everything.
         if (null == mUids) return false; // Not everything allowed but requires everything
         for (UidRange requiredRange : mUids) {
+            if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
             if (!nc.appliesToUidRange(requiredRange)) {
                 return false;
             }
@@ -1181,8 +1220,10 @@
 
         String uids = (null != mUids ? " Uids: <" + mUids + ">" : "");
 
+        String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid;
+
         return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength
-            + uids + "]";
+            + uids + establishingAppUid + "]";
     }
 
     /**