• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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