diff --git a/tests/unit/java/com/android/server/VpnManagerServiceTest.java b/tests/unit/java/com/android/server/VpnManagerServiceTest.java index ece13b3361..164f8251d7 100644 --- a/tests/unit/java/com/android/server/VpnManagerServiceTest.java +++ b/tests/unit/java/com/android/server/VpnManagerServiceTest.java @@ -24,7 +24,6 @@ import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -32,15 +31,18 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.UserIdInt; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.INetd; +import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Looper; +import android.os.UserHandle; import android.os.UserManager; import androidx.test.filters.SmallTest; @@ -48,14 +50,15 @@ import androidx.test.filters.SmallTest; import com.android.server.connectivity.Vpn; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(R) // VpnManagerService is not available before R @@ -64,18 +67,23 @@ public class VpnManagerServiceTest extends VpnTestBase { @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); - @Spy Context mContext; + private static final int TIMEOUT_MS = 2_000; + + @Mock Context mContext; + @Mock Context mSystemContext; + @Mock Context mUserAllContext; private HandlerThread mHandlerThread; - @Mock private Handler mHandler; @Mock private Vpn mVpn; @Mock private INetworkManagementService mNms; @Mock private ConnectivityManager mCm; @Mock private UserManager mUserManager; @Mock private INetd mNetd; @Mock private PackageManager mPackageManager; + private VpnManagerServiceDependencies mDeps; private VpnManagerService mService; - + private BroadcastReceiver mUserPresentReceiver; + private BroadcastReceiver mIntentReceiver; private final String mNotMyVpnPkg = "com.not.my.vpn"; class VpnManagerServiceDependencies extends VpnManagerService.Dependencies { @@ -107,46 +115,54 @@ public class VpnManagerServiceTest extends VpnTestBase { mHandlerThread = new HandlerThread("TestVpnManagerService"); mDeps = new VpnManagerServiceDependencies(); - doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); + doReturn(mUserAllContext).when(mContext).createContextAsUser(UserHandle.ALL, 0); + doReturn(mSystemContext).when(mContext).createContextAsUser(UserHandle.SYSTEM, 0); doReturn(mPackageManager).when(mContext).getPackageManager(); setMockedPackages(mPackageManager, sPackages); mockService(mContext, ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mCm); mockService(mContext, UserManager.class, Context.USER_SERVICE, mUserManager); - - doReturn(new Intent()).when(mContext).registerReceiver( - any() /* receiver */, - any() /* intentFilter */, - any() /* broadcastPermission */, - eq(mHandler) /* scheduler */); doReturn(SYSTEM_USER).when(mUserManager).getUserInfo(eq(SYSTEM_USER_ID)); + mService = new VpnManagerService(mContext, mDeps); + mService.systemReady(); + + final ArgumentCaptor intentReceiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + final ArgumentCaptor userPresentReceiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mSystemContext).registerReceiver( + userPresentReceiverCaptor.capture(), any(), any(), any()); + verify(mUserAllContext, times(2)).registerReceiver( + intentReceiverCaptor.capture(), any(), any(), any()); + mUserPresentReceiver = userPresentReceiverCaptor.getValue(); + mIntentReceiver = intentReceiverCaptor.getValue(); + + // Add user to create vpn in mVpn + onUserStarted(SYSTEM_USER_ID); + assertNotNull(mService.mVpns.get(SYSTEM_USER_ID)); } @Test public void testUpdateAppExclusionList() { - // Add user to create vpn in mVpn - mService.onUserStarted(SYSTEM_USER_ID); - assertNotNull(mService.mVpns.get(SYSTEM_USER_ID)); - // Start vpn mService.startVpnProfile(TEST_VPN_PKG); verify(mVpn).startVpnProfile(eq(TEST_VPN_PKG)); // Remove package due to package replaced. - mService.onPackageRemoved(PKGS[0], PKG_UIDS[0], true /* isReplacing */); + onPackageRemoved(PKGS[0], PKG_UIDS[0], true /* isReplacing */); verify(mVpn, never()).refreshPlatformVpnAppExclusionList(); // Add package due to package replaced. - mService.onPackageAdded(PKGS[0], PKG_UIDS[0], true /* isReplacing */); + onPackageAdded(PKGS[0], PKG_UIDS[0], true /* isReplacing */); verify(mVpn, never()).refreshPlatformVpnAppExclusionList(); // Remove package - mService.onPackageRemoved(PKGS[0], PKG_UIDS[0], false /* isReplacing */); + onPackageRemoved(PKGS[0], PKG_UIDS[0], false /* isReplacing */); verify(mVpn).refreshPlatformVpnAppExclusionList(); // Add the package back - mService.onPackageAdded(PKGS[0], PKG_UIDS[0], false /* isReplacing */); + onPackageAdded(PKGS[0], PKG_UIDS[0], false /* isReplacing */); verify(mVpn, times(2)).refreshPlatformVpnAppExclusionList(); } @@ -160,4 +176,59 @@ public class VpnManagerServiceTest extends VpnTestBase { public void testStopVpnProfileFromDiffPackage() { assertThrows(SecurityException.class, () -> mService.stopVpnProfile(mNotMyVpnPkg)); } + + @Test + public void testGetProvisionedVpnProfileStateFromDiffPackage() { + assertThrows(SecurityException.class, () -> + mService.getProvisionedVpnProfileState(mNotMyVpnPkg)); + } + + @Test + public void testGetProvisionedVpnProfileState() { + mService.getProvisionedVpnProfileState(TEST_VPN_PKG); + verify(mVpn).getProvisionedVpnProfileState(TEST_VPN_PKG); + } + + private Intent buildIntent(String action, String packageName, int userId, int uid, + boolean isReplacing) { + final Intent intent = new Intent(action); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.putExtra(Intent.EXTRA_UID, uid); + intent.putExtra(Intent.EXTRA_REPLACING, isReplacing); + if (packageName != null) { + intent.setData(Uri.fromParts("package" /* scheme */, packageName, null /* fragment */)); + } + + return intent; + } + + private void sendIntent(Intent intent) { + final Handler h = mHandlerThread.getThreadHandler(); + + // Send in handler thread. + h.post(() -> mIntentReceiver.onReceive(mContext, intent)); + HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS); + } + + private void onUserStarted(int userId) { + sendIntent(buildIntent(Intent.ACTION_USER_STARTED, + null /* packageName */, userId, -1 /* uid */, false /* isReplacing */)); + } + + private void onPackageAdded(String packageName, int userId, int uid, boolean isReplacing) { + sendIntent(buildIntent(Intent.ACTION_PACKAGE_ADDED, packageName, userId, uid, isReplacing)); + } + + private void onPackageAdded(String packageName, int uid, boolean isReplacing) { + onPackageAdded(packageName, UserHandle.USER_SYSTEM, uid, isReplacing); + } + + private void onPackageRemoved(String packageName, int userId, int uid, boolean isReplacing) { + sendIntent(buildIntent(Intent.ACTION_PACKAGE_REMOVED, packageName, userId, uid, + isReplacing)); + } + + private void onPackageRemoved(String packageName, int uid, boolean isReplacing) { + onPackageRemoved(packageName, UserHandle.USER_SYSTEM, uid, isReplacing); + } } diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java index 0891ee36d9..5c1992d9d0 100644 --- a/tests/unit/java/com/android/server/connectivity/VpnTest.java +++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java @@ -232,7 +232,7 @@ public class VpnTest extends VpnTestBase { private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345; private static final long TEST_TIMEOUT_MS = 500L; private static final String PRIMARY_USER_APP_EXCLUDE_KEY = - "VPN_APP_EXCLUDED_27_com.testvpn.vpn"; + "VPNAPPEXCLUDED_27_com.testvpn.vpn"; static final String PKGS_BYTES = getPackageByteString(List.of(PKGS)); private static final Range PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id); @@ -1359,6 +1359,31 @@ public class VpnTest extends VpnTestBase { null /* sessionKey */, true /* alwaysOn */, false /* lockdown */)); } + @Test + public void testReconnectVpnManagerVpnWithAlwaysOnEnabled() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + vpn.startVpnProfile(TEST_VPN_PKG); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); + + // Enable VPN always-on for TEST_VPN_PKG. + assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */, + null /* lockdownAllowlist */)); + + // Reset to verify next startVpnProfile. + reset(mAppOps); + + vpn.stopVpnProfile(TEST_VPN_PKG); + + // Reconnect the vpn with different package will cause exception. + assertThrows(SecurityException.class, () -> vpn.startVpnProfile(PKGS[0])); + + // Reconnect the vpn again with the vpn always on package w/o exception. + vpn.startVpnProfile(TEST_VPN_PKG); + verifyPlatformVpnIsActivated(TEST_VPN_PKG); + } + @Test public void testSetPackageAuthorizationVpnService() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks();