diff --git a/framework/src/android/net/ConnectivityFrameworkInitializer.java b/framework/src/android/net/ConnectivityFrameworkInitializer.java
index 9afa5d1311..92a792b784 100644
--- a/framework/src/android/net/ConnectivityFrameworkInitializer.java
+++ b/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -49,17 +49,6 @@ public final class ConnectivityFrameworkInitializer {
}
);
- // TODO: move outside of the connectivity JAR
- SystemServiceRegistry.registerContextAwareService(
- Context.VPN_MANAGEMENT_SERVICE,
- VpnManager.class,
- (context) -> {
- final ConnectivityManager cm = context.getSystemService(
- ConnectivityManager.class);
- return cm.createVpnManager();
- }
- );
-
SystemServiceRegistry.registerContextAwareService(
Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
ConnectivityDiagnosticsManager.class,
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 8437798b7b..25b6460ddf 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -824,6 +824,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
+
/**
* A kludge to facilitate static access where a Context pointer isn't available, like in the
* case of the static set/getProcessDefaultNetwork methods and from the Network class.
@@ -1069,106 +1070,55 @@ public class ConnectivityManager {
}
/**
- * Checks if a VPN app supports always-on mode.
- *
- * In order to support the always-on feature, an app has to
- *
- * - target {@link VERSION_CODES#N API 24} or above, and
- *
- not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
- * meta-data field.
- *
- *
- * @param userId The identifier of the user for whom the VPN app is installed.
- * @param vpnPackage The canonical package name of the VPN app.
- * @return {@code true} if and only if the VPN app exists and supports always-on mode.
+ * Calls VpnManager#isAlwaysOnVpnPackageSupportedForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
+ @Deprecated
public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
- try {
- return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().isAlwaysOnVpnPackageSupportedForUser(userId, vpnPackage);
}
/**
- * Configures an always-on VPN connection through a specific application.
- * This connection is automatically granted and persisted after a reboot.
- *
- * The designated package should declare a {@link VpnService} in its
- * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
- * otherwise the call will fail.
- *
- * @param userId The identifier of the user to set an always-on VPN for.
- * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
- * to remove an existing always-on VPN configuration.
- * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
- * {@code false} otherwise.
- * @param lockdownAllowlist The list of packages that are allowed to access network directly
- * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
- * this method must be called when a package that should be allowed is installed or
- * uninstalled.
- * @return {@code true} if the package is set as always-on VPN controller;
- * {@code false} otherwise.
+ * Calls VpnManager#setAlwaysOnVpnPackageForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ @Deprecated
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
boolean lockdownEnabled, @Nullable List lockdownAllowlist) {
- try {
- return mService.setAlwaysOnVpnPackage(
- userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdownEnabled,
+ lockdownAllowlist);
}
- /**
- * Returns the package name of the currently set always-on VPN application.
- * If there is no always-on VPN set, or the VPN is provided by the system instead
- * of by an app, {@code null} will be returned.
- *
- * @return Package name of VPN controller responsible for always-on VPN,
- * or {@code null} if none is set.
+ /**
+ * Calls VpnManager#getAlwaysOnVpnPackageForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ @Deprecated
public String getAlwaysOnVpnPackageForUser(int userId) {
- try {
- return mService.getAlwaysOnVpnPackage(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().getAlwaysOnVpnPackageForUser(userId);
}
/**
- * @return whether always-on VPN is in lockdown mode.
- *
+ * Calls VpnManager#isVpnLockdownEnabled.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
- **/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ */
+ @Deprecated
public boolean isVpnLockdownEnabled(int userId) {
- try {
- return mService.isVpnLockdownEnabled(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
+ return getVpnManager().isVpnLockdownEnabled(userId);
}
/**
- * @return the list of packages that are allowed to access network when always-on VPN is in
- * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
- *
+ * Calls VpnManager#getVpnLockdownAllowlist.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
- **/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ */
+ @Deprecated
public List getVpnLockdownWhitelist(int userId) {
- try {
- return mService.getVpnLockdownWhitelist(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().getVpnLockdownAllowlist(userId);
}
/**
@@ -3219,20 +3169,13 @@ public class ConnectivityManager {
}
/**
- * If the LockdownVpn mechanism is enabled, updates the vpn
- * with a reload of its profile.
- *
- * @return a boolean with {@code} indicating success
- *
- * This method can only be called by the system UID
- * {@hide}
+ * Calls VpnManager#updateLockdownVpn.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
+ * @hide
*/
+ @Deprecated
public boolean updateLockdownVpn() {
- try {
- return mService.updateLockdownVpn();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().updateLockdownVpn();
}
/**
@@ -4596,6 +4539,8 @@ public class ConnectivityManager {
try {
mService.factoryReset();
mTetheringManager.stopAllTethering();
+ // TODO: Migrate callers to VpnManager#factoryReset.
+ getVpnManager().factoryReset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4889,9 +4834,13 @@ public class ConnectivityManager {
return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
}
- /** @hide */
- public VpnManager createVpnManager() {
- return new VpnManager(mContext, mService);
+ /**
+ * Temporary hack to shim calls from ConnectivityManager to VpnManager. We cannot store a
+ * private final mVpnManager because ConnectivityManager is initialized before VpnManager.
+ * @hide TODO: remove.
+ */
+ public VpnManager getVpnManager() {
+ return mContext.getSystemService(VpnManager.class);
}
/** @hide */
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index ab134eb6d2..77aee5ec6f 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -42,9 +42,6 @@ import android.os.PersistableBundle;
import android.os.ResultReceiver;
import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
/**
* Interface that answers queries about, and allows changing, the
@@ -122,34 +119,6 @@ interface IConnectivityManager
ProxyInfo getProxyForNetwork(in Network nework);
- boolean prepareVpn(String oldPackage, String newPackage, int userId);
-
- void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
-
- ParcelFileDescriptor establishVpn(in VpnConfig config);
-
- boolean provisionVpnProfile(in VpnProfile profile, String packageName);
-
- void deleteVpnProfile(String packageName);
-
- void startVpnProfile(String packageName);
-
- void stopVpnProfile(String packageName);
-
- VpnConfig getVpnConfig(int userId);
-
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- void startLegacyVpn(in VpnProfile profile);
-
- LegacyVpnInfo getLegacyVpnInfo(int userId);
-
- boolean updateLockdownVpn();
- boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
- boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
- in List lockdownWhitelist);
- String getAlwaysOnVpnPackage(int userId);
- boolean isVpnLockdownEnabled(int userId);
- List getVpnLockdownWhitelist(int userId);
void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);
void setLegacyLockdownVpnEnabled(boolean enabled);
@@ -200,10 +169,6 @@ interface IConnectivityManager
int getRestoreDefaultNetworkDelay(int networkType);
- boolean addVpnAddress(String address, int prefixLength);
- boolean removeVpnAddress(String address, int prefixLength);
- boolean setUnderlyingNetworksForVpn(in Network[] networks);
-
void factoryReset();
void startNattKeepalive(in Network network, int intervalSeconds,
@@ -223,8 +188,6 @@ interface IConnectivityManager
byte[] getNetworkWatchlistConfigHash();
int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
- boolean isCallerCurrentAlwaysOnVpnApp();
- boolean isCallerCurrentAlwaysOnVpnLockdownApp();
void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
in NetworkRequest request, String callingPackageName);
diff --git a/framework/src/android/net/VpnManager.java b/framework/src/android/net/VpnManager.java
index a65769cc72..f472ed4381 100644
--- a/framework/src/android/net/VpnManager.java
+++ b/framework/src/android/net/VpnManager.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.ComponentName;
@@ -37,6 +38,7 @@ import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.GeneralSecurityException;
+import java.util.List;
/**
* This class provides an interface for apps to manage platform VPN profiles
@@ -88,7 +90,7 @@ public class VpnManager {
public @interface VpnType {}
@NonNull private final Context mContext;
- @NonNull private final IConnectivityManager mService;
+ @NonNull private final IVpnManager mService;
private static Intent getIntentForConfirmation() {
final Intent intent = new Intent();
@@ -107,9 +109,9 @@ public class VpnManager {
*
* @hide
*/
- public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
+ public VpnManager(@NonNull Context ctx, @NonNull IVpnManager service) {
mContext = checkNotNull(ctx, "missing Context");
- mService = checkNotNull(service, "missing IConnectivityManager");
+ mService = checkNotNull(service, "missing IVpnManager");
}
/**
@@ -200,6 +202,19 @@ public class VpnManager {
}
}
+ /**
+ * Resets all VPN settings back to factory defaults.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void factoryReset() {
+ try {
+ mService.factoryReset();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Prepare for a VPN application.
* VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
@@ -245,6 +260,108 @@ public class VpnManager {
}
}
+ /**
+ * Checks if a VPN app supports always-on mode.
+ *
+ * In order to support the always-on feature, an app has to
+ *
+ * - target {@link VERSION_CODES#N API 24} or above, and
+ *
- not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+ * meta-data field.
+ *
+ *
+ * @param userId The identifier of the user for whom the VPN app is installed.
+ * @param vpnPackage The canonical package name of the VPN app.
+ * @return {@code true} if and only if the VPN app exists and supports always-on mode.
+ * @hide
+ */
+ public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
+ try {
+ return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Configures an always-on VPN connection through a specific application.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * The designated package should declare a {@link VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param userId The identifier of the user to set an always-on VPN for.
+ * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+ * to remove an existing always-on VPN configuration.
+ * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
+ * {@code false} otherwise.
+ * @param lockdownAllowlist The list of packages that are allowed to access network directly
+ * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+ * this method must be called when a package that should be allowed is installed or
+ * uninstalled.
+ * @return {@code true} if the package is set as always-on VPN controller;
+ * {@code false} otherwise.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
+ boolean lockdownEnabled, @Nullable List lockdownAllowlist) {
+ try {
+ return mService.setAlwaysOnVpnPackage(
+ userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the package name of the currently set always-on VPN application.
+ * If there is no always-on VPN set, or the VPN is provided by the system instead
+ * of by an app, {@code null} will be returned.
+ *
+ * @return Package name of VPN controller responsible for always-on VPN,
+ * or {@code null} if none is set.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public String getAlwaysOnVpnPackageForUser(int userId) {
+ try {
+ return mService.getAlwaysOnVpnPackage(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return whether always-on VPN is in lockdown mode.
+ *
+ * @hide
+ **/
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public boolean isVpnLockdownEnabled(int userId) {
+ try {
+ return mService.isVpnLockdownEnabled(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the list of packages that are allowed to access network when always-on VPN is in
+ * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
+ *
+ * @hide
+ **/
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public List getVpnLockdownAllowlist(int userId) {
+ try {
+ return mService.getVpnLockdownAllowlist(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Return the legacy VPN information for the specified user ID.
* @hide
diff --git a/framework/src/android/net/VpnService.java b/framework/src/android/net/VpnService.java
index 8e90a119fe..e43b0b6fa6 100644
--- a/framework/src/android/net/VpnService.java
+++ b/framework/src/android/net/VpnService.java
@@ -170,12 +170,11 @@ public class VpnService extends Service {
"android.net.VpnService.SUPPORTS_ALWAYS_ON";
/**
- * Use IConnectivityManager since those methods are hidden and not
- * available in ConnectivityManager.
+ * Use IVpnManager since those methods are hidden and not available in VpnManager.
*/
- private static IConnectivityManager getService() {
- return IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+ private static IVpnManager getService() {
+ return IVpnManager.Stub.asInterface(
+ ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE));
}
/**
@@ -226,15 +225,15 @@ public class VpnService extends Service {
@SystemApi
@RequiresPermission(android.Manifest.permission.CONTROL_VPN)
public static void prepareAndAuthorize(Context context) {
- IConnectivityManager cm = getService();
+ IVpnManager vm = getService();
String packageName = context.getPackageName();
try {
// Only prepare if we're not already prepared.
int userId = context.getUserId();
- if (!cm.prepareVpn(packageName, null, userId)) {
- cm.prepareVpn(null, packageName, userId);
+ if (!vm.prepareVpn(packageName, null, userId)) {
+ vm.prepareVpn(null, packageName, userId);
}
- cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
+ vm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
} catch (RemoteException e) {
// ignore
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 84aaca0ae2..a3a17b3504 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
package com.android.server;
-import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
@@ -138,7 +137,6 @@ import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
-import android.net.VpnService;
import android.net.VpnTransportInfo;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
@@ -170,8 +168,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.security.Credentials;
-import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -187,9 +183,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
@@ -214,9 +207,7 @@ import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
-import com.android.server.net.LockdownVpnTracker;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.utils.PriorityDump;
@@ -309,18 +300,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final PerUidCounter mNetworkRequestCounter;
- private KeyStore mKeyStore;
-
- @VisibleForTesting
- @GuardedBy("mVpns")
- protected final SparseArray mVpns = new SparseArray<>();
-
- // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
- // a direct call to LockdownVpnTracker.isEnabled().
- @GuardedBy("mVpns")
private volatile boolean mLockdownEnabled;
- @GuardedBy("mVpns")
- private LockdownVpnTracker mLockdownTracker;
/**
* Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
@@ -997,13 +977,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return NetworkStackClient.getInstance();
}
- /**
- * Get a reference to the system keystore.
- */
- public KeyStore getKeyStore() {
- return KeyStore.getInstance();
- }
-
/**
* @see ProxyTracker
*/
@@ -1113,7 +1086,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
- mKeyStore = mDeps.getKeyStore();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1202,43 +1174,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
- // Set up the listener for user state for creating user VPNs.
+ // Listen for user add/removes to inform PermissionMonitor.
// Should run on mHandler to avoid any races.
IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
- intentFilter.addAction(Intent.ACTION_USER_STOPPED);
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- mUserAllContext.registerReceiver(
- mIntentReceiver,
- intentFilter,
- null /* broadcastPermission */,
- mHandler);
- mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
- mUserPresentReceiver,
- new IntentFilter(Intent.ACTION_USER_PRESENT),
- null /* broadcastPermission */,
- null /* scheduler */);
-
- // Listen to package add and removal events for all users.
- intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- mUserAllContext.registerReceiver(
- mIntentReceiver,
- intentFilter,
- null /* broadcastPermission */,
- mHandler);
-
- // Listen to lockdown VPN reset.
- intentFilter = new IntentFilter();
- intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- mUserAllContext.registerReceiver(
- mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+ null /* broadcastPermission */, mHandler);
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
@@ -1416,9 +1360,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private Network[] getVpnUnderlyingNetworks(int uid) {
- synchronized (mVpns) {
- if (mLockdownEnabled) return null;
- }
+ if (mLockdownEnabled) return null;
final NetworkAgentInfo nai = getVpnForUid(uid);
if (nai != null) return nai.declaredUnderlyingNetworks;
return null;
@@ -2185,22 +2127,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
isBackgroundRestricted);
}
- /**
- * Require that the caller is either in the same user or has appropriate permission to interact
- * across users.
- *
- * @param userId Target user for whatever operation the current IPC is supposed to perform.
- */
- private void enforceCrossUserPermission(int userId) {
- if (userId == UserHandle.getCallingUserId()) {
- // Not a cross-user call.
- return;
- }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "ConnectivityService");
- }
-
private boolean checkAnyPermissionOf(String... permissions) {
for (String permission : permissions) {
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
@@ -2281,12 +2207,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
}
- private void enforceControlAlwaysOnVpnPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
- "ConnectivityService");
- }
-
private void enforceNetworkStackOrSettingsPermission() {
enforceAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -2452,10 +2372,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
- // for user to unlock device too.
- updateLockdownVpn();
-
// Create network requests for always-on networks.
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
}
@@ -4739,183 +4655,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.e(TAG, s, t);
}
- /**
- * Prepare for a VPN application.
- * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
- * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
- *
- * @param oldPackage Package name of the application which currently controls VPN, which will
- * be replaced. If there is no such application, this should should either be
- * {@code null} or {@link VpnConfig.LEGACY_VPN}.
- * @param newPackage Package name of the application which should gain control of VPN, or
- * {@code null} to disable.
- * @param userId User for whom to prepare the new VPN.
- *
- * @hide
- */
- @Override
- public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
- int userId) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
- } else {
- return false;
- }
- }
- }
-
- /**
- * Set whether the VPN package has the ability to launch VPNs without user intervention. This
- * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
- * class. If the caller is not {@code userId}, {@link
- * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
- *
- * @param packageName The package for which authorization state should change.
- * @param userId User for whom {@code packageName} is installed.
- * @param authorized {@code true} if this app should be able to start a VPN connection without
- * explicit user approval, {@code false} if not.
- * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
- * permissions should be granted. When unauthorizing an app, {@link
- * VpnManager.TYPE_VPN_NONE} should be used.
- * @hide
- */
- @Override
- public void setVpnPackageAuthorization(
- String packageName, int userId, @VpnManager.VpnType int vpnType) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- vpn.setPackageAuthorization(packageName, vpnType);
- }
- }
- }
-
- /**
- * Configure a TUN interface and return its file descriptor. Parameters
- * are encoded and opaque to this class. This method is used by VpnBuilder
- * and not available in ConnectivityManager. Permissions are checked in
- * Vpn class.
- * @hide
- */
- @Override
- public ParcelFileDescriptor establishVpn(VpnConfig config) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).establish(config);
- }
- }
-
- /**
- * Stores the given VPN profile based on the provisioning package name.
- *
- * If there is already a VPN profile stored for the provisioning package, this call will
- * overwrite the profile.
- *
- *
This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @return {@code true} if user consent has already been granted, {@code false} otherwise.
- * @hide
- */
- @Override
- public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
- }
- }
-
- /**
- * Deletes the stored VPN profile for the provisioning package
- *
- *
If there are no profiles for the given package, this method will silently succeed.
- *
- *
This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @hide
- */
- @Override
- public void deleteVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
- }
- }
-
- /**
- * Starts the VPN based on the stored profile for the given package
- *
- *
This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @throws IllegalArgumentException if no profile was found for the given package name.
- * @hide
- */
- @Override
- public void startVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- mVpns.get(user).startVpnProfile(packageName, mKeyStore);
- }
- }
-
- /**
- * Stops the Platform VPN if the provided package is running one.
- *
- *
This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @hide
- */
- @Override
- public void stopVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- mVpns.get(user).stopVpnProfile(packageName);
- }
- }
-
- /**
- * Start legacy VPN, controlling native daemons as needed. Creates a
- * secondary thread to perform connection work, returning quickly.
- */
- @Override
- public void startLegacyVpn(VpnProfile profile) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- final LinkProperties egress = getActiveLinkProperties();
- if (egress == null) {
- throw new IllegalStateException("Missing active network connection");
- }
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
- }
- }
-
- /**
- * Return the information of the ongoing legacy VPN. This method is used
- * by VpnSettings and not available in ConnectivityManager. Permissions
- * are checked in Vpn class.
- */
- @Override
- public LegacyVpnInfo getLegacyVpnInfo(int userId) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- return mVpns.get(userId).getLegacyVpnInfo();
- }
- }
-
/**
* Return the information of all ongoing VPNs.
*
@@ -4925,10 +4664,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private UnderlyingNetworkInfo[] getAllVpnInfo() {
ensureRunningOnConnectivityServiceThread();
- synchronized (mVpns) {
- if (mLockdownEnabled) {
- return new UnderlyingNetworkInfo[0];
- }
+ if (mLockdownEnabled) {
+ return new UnderlyingNetworkInfo[0];
}
List infoList = new ArrayList<>();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
@@ -4984,25 +4721,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.linkProperties.getInterfaceName(), interfaces);
}
- /**
- * Returns the information of the ongoing VPN for {@code userId}. This method is used by
- * VpnDialogs and not available in ConnectivityManager.
- * Permissions are checked in Vpn class.
- * @hide
- */
- @Override
- public VpnConfig getVpnConfig(int userId) {
- enforceCrossUserPermission(userId);
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- return vpn.getVpnConfig();
- } else {
- return null;
- }
- }
- }
-
// TODO This needs to be the default network that applies to the NAI.
private Network[] underlyingNetworksOrDefault(final int ownerUid,
Network[] underlyingNetworks) {
@@ -5096,11 +4814,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler.post(() -> mLockdownEnabled = enabled);
}
- // TODO: remove when the VPN code moves out.
- private boolean isLockdownVpnEnabled() {
- return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
- }
-
private boolean isLegacyLockdownNai(NetworkAgentInfo nai) {
return mLockdownEnabled
&& getVpnType(nai) == VpnManager.TYPE_VPN_LEGACY
@@ -5143,193 +4856,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
: DetailedState.CONNECTED;
}
- @Override
- public boolean updateLockdownVpn() {
- // Allow the system UID for the system server and for Settings.
- // Also, for unit tests, allow the process that ConnectivityService is running in.
- if (mDeps.getCallingUid() != Process.SYSTEM_UID
- && Binder.getCallingPid() != Process.myPid()) {
- logw("Lockdown VPN only available to system process or AID_SYSTEM");
- return false;
- }
-
- synchronized (mVpns) {
- // Tear down existing lockdown if profile was removed
- if (!isLockdownVpnEnabled()) {
- setLockdownTracker(null);
- return true;
- }
-
- byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
- if (profileTag == null) {
- loge("Lockdown VPN configured but cannot be read from keystore");
- return false;
- }
- String profileName = new String(profileTag);
- final VpnProfile profile = VpnProfile.decode(
- profileName, mKeyStore.get(Credentials.VPN + profileName));
- if (profile == null) {
- loge("Lockdown VPN configured invalid profile " + profileName);
- setLockdownTracker(null);
- return true;
- }
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- Vpn vpn = mVpns.get(user);
- if (vpn == null) {
- logw("VPN for user " + user + " not ready yet. Skipping lockdown");
- return false;
- }
- setLockdownTracker(
- new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn, profile));
- }
-
- return true;
- }
-
- /**
- * Internally set new {@link LockdownVpnTracker}, shutting down any existing
- * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
- */
- @GuardedBy("mVpns")
- private void setLockdownTracker(LockdownVpnTracker tracker) {
- // Shutdown any existing tracker
- final LockdownVpnTracker existing = mLockdownTracker;
- // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
- // necessary onBlockedStatusChanged callbacks.
- mLockdownTracker = null;
- if (existing != null) {
- existing.shutdown();
- }
-
- if (tracker != null) {
- mLockdownTracker = tracker;
- mLockdownTracker.init();
- }
- }
-
- /**
- * Throws if there is any currently running, always-on Legacy VPN.
- *
- * The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
- * running across the entire system. Tracking for app-based VPNs is done on a per-user,
- * per-package basis in Vpn.java
- */
- @GuardedBy("mVpns")
- private void throwIfLockdownEnabled() {
- if (mLockdownEnabled) {
- throw new IllegalStateException("Unavailable in lockdown mode");
- }
- }
-
- /**
- * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
- * some setup and then call {@code establish()} to connect.
- *
- * @return {@code true} if the service was started, the service was already connected, or there
- * was no always-on VPN to start. {@code false} otherwise.
- */
- private boolean startAlwaysOnVpn(int userId) {
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- // Shouldn't happen as all code paths that point here should have checked the Vpn
- // exists already.
- Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
- return false;
- }
-
- return vpn.startAlwaysOnVpn(mKeyStore);
- }
- }
-
- @Override
- public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
- enforceSettingsPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
- }
- }
-
- @Override
- public boolean setAlwaysOnVpnPackage(
- int userId, String packageName, boolean lockdown, List lockdownWhitelist) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- // Can't set always-on VPN if legacy VPN is already in lockdown mode.
- if (isLockdownVpnEnabled()) {
- return false;
- }
-
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
- return false;
- }
- if (!startAlwaysOnVpn(userId)) {
- vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String getAlwaysOnVpnPackage(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return null;
- }
- return vpn.getAlwaysOnPackage();
- }
- }
-
- @Override
- public boolean isVpnLockdownEnabled(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- return vpn.getLockdown();
- }
- }
-
- @Override
- public List getVpnLockdownWhitelist(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return null;
- }
- return vpn.getLockdownAllowlist();
- }
- }
-
@Override
public void setProvisioningNotificationVisible(boolean visible, int networkType,
String action) {
@@ -5362,165 +4888,33 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onUserStarted(int userId) {
- synchronized (mVpns) {
- Vpn userVpn = mVpns.get(userId);
- if (userVpn != null) {
- loge("Starting user already has a VPN");
- return;
- }
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
- mVpns.put(userId, userVpn);
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
- updateLockdownVpn();
- }
- }
- }
-
- private void onUserStopped(int userId) {
- synchronized (mVpns) {
- Vpn userVpn = mVpns.get(userId);
- if (userVpn == null) {
- loge("Stopped user has no VPN");
- return;
- }
- userVpn.onUserStopped();
- mVpns.delete(userId);
- }
- }
-
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
- synchronized (mVpns) {
- final int vpnsSize = mVpns.size();
- for (int i = 0; i < vpnsSize; i++) {
- Vpn vpn = mVpns.valueAt(i);
- vpn.onUserAdded(userId);
- }
- }
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
- synchronized (mVpns) {
- final int vpnsSize = mVpns.size();
- for (int i = 0; i < vpnsSize; i++) {
- Vpn vpn = mVpns.valueAt(i);
- vpn.onUserRemoved(userId);
- }
- }
- }
-
- private void onPackageReplaced(String packageName, int uid) {
- if (TextUtils.isEmpty(packageName) || uid < 0) {
- Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
- return;
- }
- final int userId = UserHandle.getUserId(uid);
- synchronized (mVpns) {
- final Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- return;
- }
- // Legacy always-on VPN won't be affected since the package name is not set.
- if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
- log("Restarting always-on VPN package " + packageName + " for user "
- + userId);
- vpn.startAlwaysOnVpn(mKeyStore);
- }
- }
- }
-
- private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
- if (TextUtils.isEmpty(packageName) || uid < 0) {
- Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
- return;
- }
-
- final int userId = UserHandle.getUserId(uid);
- synchronized (mVpns) {
- final Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- return;
- }
- // Legacy always-on VPN won't be affected since the package name is not set.
- if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
- log("Removing always-on VPN package " + packageName + " for user "
- + userId);
- vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- }
- }
- }
-
- private void onUserUnlocked(int userId) {
- synchronized (mVpns) {
- // User present may be sent because of an unlock, which might mean an unlocked keystore.
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
- updateLockdownVpn();
- } else {
- startAlwaysOnVpn(userId);
- }
- }
- }
-
- private void onVpnLockdownReset() {
- synchronized (mVpns) {
- if (mLockdownTracker != null) mLockdownTracker.reset();
- }
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- ensureRunningOnConnectivityServiceThread();
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final Uri packageData = intent.getData();
- final String packageName =
- packageData != null ? packageData.getSchemeSpecificPart() : null;
-
- if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
- onVpnLockdownReset();
- }
// UserId should be filled for below intents, check the existence.
if (userId == UserHandle.USER_NULL) return;
- if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStarted(userId);
- } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStopped(userId);
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(userId);
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- onUserUnlocked(userId);
- } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
- onPackageReplaced(packageName, uid);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- final boolean isReplacing = intent.getBooleanExtra(
- Intent.EXTRA_REPLACING, false);
- onPackageRemoved(packageName, uid, isReplacing);
- } else {
+ } else {
Log.wtf(TAG, "received unexpected intent: " + action);
}
}
};
- private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Try creating lockdown tracker, since user present usually means
- // unlocked keystore.
- updateLockdownVpn();
- // Use the same context that registered receiver before to unregister it. Because use
- // different context to unregister receiver will cause exception.
- context.unregisterReceiver(this);
- }
- };
-
private final HashMap mNetworkProviderInfos = new HashMap<>();
private final HashMap mNetworkRequests = new HashMap<>();
@@ -8260,34 +7654,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- @Override
- public boolean addVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).addAddress(address, prefixLength);
- }
- }
-
- @Override
- public boolean removeVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).removeAddress(address, prefixLength);
- }
- }
-
- @Override
- public boolean setUnderlyingNetworksForVpn(Network[] networks) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- final boolean success;
- synchronized (mVpns) {
- success = mVpns.get(user).setUnderlyingNetworks(networks);
- }
- return success;
- }
-
@Override
public String getCaptivePortalServerUrl() {
enforceNetworkStackOrSettingsPermission();
@@ -8367,8 +7733,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
- final int userId = UserHandle.getCallingUserId();
-
final long token = Binder.clearCallingIdentity();
try {
final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
@@ -8380,44 +7744,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Turn airplane mode off
setAirplaneMode(false);
- if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
- // Remove always-on package
- synchronized (mVpns) {
- final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
- if (alwaysOnPackage != null) {
- setAlwaysOnVpnPackage(userId, null, false, null);
- setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
- }
-
- // Turn Always-on VPN off
- if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
- final long ident = Binder.clearCallingIdentity();
- try {
- mKeyStore.delete(Credentials.LOCKDOWN_VPN);
- mLockdownEnabled = false;
- setLockdownTracker(null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- // Turn VPN off
- VpnConfig vpnConfig = getVpnConfig(userId);
- if (vpnConfig != null) {
- if (vpnConfig.legacy) {
- prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
- } else {
- // Prevent this app (packagename = vpnConfig.user) from initiating
- // VPN connections in the future without user intervention.
- setVpnPackageAuthorization(
- vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
-
- prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
- }
- }
- }
- }
-
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
Settings.Global.putString(mContext.getContentResolver(),
@@ -8509,25 +7835,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- @GuardedBy("mVpns")
- private Vpn getVpnIfOwner() {
- return getVpnIfOwner(mDeps.getCallingUid());
- }
-
- // TODO: stop calling into Vpn.java and get this information from data in this class.
- @GuardedBy("mVpns")
- private Vpn getVpnIfOwner(int uid) {
- final int user = UserHandle.getUserId(uid);
-
- final Vpn vpn = mVpns.get(user);
- if (vpn == null) {
- return null;
- } else {
- final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
- return (info == null || info.ownerUid != uid) ? null : vpn;
- }
- }
-
private @VpnManager.VpnType int getVpnType(@Nullable NetworkAgentInfo vpn) {
if (vpn == null) return VpnManager.TYPE_VPN_NONE;
final TransportInfo ti = vpn.networkCapabilities.getTransportInfo();
@@ -8564,22 +7871,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return uid;
}
- @Override
- public boolean isCallerCurrentAlwaysOnVpnApp() {
- synchronized (mVpns) {
- Vpn vpn = getVpnIfOwner();
- return vpn != null && vpn.getAlwaysOn();
- }
- }
-
- @Override
- public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
- synchronized (mVpns) {
- Vpn vpn = getVpnIfOwner();
- return vpn != null && vpn.getLockdown();
- }
- }
-
/**
* Returns a IBinder to a TestNetworkService. Will be lazily created as needed.
*
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
index 95a794235a..c548e30761 100644
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -49,7 +49,7 @@ public class VpnManagerTest {
private static final String IDENTITY_STRING = "Identity";
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
- private IConnectivityManager mMockCs;
+ private IVpnManager mMockService;
private VpnManager mVpnManager;
private final MockContext mMockContext =
new MockContext() {
@@ -61,24 +61,26 @@ public class VpnManagerTest {
@Before
public void setUp() throws Exception {
- mMockCs = mock(IConnectivityManager.class);
- mVpnManager = new VpnManager(mMockContext, mMockCs);
+ mMockService = mock(IVpnManager.class);
+ mVpnManager = new VpnManager(mMockContext, mMockService);
}
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(true);
+ when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+ .thenReturn(true);
// Expect there to be no intent returned, as consent has already been granted.
assertNull(mVpnManager.provisionVpnProfile(profile));
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+ verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testProvisionVpnProfileNeedsConsent() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false);
+ when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+ .thenReturn(false);
// Expect intent to be returned, as consent has not already been granted.
final Intent intent = mVpnManager.provisionVpnProfile(profile);
@@ -88,25 +90,25 @@ public class VpnManagerTest {
ComponentName.unflattenFromString(
"com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
assertEquals(expectedComponentName, intent.getComponent());
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+ verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testDeleteProvisionedVpnProfile() throws Exception {
mVpnManager.deleteProvisionedVpnProfile();
- verify(mMockCs).deleteVpnProfile(eq(PKG_NAME));
+ verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
}
@Test
public void testStartProvisionedVpnProfile() throws Exception {
mVpnManager.startProvisionedVpnProfile();
- verify(mMockCs).startVpnProfile(eq(PKG_NAME));
+ verify(mMockService).startVpnProfile(eq(PKG_NAME));
}
@Test
public void testStopProvisionedVpnProfile() throws Exception {
mVpnManager.stopProvisionedVpnProfile();
- verify(mMockCs).stopVpnProfile(eq(PKG_NAME));
+ verify(mMockService).stopVpnProfile(eq(PKG_NAME));
}
private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1da4e317a0..917a359523 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -370,6 +370,7 @@ public class ConnectivityServiceTest {
private MockContext mServiceContext;
private HandlerThread mCsHandlerThread;
+ private HandlerThread mVMSHandlerThread;
private ConnectivityService.Dependencies mDeps;
private ConnectivityService mService;
private WrappedConnectivityManager mCm;
@@ -384,6 +385,7 @@ public class ConnectivityServiceTest {
private TestNetIdManager mNetIdManager;
private QosCallbackMockHelper mQosCallbackMockHelper;
private QosCallbackTracker mQosCallbackTracker;
+ private VpnManagerService mVpnManagerService;
// State variables required to emulate NetworkPolicyManagerService behaviour.
private int mUidRules = RULE_NONE;
@@ -1256,15 +1258,29 @@ public class ConnectivityServiceTest {
r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
}
- private void mockVpn(int uid) {
- synchronized (mService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // This has no effect unless the VPN is actually connected, because things like
- // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
- // netId, and check if that network is actually connected.
- mService.mVpns.put(userId, mMockVpn);
- }
+ private VpnManagerService makeVpnManagerService() {
+ final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
+ public int getCallingUid() {
+ return mDeps.getCallingUid();
+ }
+
+ public HandlerThread makeHandlerThread() {
+ return mVMSHandlerThread;
+ }
+
+ public KeyStore getKeyStore() {
+ return mKeyStore;
+ }
+
+ public INetd getNetd() {
+ return mMockNetd;
+ }
+
+ public INetworkManagementService getINetworkManagementService() {
+ return mNetworkManagementService;
+ }
+ };
+ return new VpnManagerService(mServiceContext, deps);
}
private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
@@ -1278,11 +1294,21 @@ public class ConnectivityServiceTest {
private void processBroadcastForVpn(Intent intent) {
// The BroadcastReceiver for this broadcast checks it is being run on the handler thread.
- final Handler handler = new Handler(mCsHandlerThread.getLooper());
+ final Handler handler = new Handler(mVMSHandlerThread.getLooper());
handler.post(() -> mServiceContext.sendBroadcast(intent));
+ HandlerUtils.waitForIdle(handler, TIMEOUT_MS);
waitForIdle();
}
+ private void mockVpn(int uid) {
+ synchronized (mVpnManagerService.mVpns) {
+ int userId = UserHandle.getUserId(uid);
+ mMockVpn = new MockVpn(userId);
+ // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
+ mVpnManagerService.mVpns.put(userId, mMockVpn);
+ }
+ }
+
private void mockUidNetworkingBlocked() {
doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
.checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
@@ -1406,6 +1432,7 @@ public class ConnectivityServiceTest {
initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
mCsHandlerThread = new HandlerThread("TestConnectivityService");
+ mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
mDeps = makeDependencies();
returnRealCallingUid();
mService = new ConnectivityService(mServiceContext,
@@ -1428,6 +1455,8 @@ public class ConnectivityServiceTest {
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReadyInternal();
+ mVpnManagerService = makeVpnManagerService();
+ mVpnManagerService.systemReady();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
mQosCallbackTracker = mock(QosCallbackTracker.class);
@@ -1455,7 +1484,6 @@ public class ConnectivityServiceTest {
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
- doReturn(mKeyStore).when(deps).getKeyStore();
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -6766,8 +6794,8 @@ public class ConnectivityServiceTest {
// Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
final ArrayList allowList = new ArrayList<>();
- mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
+ true /* lockdown */, allowList);
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
// This is arguably overspecified: a UID that is not running doesn't have an active network.
@@ -6797,7 +6825,8 @@ public class ConnectivityServiceTest {
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
- mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
+ allowList);
waitForIdle();
}
@@ -7173,7 +7202,8 @@ public class ConnectivityServiceTest {
final int uid = Process.myUid();
final int userId = UserHandle.getUserId(uid);
final ArrayList allowList = new ArrayList<>();
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
waitForIdle();
UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
@@ -7195,7 +7225,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown, expect to see the network unblocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -7208,7 +7238,8 @@ public class ConnectivityServiceTest {
// Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
allowList.add(TEST_PACKAGE_NAME);
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
@@ -7241,11 +7272,12 @@ public class ConnectivityServiceTest {
// Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
// Everything should now be blocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
allowList.clear();
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
@@ -7258,7 +7290,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown. Everything is unblocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -7270,7 +7302,8 @@ public class ConnectivityServiceTest {
// Enable and disable an always-on VPN package without lockdown. Expect no changes.
reset(mMockNetd);
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
+ allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -7281,7 +7314,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -7293,7 +7326,8 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
// Enable lockdown and connect a VPN. The VPN is not blocked.
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();