Merge "Support routing sockets as another user"
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3dbe078..7ee10c3 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -119,6 +119,8 @@
 
     boolean prepareVpn(String oldPackage, String newPackage);
 
+    void markSocketAsUser(in ParcelFileDescriptor socket, int uid);
+
     ParcelFileDescriptor establishVpn(in VpnConfig config);
 
     void startLegacyVpn(in VpnProfile profile);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index a6344ca..476a6fd 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1749,6 +1749,16 @@
                 "ConnectivityService");
     }
 
+    private void enforceMarkNetworkSocketPermission() {
+        //Media server special case
+        if (Binder.getCallingUid() == Process.MEDIA_UID) {
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MARK_NETWORK_SOCKET,
+                "ConnectivityService");
+    }
+
     /**
      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
      * network, we ignore it. If it is for the active network, we send out a
@@ -3350,6 +3360,23 @@
         }
     }
 
+    @Override
+    public void markSocketAsUser(ParcelFileDescriptor socket, int uid) {
+        enforceMarkNetworkSocketPermission();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            int mark = mNetd.getMarkForUid(uid);
+            // Clear the mark on the socket if no mark is needed to prevent socket reuse issues
+            if (mark == -1) {
+                mark = 0;
+            }
+            NetworkUtils.markSocket(socket.getFd(), mark);
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     /**
      * Configure a TUN interface and return its file descriptor. Parameters
      * are encoded and opaque to this class. This method is used by VpnBuilder