Loading services/core/java/com/android/server/ConnectivityService.java +0 −11 Original line number Diff line number Diff line Loading @@ -3740,8 +3740,6 @@ public class ConnectivityService extends IConnectivityManager.Stub vpn.setAlwaysOnPackage(null, false); return false; } vpn.saveAlwaysOnPackage(); } return true; } Loading Loading @@ -3902,15 +3900,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId); mVpns.put(userId, userVpn); final ContentResolver cr = mContext.getContentResolver(); String alwaysOnPackage = Settings.Secure.getStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP, userId); final boolean alwaysOnLockdown = Settings.Secure.getIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, /* default */ 0, userId) != 0; if (alwaysOnPackage != null) { userVpn.setAlwaysOnPackage(alwaysOnPackage, alwaysOnLockdown); } } if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { updateLockdownVpn(); Loading services/core/java/com/android/server/connectivity/Vpn.java +102 −26 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading Loading @@ -139,6 +138,7 @@ public class Vpn { private NetworkAgent mNetworkAgent; private final Looper mLooper; private final NetworkCapabilities mNetworkCapabilities; private final SystemServices mSystemServices; /** * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This Loading Loading @@ -206,7 +206,7 @@ public class Vpn { final boolean isPackageRemoved = !intent.getBooleanExtra( Intent.EXTRA_REPLACING, false); if (isPackageRemoved) { setAndSaveAlwaysOnPackage(null, false); setAlwaysOnPackage(null, false); } break; } Loading @@ -217,11 +217,18 @@ public class Vpn { private boolean mIsPackageIntentReceiverRegistered = false; public Vpn(Looper looper, Context context, INetworkManagementService netService, int userHandle) { @UserIdInt int userHandle) { this(looper, context, netService, userHandle, new SystemServices(context)); } @VisibleForTesting protected Vpn(Looper looper, Context context, INetworkManagementService netService, int userHandle, SystemServices systemServices) { mContext = context; mNetd = netService; mUserHandle = userHandle; mLooper = looper; mSystemServices = systemServices; mPackage = VpnConfig.LEGACY_VPN; mOwnerUID = getAppUid(mPackage, mUserHandle); Loading @@ -237,6 +244,8 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); loadAlwaysOnPackage(); } /** Loading Loading @@ -275,6 +284,26 @@ public class Vpn { */ public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { enforceControlPermissionOrInternalCaller(); if (setAlwaysOnPackageInternal(packageName, lockdown)) { saveAlwaysOnPackage(); return true; } return false; } /** * Configures an always-on VPN connection through a specific application, the same as * {@link #setAlwaysOnPackage}. * * Does not perform permission checks. Does not persist any of the changes to storage. * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ @GuardedBy("this") private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; Loading Loading @@ -347,13 +376,13 @@ public class Vpn { /** * Save the always-on package and lockdown config into Settings.Secure */ public synchronized void saveAlwaysOnPackage() { @GuardedBy("this") private void saveAlwaysOnPackage() { final long token = Binder.clearCallingIdentity(); try { final ContentResolver cr = mContext.getContentResolver(); Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP, mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP, getAlwaysOnPackage(), mUserHandle); Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, (mLockdown ? 1 : 0), mUserHandle); } finally { Binder.restoreCallingIdentity(token); Loading @@ -361,18 +390,19 @@ public class Vpn { } /** * Set and save always-on package and lockdown config * @see Vpn#setAlwaysOnPackage(String, boolean) * @see Vpn#saveAlwaysOnPackage() * * @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean) * Load the always-on package and lockdown config from Settings.Secure */ private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) { if (setAlwaysOnPackage(packageName, lockdown)) { saveAlwaysOnPackage(); return true; } else { return false; @GuardedBy("this") private void loadAlwaysOnPackage() { final long token = Binder.clearCallingIdentity(); try { final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser( Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle); final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0; setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown); } finally { Binder.restoreCallingIdentity(token); } } Loading Loading @@ -1276,11 +1306,7 @@ public class Vpn { private void updateAlwaysOnNotification(DetailedState networkState) { final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); updateAlwaysOnNotificationInternal(visible); } @VisibleForTesting protected void updateAlwaysOnNotificationInternal(boolean visible) { final UserHandle user = UserHandle.of(mUserHandle); final long token = Binder.clearCallingIdentity(); try { Loading @@ -1290,10 +1316,8 @@ public class Vpn { return; } final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); final PendingIntent configIntent = PendingIntent.getActivityAsUser( mContext, /* request */ 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, null, user); final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser( intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user); final Notification.Builder builder = new Notification.Builder(mContext, SystemNotificationChannels.VPN) .setSmallIcon(R.drawable.vpn_connected) Loading @@ -1310,6 +1334,58 @@ public class Vpn { } } /** * Facade for system service calls that change, or depend on, state outside of * {@link ConnectivityService} and have hard-to-mock interfaces. * * @see com.android.server.connectivity.VpnTest */ @VisibleForTesting public static class SystemServices { private final Context mContext; public SystemServices(@NonNull Context context) { mContext = context; } /** * @see PendingIntent#getActivityAsUser() */ public PendingIntent pendingIntentGetActivityAsUser( Intent intent, int flags, UserHandle user) { return PendingIntent.getActivityAsUser(mContext, 0 /*request*/, intent, flags, null /*options*/, user); } /** * @see Settings.Secure#putStringForUser */ public void settingsSecurePutStringForUser(String key, String value, int userId) { Settings.Secure.putStringForUser(mContext.getContentResolver(), key, value, userId); } /** * @see Settings.Secure#putIntForUser */ public void settingsSecurePutIntForUser(String key, int value, int userId) { Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId); } /** * @see Settings.Secure#getStringForUser */ public String settingsSecureGetStringForUser(String key, int userId) { return Settings.Secure.getStringForUser(mContext.getContentResolver(), key, userId); } /** * @see Settings.Secure#getIntForUser */ public int settingsSecureGetIntForUser(String key, int def, int userId) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId); } } private native int jniCreate(int mtu); private native String jniGetName(int tun); private native int jniSetAddresses(String interfaze, String addresses); Loading tests/net/java/com/android/server/connectivity/VpnTest.java +31 −20 Original line number Diff line number Diff line Loading @@ -27,10 +27,12 @@ import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.NotificationManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.NetworkInfo.DetailedState; import android.net.UidRange; import android.os.Build; import android.os.INetworkManagementService; import android.os.Looper; import android.os.UserHandle; Loading @@ -45,6 +47,7 @@ import java.util.Arrays; import java.util.Map; import java.util.Set; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; Loading Loading @@ -87,12 +90,13 @@ public class VpnTest extends AndroidTestCase { } } @Mock private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @Mock private PackageManager mPackageManager; @Mock private INetworkManagementService mNetService; @Mock private AppOpsManager mAppOps; @Mock private NotificationManager mNotificationManager; @Mock private Vpn.SystemServices mSystemServices; @Override public void setUp() throws Exception { Loading @@ -104,6 +108,12 @@ public class VpnTest extends AndroidTestCase { when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) .thenReturn(mNotificationManager); // Used by {@link Notification.Builder} ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; when(mContext.getApplicationInfo()).thenReturn(applicationInfo); doNothing().when(mNetService).registerObserver(any()); } Loading @@ -111,7 +121,7 @@ public class VpnTest extends AndroidTestCase { public void testRestrictedProfilesAreAddedToVpn() { setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); Loading @@ -125,7 +135,7 @@ public class VpnTest extends AndroidTestCase { public void testManagedProfilesAreNotAddedToVpn() { setMockedUsers(primaryUser, managedProfileA); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); Loading @@ -138,7 +148,7 @@ public class VpnTest extends AndroidTestCase { public void testAddUserToVpnOnlyAddsOneUser() { setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = new ArraySet<>(); vpn.addUserToRanges(ranges, primaryUser.id, null, null); Loading @@ -149,7 +159,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testUidWhiteAndBlacklist() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; Loading @@ -174,7 +184,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testLockdownChangingPackage() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); // Default state. Loading Loading @@ -209,7 +219,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testLockdownAddingAProfile() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); // Make a copy of the restricted profile, as we're going to mark it deleted halfway through. Loading Loading @@ -249,40 +259,41 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testNotificationShownForAlwaysOnApp() { final Vpn vpn = spyVpn(primaryUser.id); final InOrder order = inOrder(vpn); final UserHandle userHandle = UserHandle.of(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); final InOrder order = inOrder(mNotificationManager); // Don't show a notification for regular disconnected states. vpn.updateState(DetailedState.DISCONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager, atLeastOnce()) .cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Start showing a notification for disconnected once always-on. vpn.setAlwaysOnPackage(PKGS[0], false); order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Stop showing the notification once connected. vpn.updateState(DetailedState.CONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Show the notification if we disconnect again. vpn.updateState(DetailedState.DISCONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Notification should be cleared after unsetting always-on package. vpn.setAlwaysOnPackage(null, false); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); } /** * Mock some methods of vpn object. */ private Vpn spyVpn(@UserIdInt int userId) { final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId)); // Block calls to the NotificationManager or PendingIntent#getActivity. doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean()); return vpn; private Vpn createVpn(@UserIdInt int userId) { return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices); } private static void assertBlocked(Vpn vpn, int... uids) { Loading Loading
services/core/java/com/android/server/ConnectivityService.java +0 −11 Original line number Diff line number Diff line Loading @@ -3740,8 +3740,6 @@ public class ConnectivityService extends IConnectivityManager.Stub vpn.setAlwaysOnPackage(null, false); return false; } vpn.saveAlwaysOnPackage(); } return true; } Loading Loading @@ -3902,15 +3900,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId); mVpns.put(userId, userVpn); final ContentResolver cr = mContext.getContentResolver(); String alwaysOnPackage = Settings.Secure.getStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP, userId); final boolean alwaysOnLockdown = Settings.Secure.getIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, /* default */ 0, userId) != 0; if (alwaysOnPackage != null) { userVpn.setAlwaysOnPackage(alwaysOnPackage, alwaysOnLockdown); } } if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { updateLockdownVpn(); Loading
services/core/java/com/android/server/connectivity/Vpn.java +102 −26 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading Loading @@ -139,6 +138,7 @@ public class Vpn { private NetworkAgent mNetworkAgent; private final Looper mLooper; private final NetworkCapabilities mNetworkCapabilities; private final SystemServices mSystemServices; /** * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This Loading Loading @@ -206,7 +206,7 @@ public class Vpn { final boolean isPackageRemoved = !intent.getBooleanExtra( Intent.EXTRA_REPLACING, false); if (isPackageRemoved) { setAndSaveAlwaysOnPackage(null, false); setAlwaysOnPackage(null, false); } break; } Loading @@ -217,11 +217,18 @@ public class Vpn { private boolean mIsPackageIntentReceiverRegistered = false; public Vpn(Looper looper, Context context, INetworkManagementService netService, int userHandle) { @UserIdInt int userHandle) { this(looper, context, netService, userHandle, new SystemServices(context)); } @VisibleForTesting protected Vpn(Looper looper, Context context, INetworkManagementService netService, int userHandle, SystemServices systemServices) { mContext = context; mNetd = netService; mUserHandle = userHandle; mLooper = looper; mSystemServices = systemServices; mPackage = VpnConfig.LEGACY_VPN; mOwnerUID = getAppUid(mPackage, mUserHandle); Loading @@ -237,6 +244,8 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); loadAlwaysOnPackage(); } /** Loading Loading @@ -275,6 +284,26 @@ public class Vpn { */ public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { enforceControlPermissionOrInternalCaller(); if (setAlwaysOnPackageInternal(packageName, lockdown)) { saveAlwaysOnPackage(); return true; } return false; } /** * Configures an always-on VPN connection through a specific application, the same as * {@link #setAlwaysOnPackage}. * * Does not perform permission checks. Does not persist any of the changes to storage. * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ @GuardedBy("this") private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; Loading Loading @@ -347,13 +376,13 @@ public class Vpn { /** * Save the always-on package and lockdown config into Settings.Secure */ public synchronized void saveAlwaysOnPackage() { @GuardedBy("this") private void saveAlwaysOnPackage() { final long token = Binder.clearCallingIdentity(); try { final ContentResolver cr = mContext.getContentResolver(); Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP, mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP, getAlwaysOnPackage(), mUserHandle); Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, (mLockdown ? 1 : 0), mUserHandle); } finally { Binder.restoreCallingIdentity(token); Loading @@ -361,18 +390,19 @@ public class Vpn { } /** * Set and save always-on package and lockdown config * @see Vpn#setAlwaysOnPackage(String, boolean) * @see Vpn#saveAlwaysOnPackage() * * @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean) * Load the always-on package and lockdown config from Settings.Secure */ private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) { if (setAlwaysOnPackage(packageName, lockdown)) { saveAlwaysOnPackage(); return true; } else { return false; @GuardedBy("this") private void loadAlwaysOnPackage() { final long token = Binder.clearCallingIdentity(); try { final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser( Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle); final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0; setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown); } finally { Binder.restoreCallingIdentity(token); } } Loading Loading @@ -1276,11 +1306,7 @@ public class Vpn { private void updateAlwaysOnNotification(DetailedState networkState) { final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); updateAlwaysOnNotificationInternal(visible); } @VisibleForTesting protected void updateAlwaysOnNotificationInternal(boolean visible) { final UserHandle user = UserHandle.of(mUserHandle); final long token = Binder.clearCallingIdentity(); try { Loading @@ -1290,10 +1316,8 @@ public class Vpn { return; } final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); final PendingIntent configIntent = PendingIntent.getActivityAsUser( mContext, /* request */ 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, null, user); final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser( intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user); final Notification.Builder builder = new Notification.Builder(mContext, SystemNotificationChannels.VPN) .setSmallIcon(R.drawable.vpn_connected) Loading @@ -1310,6 +1334,58 @@ public class Vpn { } } /** * Facade for system service calls that change, or depend on, state outside of * {@link ConnectivityService} and have hard-to-mock interfaces. * * @see com.android.server.connectivity.VpnTest */ @VisibleForTesting public static class SystemServices { private final Context mContext; public SystemServices(@NonNull Context context) { mContext = context; } /** * @see PendingIntent#getActivityAsUser() */ public PendingIntent pendingIntentGetActivityAsUser( Intent intent, int flags, UserHandle user) { return PendingIntent.getActivityAsUser(mContext, 0 /*request*/, intent, flags, null /*options*/, user); } /** * @see Settings.Secure#putStringForUser */ public void settingsSecurePutStringForUser(String key, String value, int userId) { Settings.Secure.putStringForUser(mContext.getContentResolver(), key, value, userId); } /** * @see Settings.Secure#putIntForUser */ public void settingsSecurePutIntForUser(String key, int value, int userId) { Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId); } /** * @see Settings.Secure#getStringForUser */ public String settingsSecureGetStringForUser(String key, int userId) { return Settings.Secure.getStringForUser(mContext.getContentResolver(), key, userId); } /** * @see Settings.Secure#getIntForUser */ public int settingsSecureGetIntForUser(String key, int def, int userId) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId); } } private native int jniCreate(int mtu); private native String jniGetName(int tun); private native int jniSetAddresses(String interfaze, String addresses); Loading
tests/net/java/com/android/server/connectivity/VpnTest.java +31 −20 Original line number Diff line number Diff line Loading @@ -27,10 +27,12 @@ import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.NotificationManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.NetworkInfo.DetailedState; import android.net.UidRange; import android.os.Build; import android.os.INetworkManagementService; import android.os.Looper; import android.os.UserHandle; Loading @@ -45,6 +47,7 @@ import java.util.Arrays; import java.util.Map; import java.util.Set; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; Loading Loading @@ -87,12 +90,13 @@ public class VpnTest extends AndroidTestCase { } } @Mock private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @Mock private PackageManager mPackageManager; @Mock private INetworkManagementService mNetService; @Mock private AppOpsManager mAppOps; @Mock private NotificationManager mNotificationManager; @Mock private Vpn.SystemServices mSystemServices; @Override public void setUp() throws Exception { Loading @@ -104,6 +108,12 @@ public class VpnTest extends AndroidTestCase { when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) .thenReturn(mNotificationManager); // Used by {@link Notification.Builder} ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; when(mContext.getApplicationInfo()).thenReturn(applicationInfo); doNothing().when(mNetService).registerObserver(any()); } Loading @@ -111,7 +121,7 @@ public class VpnTest extends AndroidTestCase { public void testRestrictedProfilesAreAddedToVpn() { setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); Loading @@ -125,7 +135,7 @@ public class VpnTest extends AndroidTestCase { public void testManagedProfilesAreNotAddedToVpn() { setMockedUsers(primaryUser, managedProfileA); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); Loading @@ -138,7 +148,7 @@ public class VpnTest extends AndroidTestCase { public void testAddUserToVpnOnlyAddsOneUser() { setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final Set<UidRange> ranges = new ArraySet<>(); vpn.addUserToRanges(ranges, primaryUser.id, null, null); Loading @@ -149,7 +159,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testUidWhiteAndBlacklist() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; Loading @@ -174,7 +184,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testLockdownChangingPackage() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); // Default state. Loading Loading @@ -209,7 +219,7 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testLockdownAddingAProfile() throws Exception { final Vpn vpn = spyVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); // Make a copy of the restricted profile, as we're going to mark it deleted halfway through. Loading Loading @@ -249,40 +259,41 @@ public class VpnTest extends AndroidTestCase { @SmallTest public void testNotificationShownForAlwaysOnApp() { final Vpn vpn = spyVpn(primaryUser.id); final InOrder order = inOrder(vpn); final UserHandle userHandle = UserHandle.of(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); final InOrder order = inOrder(mNotificationManager); // Don't show a notification for regular disconnected states. vpn.updateState(DetailedState.DISCONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager, atLeastOnce()) .cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Start showing a notification for disconnected once always-on. vpn.setAlwaysOnPackage(PKGS[0], false); order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Stop showing the notification once connected. vpn.updateState(DetailedState.CONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Show the notification if we disconnect again. vpn.updateState(DetailedState.DISCONNECTED, TAG); order.verify(vpn).updateAlwaysOnNotificationInternal(true); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Notification should be cleared after unsetting always-on package. vpn.setAlwaysOnPackage(null, false); order.verify(vpn).updateAlwaysOnNotificationInternal(false); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); } /** * Mock some methods of vpn object. */ private Vpn spyVpn(@UserIdInt int userId) { final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId)); // Block calls to the NotificationManager or PendingIntent#getActivity. doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean()); return vpn; private Vpn createVpn(@UserIdInt int userId) { return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices); } private static void assertBlocked(Vpn vpn, int... uids) { Loading