Support cross-user VPN calls (with permission)

Settings and SystemUI need to act on other users than USER_OWNER.

This is gated by INTERACT_ACROSS_USERS_FULL in addition to the existing
CONTROL_VPN checks, so the number of processes able to interfere with
other profiles' VPNs should be quite small.

Bug: 20692490
Bug: 20747154
Bug: 20872408
Change-Id: I6e5d7220f73435bec350719e7b4715935caf4e19
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index aeecdf3..e1ec8a6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -298,13 +298,15 @@
     }
 
     /**
-     * Set whether the current package has the ability to launch VPNs without user intervention.
+     * Set whether a package has the ability to launch VPNs without user intervention.
      */
-    public void setPackageAuthorization(boolean authorized) {
+    public void setPackageAuthorization(String packageName, boolean authorized) {
         // Check if the caller is authorized.
         enforceControlPermission();
 
-        if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
+        int uid = getAppUid(packageName, mUserHandle);
+        if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
+            // Authorization for nonexistent packages (or fake ones) can't be updated.
             return;
         }
 
@@ -312,10 +314,10 @@
         try {
             AppOpsManager appOps =
                     (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
+            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
                     authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
         } catch (Exception e) {
-            Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
+            Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
         } finally {
             Binder.restoreCallingIdentity(token);
         }