diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index da5d96e49d..3d34574440 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -187,4 +187,6 @@ interface IConnectivityManager byte[] getNetworkWatchlistConfigHash(); int getConnectionOwnerUid(in ConnectionInfo connectionInfo); + boolean isCallerCurrentAlwaysOnVpnApp(); + boolean isCallerCurrentAlwaysOnVpnLockdownApp(); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d6f3e2ba48..5220bdc103 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -6342,6 +6342,20 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @GuardedBy("mVpns") + private Vpn getVpnIfOwner() { + final int uid = Binder.getCallingUid(); + final int user = UserHandle.getUserId(uid); + + final Vpn vpn = mVpns.get(user); + if (vpn == null) { + return null; + } else { + final VpnInfo info = vpn.getVpnInfo(); + return (info == null || info.ownerUid != uid) ? null : vpn; + } + } + /** * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission * for testing. @@ -6350,14 +6364,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (checkNetworkStackPermission()) { return null; } - final int uid = Binder.getCallingUid(); - final int user = UserHandle.getUserId(uid); synchronized (mVpns) { - Vpn vpn = mVpns.get(user); - try { - if (vpn.getVpnInfo().ownerUid == uid) return vpn; - } catch (NullPointerException e) { - /* vpn is null, or VPN is not connected and getVpnInfo() is null. */ + Vpn vpn = getVpnIfOwner(); + if (vpn != null) { + return vpn; } } throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK " @@ -6386,4 +6396,20 @@ public class ConnectivityService extends IConnectivityManager.Stub return uid; } + + @Override + public boolean isCallerCurrentAlwaysOnVpnApp() { + synchronized (mVpns) { + Vpn vpn = getVpnIfOwner(); + return vpn != null && vpn.getAlwaysOn(); + } + } + + @Override + public boolean isCallerCurrentAlwaysOnVpnLockdownApp() { + synchronized (mVpns) { + Vpn vpn = getVpnIfOwner(); + return vpn != null && vpn.getLockdown(); + } + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 9bf758797e..0b74d878f0 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -57,7 +57,6 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.IConnectivityManager; import android.net.IpPrefix; import android.net.LinkProperties; import android.net.Network; @@ -97,7 +96,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -239,6 +237,30 @@ public class VpnTest { })), disallow); } + @Test + public void testGetAlwaysAndOnGetLockDown() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + + // Default state. + assertFalse(vpn.getAlwaysOn()); + assertFalse(vpn.getLockdown()); + + // Set always-on without lockdown. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); + assertTrue(vpn.getAlwaysOn()); + assertFalse(vpn.getLockdown()); + + // Set always-on with lockdown. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); + assertTrue(vpn.getAlwaysOn()); + assertTrue(vpn.getLockdown()); + + // Remove always-on configuration. + assertTrue(vpn.setAlwaysOnPackage(null, false)); + assertFalse(vpn.getAlwaysOn()); + assertFalse(vpn.getLockdown()); + } + @Test public void testLockdownChangingPackage() throws Exception { final Vpn vpn = createVpn(primaryUser.id);