fwb, settings: Kang Global VPN switch from LMODroid

This enables apps in work profiles to share the same VPN as the main
profile.
This commit is contained in:
Peter Cai 2023-05-17 14:26:36 -04:00
parent 3968f293a8
commit 947bda2f4b
6 changed files with 395 additions and 14 deletions

View File

@ -1,7 +1,7 @@
From b2a523bde06164be9431c4e5f51d3acd2b459bd5 Mon Sep 17 00:00:00 2001
From 6a533d2bf91fcaf9e93e02062f9c420d6abe370a Mon Sep 17 00:00:00 2001
From: Peter Cai <peter@typeblog.net>
Date: Tue, 12 Oct 2021 21:37:22 -0400
Subject: [PATCH 1/4] PackageParser: support glob matching for properties
Subject: [PATCH 1/5] PackageParser: support glob matching for properties
Needed to make phh's vendor overlays work
---
@ -32,5 +32,5 @@ index c15b3e0b80c3..05bb843c0c4d 100644
}
return true;
--
2.39.2
2.40.0

View File

@ -1,7 +1,7 @@
From d5d5ffd0bdf5be719f18b972706948aa87135934 Mon Sep 17 00:00:00 2001
From 5dd2d06d79a5b77ed9ea304812de8420acb86fea Mon Sep 17 00:00:00 2001
From: dhacker29 <dhackerdvm@gmail.com>
Date: Tue, 24 Nov 2015 01:53:47 -0500
Subject: [PATCH 2/4] fw/b: Use ro.build.version.incremental to signal OTA
Subject: [PATCH 2/5] fw/b: Use ro.build.version.incremental to signal OTA
upgrades
[PeterCxy]: On T, there is a new class PackagePartitions that is
@ -104,10 +104,10 @@ index ff80e614be58..8bf0d5ffff76 100644
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0b20683185f0..fdc2b4c11fd1 100644
index f303fedde567..66901edb1c1d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -5139,7 +5139,7 @@ public class ShortcutService extends IShortcutService.Stub {
@@ -5162,7 +5162,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Injection point.
String injectBuildFingerprint() {
@ -117,5 +117,5 @@ index 0b20683185f0..fdc2b4c11fd1 100644
final void wtf(String message) {
--
2.39.2
2.40.0

View File

@ -1,7 +1,7 @@
From 61fc857a22f3e11f2d8095041ee7b006106064f0 Mon Sep 17 00:00:00 2001
From afb0e5101e41dc70d05a0f28d9d50fdb5b414d97 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Sat, 16 Oct 2021 05:27:57 -0700
Subject: [PATCH 3/4] Add support for app signature spoofing
Subject: [PATCH 3/5] Add support for app signature spoofing
This is needed by microG GmsCore to pretend to be the official Google
Play Services package, because client apps check the package signature
@ -159,5 +159,5 @@ index 46b7460dff1b..40549962436f 100644
if (packageInfo == null) {
return null;
--
2.39.2
2.40.0

View File

@ -1,7 +1,7 @@
From 7cd264509a929835a1770e931e3ec8001da7aecb Mon Sep 17 00:00:00 2001
From a1b9bed7443c621a72c1bd33765cd836dbea26ef Mon Sep 17 00:00:00 2001
From: Peter Cai <peter@typeblog.net>
Date: Fri, 2 Sep 2022 21:36:06 -0400
Subject: [PATCH 4/4] FrameworkParsingPackageUtils: Add glob matching support
Subject: [PATCH 4/5] FrameworkParsingPackageUtils: Add glob matching support
for properties
This is now required in addition to the one in PackageParser in order
@ -36,5 +36,5 @@ index 3e1c5bb3d7ec..f15978c57574 100644
}
return true;
--
2.39.2
2.40.0

View File

@ -0,0 +1,201 @@
From c2ebf2cf8f1a013c16a9e44a57bdc44e6d132a2f Mon Sep 17 00:00:00 2001
From: Oliver Scott <olivercscott@gmail.com>
Date: Thu, 8 Jul 2021 10:41:43 -0400
Subject: [PATCH 5/5] Global VPN feature [1/2]
* Modify existing VPN user range functions to conditionally have traffic
from all users pass through the global VPN.
These functions are called when:
1. Starting a VPN
2. Adding a user
3. Removing a user
* Disallow starting VPNs in secondary users when a global VPN is set
Also includes:
Author: Oliver Scott <olivercscott@gmail.com>
Date: 2021-08-27 16:30:22 -0400
Show Global VPN icon on all users
Change-Id: I496c0abbdf92b8f823bc57b297473aa14bd968c8
Change-Id: I42616cc1f4e39e1dad739d81f6d5c55e218be995
Signed-off-by: Mohammad Hasan Keramat J <ikeramat@protonmail.com>
---
core/java/android/provider/Settings.java | 6 +++
.../policy/SecurityControllerImpl.java | 8 +++-
.../com/android/server/connectivity/Vpn.java | 37 +++++++++++++++++--
3 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 94a6382227f3..e091b47bdddd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -15970,6 +15970,12 @@ public final class Settings {
CLOCKWORK_HOME_READY,
};
+ /**
+ * Package designated as global VPN provider.
+ * @hide
+ */
+ public static final String GLOBAL_VPN_APP = "global_vpn_app";
+
/**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index ba947149d287..e5eb04c7818d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -39,6 +39,7 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.security.KeyChain;
import android.util.ArrayMap;
import android.util.Log;
@@ -332,8 +333,13 @@ public class SecurityControllerImpl implements SecurityController {
@Override
public void onUserSwitched(int newUserId) {
mCurrentUserId = newUserId;
+ final String globalVpnApp = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.GLOBAL_VPN_APP);
final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId);
- if (newUserInfo.isRestricted()) {
+ if (mCurrentVpns.get(UserHandle.USER_SYSTEM) != null &&
+ mCurrentVpns.get(UserHandle.USER_SYSTEM).user.equals(globalVpnApp)) {
+ mVpnUserId = UserHandle.USER_SYSTEM;
+ } else if (newUserInfo.isRestricted()) {
// VPN for a restricted profile is routed through its owner user
mVpnUserId = newUserInfo.restrictedProfileParentId;
} else {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8510de4ef201..7c02924a711d 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -691,6 +691,15 @@ public class Vpn {
return mAlwaysOn;
}
+ /**
+ * Returns whether currently prepared VPN package is set as the global VPN.
+ */
+ private synchronized boolean isGlobalVpn() {
+ final String globalVpnPkg = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.GLOBAL_VPN_APP);
+ return mUserId == UserHandle.USER_SYSTEM && mPackage.equals(globalVpnPkg);
+ }
+
/**
* Checks if a VPN app supports always-on mode.
*
@@ -1559,6 +1568,7 @@ public class Vpn {
try {
// Restricted users are not allowed to create VPNs, they are tied to Owner
enforceNotRestrictedUser();
+ enforceNotGlobalVpn();
final PackageManager packageManager = mUserIdContext.getPackageManager();
if (packageManager == null) {
@@ -1720,7 +1730,7 @@ public class Vpn {
addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
// If the user can have restricted profiles, assign all its restricted profiles too
- if (canHaveRestrictedProfile(userId)) {
+ if (canHaveRestrictedProfile(userId) || isGlobalVpn()) {
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
@@ -1729,7 +1739,8 @@ public class Vpn {
Binder.restoreCallingIdentity(token);
}
for (UserInfo user : users) {
- if (user.isRestricted() && (user.restrictedProfileParentId == userId)) {
+ if ((user.isRestricted() && (user.restrictedProfileParentId == userId))
+ || isGlobalVpn()) {
addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
}
}
@@ -1810,7 +1821,8 @@ public class Vpn {
public void onUserAdded(int userId) {
// If the user is restricted tie them to the parent user's VPN
UserInfo user = mUserManager.getUserInfo(userId);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
+ if ((user.isRestricted() && user.restrictedProfileParentId == mUserId) ||
+ isGlobalVpn()) {
synchronized(Vpn.this) {
final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
@@ -1839,7 +1851,8 @@ public class Vpn {
public void onUserRemoved(int userId) {
// clean up if restricted
UserInfo user = mUserManager.getUserInfo(userId);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
+ if ((user.isRestricted() && user.restrictedProfileParentId == mUserId) ||
+ isGlobalVpn()) {
synchronized(Vpn.this) {
final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
@@ -2278,6 +2291,17 @@ public class Vpn {
}
}
+ private void enforceNotGlobalVpn() {
+ Binder.withCleanCallingIdentity(() -> {
+ if (mUserId != UserHandle.USER_SYSTEM && !TextUtils.isEmpty(
+ Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.GLOBAL_VPN_APP))) {
+ throw new SecurityException("Secondary users cannot configure VPNs when" +
+ " global vpn is set");
+ }
+ });
+ }
+
/**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
@@ -2362,6 +2386,7 @@ public class Vpn {
new UserHandle(mUserId))) {
throw new SecurityException("Restricted users cannot establish VPNs");
}
+ enforceNotGlobalVpn();
final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
@@ -3859,6 +3884,7 @@ public class Vpn {
verifyCallingUidAndPackage(packageName);
enforceNotRestrictedUser();
+ enforceNotGlobalVpn();
validateRequiredFeatures(profile);
if (profile.isRestrictedToTestNetworks) {
@@ -3901,6 +3927,7 @@ public class Vpn {
verifyCallingUidAndPackage(packageName);
enforceNotRestrictedUser();
+ enforceNotGlobalVpn();
final long token = Binder.clearCallingIdentity();
try {
@@ -3964,6 +3991,7 @@ public class Vpn {
requireNonNull(packageName, "No package name provided");
enforceNotRestrictedUser();
+ enforceNotGlobalVpn();
// Prepare VPN for startup
if (!prepare(packageName, null /* newPackage */, VpnManager.TYPE_VPN_PLATFORM)) {
@@ -4085,6 +4113,7 @@ public class Vpn {
requireNonNull(packageName, "No package name provided");
enforceNotRestrictedUser();
+ enforceNotGlobalVpn();
// To stop the VPN profile, the caller must be the current prepared package and must be
// running an Ikev2VpnProfile.
--
2.40.0

View File

@ -0,0 +1,180 @@
From 16c9311e41992ddd8d0bfb5a340cedbf001e3413 Mon Sep 17 00:00:00 2001
From: Oliver Scott <olivercscott@gmail.com>
Date: Thu, 8 Jul 2021 10:40:49 -0400
Subject: [PATCH] Global VPN feature [2/2]
* Create a global VPN toggle for VPNs in the system user. It is only
enabled when no VPN is active in any user.
Change-Id: Ic3b79beb635afe03642fce9473bc481239166566
Signed-off-by: Mohammad Hasan Keramat J <ikeramat@protonmail.com>
---
res/values/strings.xml | 5 ++
res/xml/vpn_app_management.xml | 6 +++
.../settings/vpn2/AppManagementFragment.java | 48 ++++++++++++++++++-
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 28b35b3fcf..29ca3882e9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14457,4 +14457,9 @@
<!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
<string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
+ <!-- VPN app management screen, global VPN -->
+ <string name="global_vpn_title">Global VPN</string>
+ <string name="global_vpn_summary">Force all traffic on the device through this VPN, including work profile and other users.</string>
+ <string name="global_vpn_summary_on">Force all traffic on the device through this VPN, including work profile and other users. Note: When enabled, you will not be able to use a separate VPN in a work profile or other users</string>
+ <string name="global_vpn_summary_any_vpn_active">You need to disable all active VPN connections first to enable this</string>
</resources>
diff --git a/res/xml/vpn_app_management.xml b/res/xml/vpn_app_management.xml
index adc441d846..e00f23ccfa 100644
--- a/res/xml/vpn_app_management.xml
+++ b/res/xml/vpn_app_management.xml
@@ -31,6 +31,12 @@
android:selectable="false"/>
-->
+ <SwitchPreference
+ android:key="global_vpn"
+ android:title="@string/global_vpn_title"
+ android:defaultValue="false"
+ android:summary="@string/global_vpn_summary" />
+
<com.android.settingslib.RestrictedSwitchPreference
android:order="10"
android:key="always_on_vpn"
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index d4ee5b9c47..7a52e0c42c 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -28,10 +28,12 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.net.VpnManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
@@ -41,6 +43,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
import com.android.internal.net.VpnConfig;
import com.android.internal.util.ArrayUtils;
@@ -64,6 +67,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment
private static final String ARG_PACKAGE_NAME = "package";
private static final String KEY_VERSION = "version";
+ private static final String KEY_GLOBAL_VPN = "global_vpn";
private static final String KEY_ALWAYS_ON_VPN = "always_on_vpn";
private static final String KEY_LOCKDOWN_VPN = "lockdown_vpn";
private static final String KEY_FORGET_VPN = "forget_vpn";
@@ -79,6 +83,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment
private String mVpnLabel;
// UI preference
+ private SwitchPreference mPreferenceGlobal;
private RestrictedSwitchPreference mPreferenceAlwaysOn;
private RestrictedSwitchPreference mPreferenceLockdown;
private RestrictedPreference mPreferenceForget;
@@ -123,10 +128,16 @@ public class AppManagementFragment extends SettingsPreferenceFragment
mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class);
mVpnManager = getContext().getSystemService(VpnManager.class);
+ mPreferenceGlobal = (SwitchPreference) findPreference(KEY_GLOBAL_VPN);
mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN);
mPreferenceLockdown = (RestrictedSwitchPreference) findPreference(KEY_LOCKDOWN_VPN);
mPreferenceForget = (RestrictedPreference) findPreference(KEY_FORGET_VPN);
+ if (mUserId != UserHandle.USER_SYSTEM) {
+ removePreference(KEY_GLOBAL_VPN);
+ }
+
+ mPreferenceGlobal.setOnPreferenceChangeListener(this);
mPreferenceAlwaysOn.setOnPreferenceChangeListener(this);
mPreferenceLockdown.setOnPreferenceChangeListener(this);
mPreferenceForget.setOnPreferenceClickListener(this);
@@ -204,6 +215,8 @@ public class AppManagementFragment extends SettingsPreferenceFragment
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
switch (preference.getKey()) {
+ case KEY_GLOBAL_VPN:
+ return onGlobalVpnClick((Boolean) newValue);
case KEY_ALWAYS_ON_VPN:
return onAlwaysOnVpnClick((Boolean) newValue, mPreferenceLockdown.isChecked());
case KEY_LOCKDOWN_VPN:
@@ -243,6 +256,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment
return setAlwaysOnVpnByUI(alwaysOnSetting, lockdown);
}
+ private boolean onGlobalVpnClick(final boolean global) {
+ return Settings.Global.putString(getContext().getContentResolver(),
+ Settings.Global.GLOBAL_VPN_APP, global ? mPackageName : "");
+ }
+
@Override
public void onConfirmLockdown(Bundle options, boolean isEnabled, boolean isLockdown) {
setAlwaysOnVpnByUI(isEnabled, isLockdown);
@@ -276,7 +294,18 @@ public class AppManagementFragment extends SettingsPreferenceFragment
final boolean alwaysOn = isVpnAlwaysOn();
final boolean lockdown = alwaysOn
&& VpnUtils.isAnyLockdownActive(getActivity());
-
+ final boolean anyVpnActive = isAnyVpnActive();
+ final boolean globalVpn = isGlobalVpn();
+
+ mPreferenceGlobal.setEnabled(!anyVpnActive);
+ mPreferenceGlobal.setChecked(globalVpn);
+ if (globalVpn) {
+ mPreferenceGlobal.setSummary(R.string.global_vpn_summary_on);
+ } else if (anyVpnActive) {
+ mPreferenceGlobal.setSummary(R.string.global_vpn_summary_any_vpn_active);
+ } else {
+ mPreferenceGlobal.setSummary(R.string.global_vpn_summary);
+ }
mPreferenceAlwaysOn.setChecked(alwaysOn);
mPreferenceLockdown.setChecked(lockdown);
updateRestrictedViews();
@@ -322,6 +351,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment
return mPackageName.equals(getAlwaysOnVpnPackage());
}
+ private boolean isGlobalVpn() {
+ return mPackageName.equals(Settings.Global.getString(
+ getContext().getContentResolver(), Settings.Global.GLOBAL_VPN_APP));
+ }
+
/**
* @return false if the intent doesn't contain an existing package or can't retrieve activated
* vpn info.
@@ -376,6 +410,18 @@ public class AppManagementFragment extends SettingsPreferenceFragment
return config != null && !TextUtils.equals(config.user, mPackageName);
}
+ /**
+ * @return {@code true} if any VPN (VpnService or legacy) is connected or set as always-on.
+ */
+ private boolean isAnyVpnActive() {
+ for (UserInfo userInfo : UserManager.get(getContext()).getUsers()) {
+ if (mVpnManager.getVpnConfig(userInfo.id) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static class CannotConnectFragment extends InstrumentedDialogFragment {
private static final String TAG = "CannotConnect";
private static final String ARG_VPN_LABEL = "label";
--
2.40.0