From 11febba2850737f2840ae836975f09a79c7f9e85 Mon Sep 17 00:00:00 2001 From: liamsmith827 Date: Tue, 23 Jun 2026 04:54:24 +0100 Subject: [PATCH] prevent removing always-on VPN during its app update --- .../core/java/com/android/server/VpnManagerService.java | 5 ++++- .../core/java/com/android/server/connectivity/Vpn.java | 8 ++++++++ .../java/com/android/server/connectivity/VpnTest.java | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index 82efa807e2cfb..afcf2faa56495 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -625,7 +625,7 @@ public boolean setAlwaysOnVpnPackage( if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist)) { return false; } - if (!startAlwaysOnVpn(userId)) { + if (mUserManager.isUserUnlocked(userId) && !startAlwaysOnVpn(userId)) { vpn.setAlwaysOnPackage(null, false, null); return false; } @@ -879,6 +879,9 @@ private void onPackageReplaced(String packageName, int uid) { return; } final int userId = UserHandle.getUserId(uid); + if (!mUserManager.isUserUnlocked()) { + return; + } synchronized (mVpns) { final Vpn vpn = mVpns.get(userId); if (vpn == null) { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index e01960a71598c..920418b51683d 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1146,6 +1146,14 @@ private void loadAlwaysOnPackage() { * was no always-on VPN to start. {@code false} otherwise. */ public boolean startAlwaysOnVpn() { + // If the user is locked and the always-on package has not marked its VpnService as + // directBootAware then isAlwaysOnPackageSupported() will return false. As a result, the + // package will be erroneously removed as the always-on package and in turn leak blocking + // will be disabled too. + if (!mUserManager.isUserUnlocked(mUserId)) { + throw new IllegalStateException("attempted to start VPN prior to unlocking user"); + } + final String alwaysOnPackage; synchronized (this) { alwaysOnPackage = getAlwaysOnPackage(); diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java index b9f0aadd54269..394981825d022 100644 --- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java +++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java @@ -3692,6 +3692,8 @@ private void setMockedUsers(UserInfo... users) { final int id = (int) invocation.getArguments()[0]; return userMap.get(id); }).when(mUserManager).getUserInfo(anyInt()); + + doAnswer(invocation -> true).when(mUserManager).isUserUnlocked(anyInt()); } /**