1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import static com.android.internal.util.Preconditions.checkNotNull; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SystemApi; 28 import android.annotation.UserIdInt; 29 import android.app.Activity; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.res.Resources; 34 import android.os.RemoteException; 35 36 import com.android.internal.net.LegacyVpnInfo; 37 import com.android.internal.net.VpnConfig; 38 import com.android.internal.net.VpnProfile; 39 40 import java.io.IOException; 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 import java.security.GeneralSecurityException; 44 import java.util.List; 45 46 /** 47 * This class provides an interface for apps to manage platform VPN profiles 48 * 49 * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without 50 * further app intermediation. When a VPN profile is present and the app is selected as an always-on 51 * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the 52 * app (unlike VpnService). 53 * 54 * <p>VPN apps using supported protocols should preferentially use this API over the {@link 55 * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user 56 * the guarantee that VPN network traffic is not subjected to on-device packet interception. 57 * 58 * @see Ikev2VpnProfile 59 */ 60 public class VpnManager { 61 /** Type representing a lack of VPN @hide */ 62 @SystemApi(client = MODULE_LIBRARIES) 63 public static final int TYPE_VPN_NONE = -1; 64 65 /** 66 * A VPN created by an app using the {@link VpnService} API. 67 * @hide 68 */ 69 @SystemApi(client = MODULE_LIBRARIES) 70 public static final int TYPE_VPN_SERVICE = 1; 71 72 /** 73 * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}. 74 * @hide 75 */ 76 @SystemApi(client = MODULE_LIBRARIES) 77 public static final int TYPE_VPN_PLATFORM = 2; 78 79 /** 80 * An IPsec VPN created by the built-in LegacyVpnRunner. 81 * @hide 82 */ 83 @SystemApi(client = MODULE_LIBRARIES) 84 public static final int TYPE_VPN_LEGACY = 3; 85 86 /** 87 * An VPN created by OEM code through other means than {@link VpnService} or {@link VpnManager}. 88 * @hide 89 */ 90 @SystemApi(client = MODULE_LIBRARIES) 91 public static final int TYPE_VPN_OEM = 4; 92 93 /** 94 * Channel for VPN notifications. 95 * @hide 96 */ 97 public static final String NOTIFICATION_CHANNEL_VPN = "VPN"; 98 99 /** @hide */ 100 @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY, 101 TYPE_VPN_OEM}) 102 @Retention(RetentionPolicy.SOURCE) 103 public @interface VpnType {} 104 105 @NonNull private final Context mContext; 106 @NonNull private final IVpnManager mService; 107 getIntentForConfirmation()108 private static Intent getIntentForConfirmation() { 109 final Intent intent = new Intent(); 110 final ComponentName componentName = ComponentName.unflattenFromString( 111 Resources.getSystem().getString( 112 com.android.internal.R.string.config_platformVpnConfirmDialogComponent)); 113 intent.setComponent(componentName); 114 return intent; 115 } 116 117 /** 118 * Create an instance of the VpnManager with the given context. 119 * 120 * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the 121 * {@link Context.getSystemService()} method call. 122 * 123 * @hide 124 */ VpnManager(@onNull Context ctx, @NonNull IVpnManager service)125 public VpnManager(@NonNull Context ctx, @NonNull IVpnManager service) { 126 mContext = checkNotNull(ctx, "missing Context"); 127 mService = checkNotNull(service, "missing IVpnManager"); 128 } 129 130 /** 131 * Install a VpnProfile configuration keyed on the calling app's package name. 132 * 133 * <p>This method returns {@code null} if user consent has already been granted, or an {@link 134 * Intent} to a system activity. If an intent is returned, the application should launch the 135 * activity using {@link Activity#startActivityForResult} to request user consent. The activity 136 * may pop up a dialog to require user action, and the result will come back via its {@link 137 * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has 138 * consented, and the VPN profile can be started. 139 * 140 * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile 141 * stored for this package. 142 * @return an Intent requesting user consent to start the VPN, or null if consent is not 143 * required based on privileges or previous user consent. 144 */ 145 @Nullable provisionVpnProfile(@onNull PlatformVpnProfile profile)146 public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) { 147 final VpnProfile internalProfile; 148 149 try { 150 internalProfile = profile.toVpnProfile(); 151 } catch (GeneralSecurityException | IOException e) { 152 // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions 153 // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded 154 // string as required by the VpnProfile. 155 throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e); 156 } 157 158 try { 159 // Profile can never be null; it either gets set, or an exception is thrown. 160 if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) { 161 return null; 162 } 163 } catch (RemoteException e) { 164 throw e.rethrowFromSystemServer(); 165 } 166 return getIntentForConfirmation(); 167 } 168 169 /** 170 * Delete the VPN profile configuration that was provisioned by the calling app 171 * 172 * @throws SecurityException if this would violate user settings 173 */ deleteProvisionedVpnProfile()174 public void deleteProvisionedVpnProfile() { 175 try { 176 mService.deleteVpnProfile(mContext.getOpPackageName()); 177 } catch (RemoteException e) { 178 throw e.rethrowFromSystemServer(); 179 } 180 } 181 182 /** 183 * Request the startup of a previously provisioned VPN. 184 * 185 * @throws SecurityException exception if user or device settings prevent this VPN from being 186 * setup, or if user consent has not been granted 187 */ startProvisionedVpnProfile()188 public void startProvisionedVpnProfile() { 189 try { 190 mService.startVpnProfile(mContext.getOpPackageName()); 191 } catch (RemoteException e) { 192 throw e.rethrowFromSystemServer(); 193 } 194 } 195 196 /** Tear down the VPN provided by the calling app (if any) */ stopProvisionedVpnProfile()197 public void stopProvisionedVpnProfile() { 198 try { 199 mService.stopVpnProfile(mContext.getOpPackageName()); 200 } catch (RemoteException e) { 201 throw e.rethrowFromSystemServer(); 202 } 203 } 204 205 /** 206 * Return the VPN configuration for the given user ID. 207 * @hide 208 */ 209 @Nullable getVpnConfig(@serIdInt int userId)210 public VpnConfig getVpnConfig(@UserIdInt int userId) { 211 try { 212 return mService.getVpnConfig(userId); 213 } catch (RemoteException e) { 214 throw e.rethrowFromSystemServer(); 215 } 216 } 217 218 /** 219 * Resets all VPN settings back to factory defaults. 220 * @hide 221 */ 222 @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) factoryReset()223 public void factoryReset() { 224 try { 225 mService.factoryReset(); 226 } catch (RemoteException e) { 227 throw e.rethrowFromSystemServer(); 228 } 229 } 230 231 /** 232 * Prepare for a VPN application. 233 * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId}, 234 * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required. 235 * 236 * @param oldPackage Package name of the application which currently controls VPN, which will 237 * be replaced. If there is no such application, this should should either be 238 * {@code null} or {@link VpnConfig.LEGACY_VPN}. 239 * @param newPackage Package name of the application which should gain control of VPN, or 240 * {@code null} to disable. 241 * @param userId User for whom to prepare the new VPN. 242 * 243 * @hide 244 */ prepareVpn(@ullable String oldPackage, @Nullable String newPackage, int userId)245 public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage, 246 int userId) { 247 try { 248 return mService.prepareVpn(oldPackage, newPackage, userId); 249 } catch (RemoteException e) { 250 throw e.rethrowFromSystemServer(); 251 } 252 } 253 254 /** 255 * Set whether the VPN package has the ability to launch VPNs without user intervention. This 256 * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn} 257 * class. If the caller is not {@code userId}, {@link 258 * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required. 259 * 260 * @param packageName The package for which authorization state should change. 261 * @param userId User for whom {@code packageName} is installed. 262 * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN 263 * permissions should be granted. When unauthorizing an app, {@link 264 * VpnManager.TYPE_VPN_NONE} should be used. 265 * @hide 266 */ setVpnPackageAuthorization( String packageName, int userId, @VpnManager.VpnType int vpnType)267 public void setVpnPackageAuthorization( 268 String packageName, int userId, @VpnManager.VpnType int vpnType) { 269 try { 270 mService.setVpnPackageAuthorization(packageName, userId, vpnType); 271 } catch (RemoteException e) { 272 throw e.rethrowFromSystemServer(); 273 } 274 } 275 276 /** 277 * Checks if a VPN app supports always-on mode. 278 * 279 * In order to support the always-on feature, an app has to 280 * <ul> 281 * <li>target {@link VERSION_CODES#N API 24} or above, and 282 * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} 283 * meta-data field. 284 * </ul> 285 * 286 * @param userId The identifier of the user for whom the VPN app is installed. 287 * @param vpnPackage The canonical package name of the VPN app. 288 * @return {@code true} if and only if the VPN app exists and supports always-on mode. 289 * @hide 290 */ isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage)291 public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) { 292 try { 293 return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage); 294 } catch (RemoteException e) { 295 throw e.rethrowFromSystemServer(); 296 } 297 } 298 299 /** 300 * Configures an always-on VPN connection through a specific application. 301 * This connection is automatically granted and persisted after a reboot. 302 * 303 * <p>The designated package should declare a {@link VpnService} in its 304 * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, 305 * otherwise the call will fail. 306 * 307 * @param userId The identifier of the user to set an always-on VPN for. 308 * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} 309 * to remove an existing always-on VPN configuration. 310 * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or 311 * {@code false} otherwise. 312 * @param lockdownAllowlist The list of packages that are allowed to access network directly 313 * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so 314 * this method must be called when a package that should be allowed is installed or 315 * uninstalled. 316 * @return {@code true} if the package is set as always-on VPN controller; 317 * {@code false} otherwise. 318 * @hide 319 */ 320 @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist)321 public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, 322 boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) { 323 try { 324 return mService.setAlwaysOnVpnPackage( 325 userId, vpnPackage, lockdownEnabled, lockdownAllowlist); 326 } catch (RemoteException e) { 327 throw e.rethrowFromSystemServer(); 328 } 329 } 330 331 /** 332 * Returns the package name of the currently set always-on VPN application. 333 * If there is no always-on VPN set, or the VPN is provided by the system instead 334 * of by an app, {@code null} will be returned. 335 * 336 * @return Package name of VPN controller responsible for always-on VPN, 337 * or {@code null} if none is set. 338 * @hide 339 */ 340 @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) getAlwaysOnVpnPackageForUser(int userId)341 public String getAlwaysOnVpnPackageForUser(int userId) { 342 try { 343 return mService.getAlwaysOnVpnPackage(userId); 344 } catch (RemoteException e) { 345 throw e.rethrowFromSystemServer(); 346 } 347 } 348 349 /** 350 * @return whether always-on VPN is in lockdown mode. 351 * 352 * @hide 353 **/ 354 @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) isVpnLockdownEnabled(int userId)355 public boolean isVpnLockdownEnabled(int userId) { 356 try { 357 return mService.isVpnLockdownEnabled(userId); 358 } catch (RemoteException e) { 359 throw e.rethrowFromSystemServer(); 360 } 361 } 362 363 /** 364 * @return the list of packages that are allowed to access network when always-on VPN is in 365 * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. 366 * 367 * @hide 368 **/ 369 @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) getVpnLockdownAllowlist(int userId)370 public List<String> getVpnLockdownAllowlist(int userId) { 371 try { 372 return mService.getVpnLockdownAllowlist(userId); 373 } catch (RemoteException e) { 374 throw e.rethrowFromSystemServer(); 375 } 376 } 377 378 /** 379 * Return the legacy VPN information for the specified user ID. 380 * @hide 381 */ getLegacyVpnInfo(@serIdInt int userId)382 public LegacyVpnInfo getLegacyVpnInfo(@UserIdInt int userId) { 383 try { 384 return mService.getLegacyVpnInfo(userId); 385 } catch (RemoteException e) { 386 throw e.rethrowFromSystemServer(); 387 } 388 } 389 390 /** 391 * Starts a legacy VPN. 392 * 393 * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the 394 * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be 395 * thrown. 396 * @hide 397 */ startLegacyVpn(VpnProfile profile)398 public void startLegacyVpn(VpnProfile profile) { 399 try { 400 mService.startLegacyVpn(profile); 401 } catch (RemoteException e) { 402 throw e.rethrowFromSystemServer(); 403 } 404 } 405 406 /** 407 * Informs the service that legacy lockdown VPN state should be updated (e.g., if its keystore 408 * entry has been updated). If the LockdownVpn mechanism is enabled, updates the vpn 409 * with a reload of its profile. 410 * 411 * <p>This method can only be called by the system UID 412 * @return a boolean indicating success 413 * 414 * @hide 415 */ updateLockdownVpn()416 public boolean updateLockdownVpn() { 417 try { 418 return mService.updateLockdownVpn(); 419 } catch (RemoteException e) { 420 throw e.rethrowFromSystemServer(); 421 } 422 } 423 } 424