From c5bf088ced4c729c5a11c4d29e2c0bb9077a4c14 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 25 Apr 2022 23:12:26 +0800 Subject: [PATCH 1/4] Test VpnManager event for CATEGORY_EVENT_DEACTIVATED_BY_USER Bug: 191413541 Test: atest FrameworksNetTests:VpnTest Change-Id: Idc876275b88c2f4ddeb85c43d37d5f657b0f307b --- .../android/server/connectivity/VpnTest.java | 119 ++++++++++++++---- 1 file changed, 92 insertions(+), 27 deletions(-) diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index 33c0868c17..52a61de1cf 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -27,6 +27,7 @@ import static android.content.pm.UserInfo.FLAG_RESTRICTED; import static android.net.ConnectivityManager.NetworkCallback; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; +import static android.net.VpnManager.TYPE_VPN_PLATFORM; import static android.os.UserHandle.PER_USER_RANGE; import static com.android.modules.utils.build.SdkLevel.isAtLeastT; @@ -54,6 +55,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -65,6 +67,7 @@ import android.app.AppOpsManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -118,6 +121,7 @@ import com.android.server.IpSecService; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -271,6 +275,11 @@ public class VpnTest { doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any()); } + @After + public void tearDown() throws Exception { + doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN); + } + private void mockService(Class clazz, String name, T service) { doReturn(service).when(mContext).getSystemService(name); doReturn(name).when(mContext).getSystemServiceName(clazz); @@ -783,6 +792,30 @@ public class VpnTest { verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); } + private void verifyPlatformVpnIsActivated(String packageName) { + verify(mAppOps).noteOpNoThrow( + eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), + eq(Process.myUid()), + eq(packageName), + eq(null) /* attributionTag */, + eq(null) /* message */); + verify(mAppOps).startOp( + eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), + eq(Process.myUid()), + eq(packageName), + eq(null) /* attributionTag */, + eq(null) /* message */); + } + + private void verifyPlatformVpnIsDeactivated(String packageName) { + // Add a small delay to double confirm that finishOp is only called once. + verify(mAppOps, after(100)).finishOp( + eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), + eq(Process.myUid()), + eq(packageName), + eq(null) /* attributionTag */); + } + @Test public void testStartVpnProfile() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); @@ -793,13 +826,7 @@ public class VpnTest { vpn.startVpnProfile(TEST_VPN_PKG); verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); - verify(mAppOps) - .noteOpNoThrow( - eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), - eq(Process.myUid()), - eq(TEST_VPN_PKG), - eq(null) /* attributionTag */, - eq(null) /* message */); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); } @Test @@ -811,7 +838,7 @@ public class VpnTest { vpn.startVpnProfile(TEST_VPN_PKG); - // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown. + // Verify that the ACTIVATE_VPN appop was checked, but no error was thrown. verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG, null /* attributionTag */, null /* message */); } @@ -896,18 +923,7 @@ public class VpnTest { when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); vpn.startVpnProfile(TEST_VPN_PKG); - verify(mAppOps).noteOpNoThrow( - eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), - eq(Process.myUid()), - eq(TEST_VPN_PKG), - eq(null) /* attributionTag */, - eq(null) /* message */); - verify(mAppOps).startOp( - eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), - eq(Process.myUid()), - eq(TEST_VPN_PKG), - eq(null) /* attributionTag */, - eq(null) /* message */); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); // Add a small delay to make sure that startOp is only called once. verify(mAppOps, after(100).times(1)).startOp( eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), @@ -923,12 +939,7 @@ public class VpnTest { eq(null) /* attributionTag */, eq(null) /* message */); vpn.stopVpnProfile(TEST_VPN_PKG); - // Add a small delay to double confirm that startOp is only called once. - verify(mAppOps, after(100)).finishOp( - eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER), - eq(Process.myUid()), - eq(TEST_VPN_PKG), - eq(null) /* attributionTag */); + verifyPlatformVpnIsDeactivated(TEST_VPN_PKG); } @Test @@ -964,6 +975,60 @@ public class VpnTest { eq(null) /* message */); } + private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass, + int errorCode) { + final Context userContext = + mContext.createContextAsUser(UserHandle.of(primaryUser.id), 0 /* flags */); + final ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + + verify(userContext, timeout(TEST_TIMEOUT_MS)).startService( + intentArgumentCaptor.capture()); + + final Intent intent = intentArgumentCaptor.getValue(); + assertEquals(sessionKey, intent.getStringExtra(VpnManager.EXTRA_SESSION_KEY)); + assertTrue(intent.getCategories().contains(category)); + assertEquals(errorClass, + intent.getIntExtra(VpnManager.EXTRA_ERROR_CLASS, -1 /* defaultValue */)); + assertEquals(errorCode, + intent.getIntExtra(VpnManager.EXTRA_ERROR_CODE, -1 /* defaultValue */)); + reset(userContext); + } + + @Test + public void testVpnManagerEventForUserDeactivated() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + // For security reasons, Vpn#prepare() will check that oldPackage and newPackage are either + // null or the package of the caller. This test will call Vpn#prepare() to pretend the old + // VPN is replaced by a new one. But only Settings can change to some other packages, and + // this is checked with CONTROL_VPN so simulate holding CONTROL_VPN in order to pass the + // security checks. + doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN); + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + + // Test the case that the user deactivates the vpn in vpn app. + final String sessionKey1 = vpn.startVpnProfile(TEST_VPN_PKG); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); + vpn.stopVpnProfile(TEST_VPN_PKG); + verifyPlatformVpnIsDeactivated(TEST_VPN_PKG); + // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and + // errorCode won't be set. + verifyVpnManagerEvent(sessionKey1, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, + -1 /* errorClass */, -1 /* errorCode */); + reset(mAppOps); + + // Test the case that the user chooses another vpn and the original one is replaced. + final String sessionKey2 = vpn.startVpnProfile(TEST_VPN_PKG); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); + vpn.prepare(TEST_VPN_PKG, "com.new.vpn" /* newPackage */, TYPE_VPN_PLATFORM); + verifyPlatformVpnIsDeactivated(TEST_VPN_PKG); + // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and + // errorCode won't be set. + verifyVpnManagerEvent(sessionKey2, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, + -1 /* errorClass */, -1 /* errorCode */); + } + @Test public void testSetPackageAuthorizationVpnService() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(); @@ -981,7 +1046,7 @@ public class VpnTest { public void testSetPackageAuthorizationPlatformVpn() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(); - assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM)); + assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, TYPE_VPN_PLATFORM)); verify(mAppOps) .setMode( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), From 0772c169b59e0536a68486a921f9144c5732faff Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 26 Apr 2022 09:09:03 +0800 Subject: [PATCH 2/4] Test VpnManager event for CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED Bug: 225010642 Test: atest FrameworksNetTests:VpnTest Change-Id: I078be4e00470efd9d7a2a87b40919116b99c83b8 --- .../server/ConnectivityServiceTest.java | 4 +- .../android/server/connectivity/VpnTest.java | 93 ++++++++++++++++--- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 37df4eb1ab..454381728e 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -338,6 +338,7 @@ import com.android.net.module.util.ArrayTrackRecord; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.LocationPermissionChecker; import com.android.networkstack.apishim.NetworkAgentConfigShimImpl; +import com.android.networkstack.apishim.api29.ConstantsShim; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.ConnectivityService.NetworkRequestInfo; import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.ReportedInterfaces; @@ -644,7 +645,8 @@ public class ConnectivityServiceTest { @Override public ComponentName startService(Intent service) { final String action = service.getAction(); - if (!VpnConfig.SERVICE_INTERFACE.equals(action)) { + if (!VpnConfig.SERVICE_INTERFACE.equals(action) + && !ConstantsShim.ACTION_VPN_MANAGER_EVENT.equals(action)) { fail("Attempt to start unknown service, action=" + action); } return new ComponentName(service.getPackage(), "com.android.test.Service"); diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index 52a61de1cf..73363deccb 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -91,6 +91,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; import android.net.UidRangeParcel; import android.net.VpnManager; +import android.net.VpnProfileState; import android.net.VpnService; import android.net.VpnTransportInfo; import android.net.ipsec.ike.IkeSessionCallback; @@ -976,21 +977,28 @@ public class VpnTest { } private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass, - int errorCode) { + int errorCode, VpnProfileState... profileState) { final Context userContext = mContext.createContextAsUser(UserHandle.of(primaryUser.id), 0 /* flags */); final ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(userContext, timeout(TEST_TIMEOUT_MS)).startService( - intentArgumentCaptor.capture()); + final int verifyTimes = (profileState == null) ? 1 : profileState.length; + verify(userContext, times(verifyTimes)).startService(intentArgumentCaptor.capture()); - final Intent intent = intentArgumentCaptor.getValue(); - assertEquals(sessionKey, intent.getStringExtra(VpnManager.EXTRA_SESSION_KEY)); - assertTrue(intent.getCategories().contains(category)); - assertEquals(errorClass, - intent.getIntExtra(VpnManager.EXTRA_ERROR_CLASS, -1 /* defaultValue */)); - assertEquals(errorCode, - intent.getIntExtra(VpnManager.EXTRA_ERROR_CODE, -1 /* defaultValue */)); + for (int i = 0; i < verifyTimes; i++) { + final Intent intent = intentArgumentCaptor.getAllValues().get(i); + assertEquals(sessionKey, intent.getStringExtra(VpnManager.EXTRA_SESSION_KEY)); + final Set categories = intent.getCategories(); + assertTrue(categories.contains(category)); + assertEquals(errorClass, + intent.getIntExtra(VpnManager.EXTRA_ERROR_CLASS, -1 /* defaultValue */)); + assertEquals(errorCode, + intent.getIntExtra(VpnManager.EXTRA_ERROR_CODE, -1 /* defaultValue */)); + if (profileState != null) { + assertEquals(profileState[i], intent.getParcelableExtra( + VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class)); + } + } reset(userContext); } @@ -1015,7 +1023,7 @@ public class VpnTest { // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and // errorCode won't be set. verifyVpnManagerEvent(sessionKey1, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, - -1 /* errorClass */, -1 /* errorCode */); + -1 /* errorClass */, -1 /* errorCode */, null /* profileState */); reset(mAppOps); // Test the case that the user chooses another vpn and the original one is replaced. @@ -1026,7 +1034,68 @@ public class VpnTest { // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and // errorCode won't be set. verifyVpnManagerEvent(sessionKey2, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, - -1 /* errorClass */, -1 /* errorCode */); + -1 /* errorClass */, -1 /* errorCode */, null /* profileState */); + } + + @Test + public void testVpnManagerEventForAlwaysOnChanged() throws Exception { + assumeTrue(SdkLevel.isAtLeastT()); + // Calling setAlwaysOnPackage() needs to hold CONTROL_VPN. + doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN); + final Vpn vpn = createVpn(primaryUser.id); + // Enable VPN always-on for PKGS[1]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */, + null /* lockdownAllowlist */)); + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, true /* alwaysOn */, false /* lockdown */)); + + // Enable VPN lockdown for PKGS[1]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true /* lockdown */, + null /* lockdownAllowlist */)); + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, true /* alwaysOn */, true /* lockdown */)); + + // Disable VPN lockdown for PKGS[1]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */, + null /* lockdownAllowlist */)); + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, true /* alwaysOn */, false /* lockdown */)); + + // Disable VPN always-on. + assertTrue(vpn.setAlwaysOnPackage(null, false /* lockdown */, + null /* lockdownAllowlist */)); + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, false /* alwaysOn */, false /* lockdown */)); + + // Enable VPN always-on for PKGS[1] again. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */, + null /* lockdownAllowlist */)); + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, true /* alwaysOn */, false /* lockdown */)); + + // Enable VPN always-on for PKGS[2]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[2], false /* lockdown */, + null /* lockdownAllowlist */)); + // PKGS[1] is replaced with PKGS[2]. + // Pass 2 VpnProfileState objects to verifyVpnManagerEvent(), the first one is sent to + // PKGS[1] to notify PKGS[1] that the VPN always-on is disabled, the second one is sent to + // PKGS[2] to notify PKGS[2] that the VPN always-on is enabled. + verifyVpnManagerEvent(null /* sessionKey */, + VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */, + -1 /* errorCode */, new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, false /* alwaysOn */, false /* lockdown */), + new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, + null /* sessionKey */, true /* alwaysOn */, false /* lockdown */)); } @Test From 827b44daeaec3298429d4e031839e55b864c4bb3 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 22 Apr 2022 03:14:46 +0800 Subject: [PATCH 3/4] Test VpnManager event for CATEGORY_EVENT_IKE_ERROR Bug: 191413541 Test: atest FrameworksNetTests:VpnTest Change-Id: Iebc0ac281eb03fac9626c64e44cdd14be1462d89 --- .../android/server/connectivity/VpnTest.java | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index 73363deccb..b3c25ac8e7 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -95,6 +95,7 @@ import android.net.VpnProfileState; import android.net.VpnService; import android.net.VpnTransportInfo; import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.os.Build.VERSION_CODES; import android.os.Bundle; @@ -1165,15 +1166,16 @@ public class VpnTest { config -> Arrays.asList(config.flags).contains(flag))); } - @Test - public void testStartPlatformVpnAuthenticationFailed() throws Exception { + private void setupPlatformVpnWithSpecificExceptionAndItsErrorCode( + IkeException exception, int errorType, int errorCode) throws Exception { final ArgumentCaptor captor = ArgumentCaptor.forClass(IkeSessionCallback.class); - final IkeProtocolException exception = mock(IkeProtocolException.class); - when(exception.getErrorType()) - .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED); - final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile)); + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + + final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG); final NetworkCallback cb = triggerOnAvailableAndGetCallback(); verifyInterfaceSetCfgWithFlags(IF_STATE_UP); @@ -1183,10 +1185,32 @@ public class VpnTest { verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)) .createIkeSession(any(), any(), any(), any(), captor.capture(), any()); final IkeSessionCallback ikeCb = captor.getValue(); - ikeCb.onClosedExceptionally(exception); + ikeCb.onClosedWithException(exception); - verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb)); - assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state); + verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_IKE_ERROR, errorType, errorCode, + null /* profileState */); + if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) { + verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)) + .unregisterNetworkCallback(eq(cb)); + } + } + + @Test + public void testStartPlatformVpnAuthenticationFailed() throws Exception { + final IkeProtocolException exception = mock(IkeProtocolException.class); + final int errorCode = IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; + when(exception.getErrorType()).thenReturn(errorCode); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.ERROR_CLASS_NOT_RECOVERABLE, errorCode); + } + + @Test + public void testStartPlatformVpnFailedWithRecoverableError() throws Exception { + final IkeProtocolException exception = mock(IkeProtocolException.class); + final int errorCode = IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; + when(exception.getErrorType()).thenReturn(errorCode); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.ERROR_CLASS_RECOVERABLE, errorCode); } @Test From cfec723ef9b7b82586192ee106e0efab52640bc0 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 22 Apr 2022 03:40:27 +0800 Subject: [PATCH 4/4] Test VpnManager event for CATEGORY_EVENT_NETWORK_ERROR Bug: 191413541 Test: atest FrameworksNetTests:VpnTest Change-Id: Idffd5f5f8fc6614281f3fb0884228a797d783fe3 --- .../android/server/connectivity/VpnTest.java | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index b3c25ac8e7..6da4f0729f 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -96,7 +96,10 @@ import android.net.VpnService; import android.net.VpnTransportInfo; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.exceptions.IkeException; +import android.net.ipsec.ike.exceptions.IkeNetworkLostException; +import android.net.ipsec.ike.exceptions.IkeNonProtocolException; import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.net.ipsec.ike.exceptions.IkeTimeoutException; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.ConditionVariable; @@ -141,6 +144,7 @@ import java.io.FileWriter; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1166,8 +1170,8 @@ public class VpnTest { config -> Arrays.asList(config.flags).contains(flag))); } - private void setupPlatformVpnWithSpecificExceptionAndItsErrorCode( - IkeException exception, int errorType, int errorCode) throws Exception { + private void setupPlatformVpnWithSpecificExceptionAndItsErrorCode(IkeException exception, + String category, int errorType, int errorCode) throws Exception { final ArgumentCaptor captor = ArgumentCaptor.forClass(IkeSessionCallback.class); @@ -1187,8 +1191,7 @@ public class VpnTest { final IkeSessionCallback ikeCb = captor.getValue(); ikeCb.onClosedWithException(exception); - verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_IKE_ERROR, errorType, errorCode, - null /* profileState */); + verifyVpnManagerEvent(sessionKey, category, errorType, errorCode, null /* profileState */); if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) { verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)) .unregisterNetworkCallback(eq(cb)); @@ -1201,7 +1204,8 @@ public class VpnTest { final int errorCode = IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; when(exception.getErrorType()).thenReturn(errorCode); setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, - VpnManager.ERROR_CLASS_NOT_RECOVERABLE, errorCode); + VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_NOT_RECOVERABLE, + errorCode); } @Test @@ -1210,7 +1214,50 @@ public class VpnTest { final int errorCode = IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; when(exception.getErrorType()).thenReturn(errorCode); setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, - VpnManager.ERROR_CLASS_RECOVERABLE, errorCode); + VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, errorCode); + } + + @Test + public void testStartPlatformVpnFailedWithUnknownHostException() throws Exception { + final IkeNonProtocolException exception = mock(IkeNonProtocolException.class); + final UnknownHostException unknownHostException = new UnknownHostException(); + final int errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST; + when(exception.getCause()).thenReturn(unknownHostException); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, + errorCode); + } + + @Test + public void testStartPlatformVpnFailedWithIkeTimeoutException() throws Exception { + final IkeNonProtocolException exception = mock(IkeNonProtocolException.class); + final IkeTimeoutException ikeTimeoutException = + new IkeTimeoutException("IkeTimeoutException"); + final int errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT; + when(exception.getCause()).thenReturn(ikeTimeoutException); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, + errorCode); + } + + @Test + public void testStartPlatformVpnFailedWithIkeNetworkLostException() throws Exception { + final IkeNetworkLostException exception = new IkeNetworkLostException( + new Network(100)); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, + VpnManager.ERROR_CODE_NETWORK_LOST); + } + + @Test + public void testStartPlatformVpnFailedWithIOException() throws Exception { + final IkeNonProtocolException exception = mock(IkeNonProtocolException.class); + final IOException ioException = new IOException(); + final int errorCode = VpnManager.ERROR_CODE_NETWORK_IO; + when(exception.getCause()).thenReturn(ioException); + setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception, + VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, + errorCode); } @Test