Merge changes from topic "always-on-vpn"

* changes:
  Opt-out for always-on VPN: rename API.
  Opt-out for always-on VPN
This commit is contained in:
Charles He
2017-09-19 07:50:13 +00:00
committed by Gerrit Code Review
4 changed files with 93 additions and 11 deletions

View File

@@ -834,6 +834,29 @@ public class ConnectivityManager {
} }
} }
/**
* Checks if a VPN app supports always-on mode.
*
* In order to support the always-on feature, an app has to
* <ul>
* <li>target {@link VERSION_CODES#N API 24} or above, and
* <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
* meta-data field.
* </ul>
*
* @param userId The identifier of the user for whom the VPN app is installed.
* @param vpnPackage The canonical package name of the VPN app.
* @return {@code true} if and only if the VPN app exists and supports always-on mode.
* @hide
*/
public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
try {
return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** /**
* Configures an always-on VPN connection through a specific application. * Configures an always-on VPN connection through a specific application.
* This connection is automatically granted and persisted after a reboot. * This connection is automatically granted and persisted after a reboot.

View File

@@ -123,6 +123,7 @@ interface IConnectivityManager
VpnInfo[] getAllVpnInfo(); VpnInfo[] getAllVpnInfo();
boolean updateLockdownVpn(); boolean updateLockdownVpn();
boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown);
String getAlwaysOnVpnPackage(int userId); String getAlwaysOnVpnPackage(int userId);

View File

@@ -128,9 +128,9 @@ import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService; import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor;
@@ -1515,6 +1515,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
ConnectivityManager.enforceChangePermission(mContext); ConnectivityManager.enforceChangePermission(mContext);
} }
private void enforceSettingsPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.NETWORK_SETTINGS,
"ConnectivityService");
}
private void enforceTetherAccessPermission() { private void enforceTetherAccessPermission() {
mContext.enforceCallingOrSelfPermission( mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -3645,6 +3651,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
@Override
public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
enforceSettingsPermission();
enforceCrossUserPermission(userId);
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return false;
}
return vpn.isAlwaysOnPackageSupported(packageName);
}
}
@Override @Override
public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) { public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) {
enforceConnectivityInternalPermission(); enforceConnectivityInternalPermission();

View File

@@ -27,13 +27,16 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.UidRange; import android.net.UidRange;
import android.os.Build; import android.net.VpnService;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.Looper; import android.os.Looper;
import android.os.UserHandle; import android.os.UserHandle;
@@ -45,22 +48,22 @@ import android.util.ArraySet;
import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import org.mockito.Answers; import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/** /**
* Tests for {@link Vpn}. * Tests for {@link Vpn}.
* *
* Build, install and run with: * Build, install and run with:
* runtest --path src/com/android/server/connectivity/VpnTest.java * runtest --path java/com/android/server/connectivity/VpnTest.java
*/ */
public class VpnTest extends AndroidTestCase { public class VpnTest extends AndroidTestCase {
private static final String TAG = "VpnTest"; private static final String TAG = "VpnTest";
@@ -116,7 +119,7 @@ public class VpnTest extends AndroidTestCase {
// Used by {@link Notification.Builder} // Used by {@link Notification.Builder}
ApplicationInfo applicationInfo = new ApplicationInfo(); ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
when(mContext.getApplicationInfo()).thenReturn(applicationInfo); when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
doNothing().when(mNetService).registerObserver(any()); doNothing().when(mNetService).registerObserver(any());
@@ -314,6 +317,40 @@ public class VpnTest extends AndroidTestCase {
order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
} }
@SmallTest
public void testIsAlwaysOnPackageSupported() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
ApplicationInfo appInfo = new ApplicationInfo();
when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
.thenReturn(appInfo);
ServiceInfo svcInfo = new ServiceInfo();
ResolveInfo resInfo = new ResolveInfo();
resInfo.serviceInfo = svcInfo;
when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
eq(primaryUser.id)))
.thenReturn(Collections.singletonList(resInfo));
// null package name should return false
assertFalse(vpn.isAlwaysOnPackageSupported(null));
// Pre-N apps are not supported
appInfo.targetSdkVersion = VERSION_CODES.M;
assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
// N+ apps are supported by default
appInfo.targetSdkVersion = VERSION_CODES.N;
assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
// Apps that opt out explicitly are not supported
appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
Bundle metaData = new Bundle();
metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
svcInfo.metaData = metaData;
assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
}
@SmallTest @SmallTest
public void testNotificationShownForAlwaysOnApp() { public void testNotificationShownForAlwaysOnApp() {
final UserHandle userHandle = UserHandle.of(primaryUser.id); final UserHandle userHandle = UserHandle.of(primaryUser.id);