blob: 1812509ba6d2f1f55ee07826b613b9475c5efc31 [file] [log] [blame]
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +09001/*
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
17package android.net;
18
19import static com.android.internal.util.Preconditions.checkNotNull;
20
21import android.annotation.IntDef;
22import android.annotation.NonNull;
23import android.annotation.Nullable;
Lorenzo Colittid9a569f2021-02-05 01:10:56 +090024import android.annotation.UserIdInt;
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +090025import android.app.Activity;
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.res.Resources;
30import android.os.RemoteException;
31
Lorenzo Colittid9a569f2021-02-05 01:10:56 +090032import com.android.internal.net.LegacyVpnInfo;
33import com.android.internal.net.VpnConfig;
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +090034import com.android.internal.net.VpnProfile;
35
36import java.io.IOException;
37import java.lang.annotation.Retention;
38import java.lang.annotation.RetentionPolicy;
39import java.security.GeneralSecurityException;
40
41/**
42 * This class provides an interface for apps to manage platform VPN profiles
43 *
44 * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
45 * further app intermediation. When a VPN profile is present and the app is selected as an always-on
46 * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
47 * app (unlike VpnService).
48 *
49 * <p>VPN apps using supported protocols should preferentially use this API over the {@link
50 * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
51 * the guarantee that VPN network traffic is not subjected to on-device packet interception.
52 *
53 * @see Ikev2VpnProfile
54 */
55public class VpnManager {
56 /** Type representing a lack of VPN @hide */
57 public static final int TYPE_VPN_NONE = -1;
58 /** VPN service type code @hide */
59 public static final int TYPE_VPN_SERVICE = 1;
60 /** Platform VPN type code @hide */
61 public static final int TYPE_VPN_PLATFORM = 2;
62
63 /** @hide */
64 @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
65 @Retention(RetentionPolicy.SOURCE)
66 public @interface VpnType {}
67
68 @NonNull private final Context mContext;
69 @NonNull private final IConnectivityManager mService;
70
71 private static Intent getIntentForConfirmation() {
72 final Intent intent = new Intent();
73 final ComponentName componentName = ComponentName.unflattenFromString(
74 Resources.getSystem().getString(
75 com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
76 intent.setComponent(componentName);
77 return intent;
78 }
79
80 /**
81 * Create an instance of the VpnManager with the given context.
82 *
83 * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
84 * {@link Context.getSystemService()} method call.
85 *
86 * @hide
87 */
88 public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
89 mContext = checkNotNull(ctx, "missing Context");
90 mService = checkNotNull(service, "missing IConnectivityManager");
91 }
92
93 /**
94 * Install a VpnProfile configuration keyed on the calling app's package name.
95 *
96 * <p>This method returns {@code null} if user consent has already been granted, or an {@link
97 * Intent} to a system activity. If an intent is returned, the application should launch the
98 * activity using {@link Activity#startActivityForResult} to request user consent. The activity
99 * may pop up a dialog to require user action, and the result will come back via its {@link
100 * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
101 * consented, and the VPN profile can be started.
102 *
103 * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
104 * stored for this package.
105 * @return an Intent requesting user consent to start the VPN, or null if consent is not
106 * required based on privileges or previous user consent.
107 */
108 @Nullable
109 public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
110 final VpnProfile internalProfile;
111
112 try {
113 internalProfile = profile.toVpnProfile();
114 } catch (GeneralSecurityException | IOException e) {
115 // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
116 // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
117 // string as required by the VpnProfile.
118 throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
119 }
120
121 try {
122 // Profile can never be null; it either gets set, or an exception is thrown.
123 if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
124 return null;
125 }
126 } catch (RemoteException e) {
127 throw e.rethrowFromSystemServer();
128 }
129 return getIntentForConfirmation();
130 }
131
132 /**
133 * Delete the VPN profile configuration that was provisioned by the calling app
134 *
135 * @throws SecurityException if this would violate user settings
136 */
137 public void deleteProvisionedVpnProfile() {
138 try {
139 mService.deleteVpnProfile(mContext.getOpPackageName());
140 } catch (RemoteException e) {
141 throw e.rethrowFromSystemServer();
142 }
143 }
144
145 /**
146 * Request the startup of a previously provisioned VPN.
147 *
148 * @throws SecurityException exception if user or device settings prevent this VPN from being
149 * setup, or if user consent has not been granted
150 */
151 public void startProvisionedVpnProfile() {
152 try {
153 mService.startVpnProfile(mContext.getOpPackageName());
154 } catch (RemoteException e) {
155 throw e.rethrowFromSystemServer();
156 }
157 }
158
159 /** Tear down the VPN provided by the calling app (if any) */
160 public void stopProvisionedVpnProfile() {
161 try {
162 mService.stopVpnProfile(mContext.getOpPackageName());
163 } catch (RemoteException e) {
164 throw e.rethrowFromSystemServer();
165 }
166 }
Lorenzo Colittid9a569f2021-02-05 01:10:56 +0900167
168 /**
169 * Return the VPN configuration for the given user ID.
170 * @hide
171 */
172 @Nullable
173 public VpnConfig getVpnConfig(@UserIdInt int userId) {
174 try {
175 return mService.getVpnConfig(userId);
176 } catch (RemoteException e) {
177 throw e.rethrowFromSystemServer();
178 }
179 }
180
181 /**
182 * Prepare for a VPN application.
183 * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
184 * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
185 *
186 * @param oldPackage Package name of the application which currently controls VPN, which will
187 * be replaced. If there is no such application, this should should either be
188 * {@code null} or {@link VpnConfig.LEGACY_VPN}.
189 * @param newPackage Package name of the application which should gain control of VPN, or
190 * {@code null} to disable.
191 * @param userId User for whom to prepare the new VPN.
192 *
193 * @hide
194 */
195 public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
196 int userId) {
197 try {
198 return mService.prepareVpn(oldPackage, newPackage, userId);
199 } catch (RemoteException e) {
200 throw e.rethrowFromSystemServer();
201 }
202 }
203
204 /**
205 * Set whether the VPN package has the ability to launch VPNs without user intervention. This
206 * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
207 * class. If the caller is not {@code userId}, {@link
208 * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
209 *
210 * @param packageName The package for which authorization state should change.
211 * @param userId User for whom {@code packageName} is installed.
212 * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
213 * permissions should be granted. When unauthorizing an app, {@link
214 * VpnManager.TYPE_VPN_NONE} should be used.
215 * @hide
216 */
217 public void setVpnPackageAuthorization(
218 String packageName, int userId, @VpnManager.VpnType int vpnType) {
219 try {
220 mService.setVpnPackageAuthorization(packageName, userId, vpnType);
221 } catch (RemoteException e) {
222 throw e.rethrowFromSystemServer();
223 }
224 }
225
226 /**
227 * Return the legacy VPN information for the specified user ID.
228 * @hide
229 */
230 public LegacyVpnInfo getLegacyVpnInfo(@UserIdInt int userId) {
231 try {
232 return mService.getLegacyVpnInfo(userId);
233 } catch (RemoteException e) {
234 throw e.rethrowFromSystemServer();
235 }
236 }
237
238 /**
239 * Starts a legacy VPN.
240 * @hide
241 */
242 public void startLegacyVpn(VpnProfile profile) {
243 try {
244 mService.startLegacyVpn(profile);
245 } catch (RemoteException e) {
246 throw e.rethrowFromSystemServer();
247 }
248 }
249
250 /**
251 * Informs the service that legacy lockdown VPN state should be updated (e.g., if its keystore
252 * entry has been updated). If the LockdownVpn mechanism is enabled, updates the vpn
253 * with a reload of its profile.
254 *
255 * <p>This method can only be called by the system UID
256 * @return a boolean indicating success
257 *
258 * @hide
259 */
260 public boolean updateLockdownVpn() {
261 try {
262 return mService.updateLockdownVpn();
263 } catch (RemoteException e) {
264 throw e.rethrowFromSystemServer();
265 }
266 }
267}