Verify lock down related flows
This commit verifies the lock down related flows:
- When a user present
- When lock down is reset
- Create LockdownVpnTracker
- isVpnLockdownEnabled(int)
- getVpnLockdownAllowlist(int)
Bug: 230548427
Test: atest VpnManagerServiceTest
Change-Id: Ic42d884b64d2c7ec0caf9dff95d94fc5e52456b2
diff --git a/tests/unit/java/com/android/server/VpnManagerServiceTest.java b/tests/unit/java/com/android/server/VpnManagerServiceTest.java
index c814cc5..c8a93a6 100644
--- a/tests/unit/java/com/android/server/VpnManagerServiceTest.java
+++ b/tests/unit/java/com/android/server/VpnManagerServiceTest.java
@@ -22,7 +22,11 @@
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.MiscAsserts.assertThrows;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -44,10 +48,14 @@
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.security.Credentials;
import androidx.test.filters.SmallTest;
+import com.android.internal.net.VpnProfile;
import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
+import com.android.server.net.LockdownVpnTracker;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -60,6 +68,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
@RunWith(DevSdkIgnoreRunner.class)
@IgnoreUpTo(R) // VpnManagerService is not available before R
@SmallTest
@@ -79,6 +90,8 @@
@Mock private UserManager mUserManager;
@Mock private INetd mNetd;
@Mock private PackageManager mPackageManager;
+ @Mock private VpnProfileStore mVpnProfileStore;
+ @Mock private LockdownVpnTracker mLockdownVpnTracker;
private VpnManagerServiceDependencies mDeps;
private VpnManagerService mService;
@@ -107,6 +120,17 @@
INetd netd, @UserIdInt int userId) {
return mVpn;
}
+
+ @Override
+ public VpnProfileStore getVpnProfileStore() {
+ return mVpnProfileStore;
+ }
+
+ @Override
+ public LockdownVpnTracker createLockDownVpnTracker(Context context, Handler handler,
+ Vpn vpn, VpnProfile profile) {
+ return mLockdownVpnTracker;
+ }
}
@Before
@@ -203,10 +227,14 @@
}
private void sendIntent(Intent intent) {
+ sendIntent(mIntentReceiver, mContext, intent);
+ }
+
+ private void sendIntent(BroadcastReceiver receiver, Context context, Intent intent) {
final Handler h = mHandlerThread.getThreadHandler();
// Send in handler thread.
- h.post(() -> mIntentReceiver.onReceive(mContext, intent));
+ h.post(() -> receiver.onReceive(context, intent));
HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS);
}
@@ -215,6 +243,21 @@
null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
}
+ private void onUserUnlocked(int userId) {
+ sendIntent(buildIntent(Intent.ACTION_USER_UNLOCKED,
+ null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+ }
+
+ private void onUserStopped(int userId) {
+ sendIntent(buildIntent(Intent.ACTION_USER_STOPPED,
+ null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+ }
+
+ private void onLockDownReset() {
+ sendIntent(buildIntent(LockdownVpnTracker.ACTION_LOCKDOWN_RESET, null /* packageName */,
+ UserHandle.USER_SYSTEM, -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));
}
@@ -241,4 +284,111 @@
assertThrows(IllegalStateException.class, () ->
mUserPresentReceiver.onReceive(mContext, new Intent(Intent.ACTION_USER_PRESENT)));
}
+
+ private void setupLockdownVpn(String packageName) {
+ final byte[] profileTag = packageName.getBytes(StandardCharsets.UTF_8);
+ doReturn(profileTag).when(mVpnProfileStore).get(Credentials.LOCKDOWN_VPN);
+ }
+
+ private void setupVpnProfile(String profileName) {
+ final VpnProfile profile = new VpnProfile(profileName);
+ profile.name = profileName;
+ profile.server = "192.0.2.1";
+ profile.dnsServers = "8.8.8.8";
+ profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+ final byte[] encodedProfile = profile.encode();
+ doReturn(encodedProfile).when(mVpnProfileStore).get(Credentials.VPN + profileName);
+ }
+
+ @Test
+ public void testUserPresent() {
+ // Verify that LockDownVpnTracker is not created.
+ verify(mLockdownVpnTracker, never()).init();
+
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+
+ // mUserPresentReceiver only registers ACTION_USER_PRESENT intent and does no verification
+ // on action, so an empty intent is enough.
+ sendIntent(mUserPresentReceiver, mSystemContext, new Intent());
+
+ verify(mLockdownVpnTracker).init();
+ verify(mSystemContext).unregisterReceiver(mUserPresentReceiver);
+ verify(mUserAllContext, never()).unregisterReceiver(any());
+ }
+
+ @Test
+ public void testUpdateLockdownVpn() {
+ setupLockdownVpn(TEST_VPN_PKG);
+ onUserUnlocked(SYSTEM_USER_ID);
+
+ // Will not create lockDownVpnTracker w/o valid profile configured in the keystore
+ verify(mLockdownVpnTracker, never()).init();
+
+ setupVpnProfile(TEST_VPN_PKG);
+
+ // Remove the user from mVpns
+ onUserStopped(SYSTEM_USER_ID);
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker, never()).init();
+
+ // Add user back
+ onUserStarted(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).init();
+
+ // Trigger another update. The existing LockDownVpnTracker should be shut down and
+ // initialize another one.
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).shutdown();
+ verify(mLockdownVpnTracker, times(2)).init();
+ }
+
+ @Test
+ public void testLockdownReset() {
+ // Init LockdownVpnTracker
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).init();
+
+ onLockDownReset();
+ verify(mLockdownVpnTracker).reset();
+ }
+
+ @Test
+ public void testLockdownResetWhenLockdownVpnTrackerIsNotInit() {
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+
+ onLockDownReset();
+
+ // LockDownVpnTracker is not created. Lockdown reset will not take effect.
+ verify(mLockdownVpnTracker, never()).reset();
+ }
+
+ @Test
+ public void testIsVpnLockdownEnabled() {
+ // Vpn is created but the VPN lockdown is not enabled.
+ assertFalse(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+ // Set lockdown for the SYSTEM_USER_ID VPN.
+ doReturn(true).when(mVpn).getLockdown();
+ assertTrue(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+ // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+ assertFalse(mService.isVpnLockdownEnabled(SECONDARY_USER.id));
+ }
+
+ @Test
+ public void testGetVpnLockdownAllowlist() {
+ doReturn(null).when(mVpn).getLockdownAllowlist();
+ assertNull(mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+ final List<String> expected = List.of(PKGS);
+ doReturn(expected).when(mVpn).getLockdownAllowlist();
+ assertEquals(expected, mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+ // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+ assertNull(mService.getVpnLockdownAllowlist(SECONDARY_USER.id));
+ }
}