Merge "Add API for VPN apps to query always-on and lockdown."

am: 479c0769f1

Change-Id: Icb11cdd5c7384eacf1df9b7a0c42e451641f0e04
This commit is contained in:
Pavel Grafov
2019-01-22 07:00:53 -08:00
committed by android-build-merger
6 changed files with 94 additions and 14 deletions

View File

@@ -27766,6 +27766,8 @@ package android.net {
public class VpnService extends android.app.Service {
ctor public VpnService();
method public final boolean isAlwaysOn();
method public final boolean isLockdownEnabled();
method public android.os.IBinder onBind(android.content.Intent);
method public void onRevoke();
method public static android.content.Intent prepare(android.content.Context);

View File

@@ -187,4 +187,6 @@ interface IConnectivityManager
byte[] getNetworkWatchlistConfigHash();
int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
boolean isCallerCurrentAlwaysOnVpnApp();
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
}

View File

@@ -367,6 +367,29 @@ public class VpnService extends Service {
}
}
/**
* Returns whether the service is running in always-on VPN mode.
*/
public final boolean isAlwaysOn() {
try {
return getService().isCallerCurrentAlwaysOnVpnApp();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns whether the service is running in always-on VPN mode blocking connections without
* VPN.
*/
public final boolean isLockdownEnabled() {
try {
return getService().isCallerCurrentAlwaysOnVpnLockdownApp();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return the communication interface to the service. This method returns
* {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}

View File

@@ -6346,6 +6346,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.
@@ -6354,14 +6368,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 "
@@ -6390,4 +6400,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();
}
}
}

View File

@@ -60,7 +60,6 @@ import android.net.NetworkMisc;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
@@ -71,7 +70,6 @@ import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PatternMatcher;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -100,6 +98,8 @@ import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
import libcore.io.IoUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -121,8 +121,6 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import libcore.io.IoUtils;
/**
* @hide
*/
@@ -346,10 +344,17 @@ public class Vpn {
*
* @return {@code true} if VPN lockdown is enabled.
*/
public boolean getLockdown() {
public synchronized boolean getLockdown() {
return mLockdown;
}
/**
* Returns whether VPN is configured as always-on.
*/
public synchronized boolean getAlwaysOn() {
return mAlwaysOn;
}
/**
* Checks if a VPN app supports always-on mode.
*

View File

@@ -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);