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 0a02e3a380..ef02a7e7b9 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 - * - * - * @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); } /** @@ -1220,6 +1170,45 @@ public class ConnectivityManager { } } + /** + * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by + * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12 + * but is still supported for backwards compatibility. + *

+ * This type of VPN is assumed always to use the system default network, and must always declare + * exactly one underlying network, which is the network that was the default when the VPN + * connected. + *

+ * Calling this method with {@code true} enables legacy behaviour, specifically: + *

+ * + * @param enabled whether legacy lockdown VPN is enabled or disabled + * + * TODO: @SystemApi(client = MODULE_LIBRARIES) + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + public void setLegacyLockdownVpnEnabled(boolean enabled) { + try { + mService.setLegacyLockdownVpnEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Returns details about the currently active default data network * for a given uid. This is for internal use only to avoid spying @@ -3180,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(); } /** @@ -4557,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(); } @@ -4850,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 befd4fb03d..6391802f33 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -43,9 +43,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 @@ -123,35 +120,8 @@ 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); void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); @@ -200,10 +170,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 +189,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 1e30283a9e..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 @@ -76,13 +78,19 @@ public class VpnManager { @Deprecated public static final int TYPE_VPN_LEGACY = 3; + /** + * Channel for VPN notifications. + * @hide + */ + public static final String NOTIFICATION_CHANNEL_VPN = "VPN"; + /** @hide */ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY}) @Retention(RetentionPolicy.SOURCE) 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(); @@ -101,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"); } /** @@ -194,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}, @@ -239,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 + *

+ * + * @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 }