blob: c87b8279c4d60ff557e950670144f1020904a359 [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;
24import android.app.Activity;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.res.Resources;
29import android.os.RemoteException;
30
31import com.android.internal.net.VpnProfile;
32
33import java.io.IOException;
34import java.lang.annotation.Retention;
35import java.lang.annotation.RetentionPolicy;
36import java.security.GeneralSecurityException;
37
38/**
39 * This class provides an interface for apps to manage platform VPN profiles
40 *
41 * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
42 * further app intermediation. When a VPN profile is present and the app is selected as an always-on
43 * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
44 * app (unlike VpnService).
45 *
46 * <p>VPN apps using supported protocols should preferentially use this API over the {@link
47 * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
48 * the guarantee that VPN network traffic is not subjected to on-device packet interception.
49 *
50 * @see Ikev2VpnProfile
51 */
52public class VpnManager {
53 /** Type representing a lack of VPN @hide */
54 public static final int TYPE_VPN_NONE = -1;
55 /** VPN service type code @hide */
56 public static final int TYPE_VPN_SERVICE = 1;
57 /** Platform VPN type code @hide */
58 public static final int TYPE_VPN_PLATFORM = 2;
59
60 /** @hide */
61 @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
62 @Retention(RetentionPolicy.SOURCE)
63 public @interface VpnType {}
64
65 @NonNull private final Context mContext;
66 @NonNull private final IConnectivityManager mService;
67
68 private static Intent getIntentForConfirmation() {
69 final Intent intent = new Intent();
70 final ComponentName componentName = ComponentName.unflattenFromString(
71 Resources.getSystem().getString(
72 com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
73 intent.setComponent(componentName);
74 return intent;
75 }
76
77 /**
78 * Create an instance of the VpnManager with the given context.
79 *
80 * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
81 * {@link Context.getSystemService()} method call.
82 *
83 * @hide
84 */
85 public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
86 mContext = checkNotNull(ctx, "missing Context");
87 mService = checkNotNull(service, "missing IConnectivityManager");
88 }
89
90 /**
91 * Install a VpnProfile configuration keyed on the calling app's package name.
92 *
93 * <p>This method returns {@code null} if user consent has already been granted, or an {@link
94 * Intent} to a system activity. If an intent is returned, the application should launch the
95 * activity using {@link Activity#startActivityForResult} to request user consent. The activity
96 * may pop up a dialog to require user action, and the result will come back via its {@link
97 * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
98 * consented, and the VPN profile can be started.
99 *
100 * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
101 * stored for this package.
102 * @return an Intent requesting user consent to start the VPN, or null if consent is not
103 * required based on privileges or previous user consent.
104 */
105 @Nullable
106 public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
107 final VpnProfile internalProfile;
108
109 try {
110 internalProfile = profile.toVpnProfile();
111 } catch (GeneralSecurityException | IOException e) {
112 // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
113 // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
114 // string as required by the VpnProfile.
115 throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
116 }
117
118 try {
119 // Profile can never be null; it either gets set, or an exception is thrown.
120 if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
121 return null;
122 }
123 } catch (RemoteException e) {
124 throw e.rethrowFromSystemServer();
125 }
126 return getIntentForConfirmation();
127 }
128
129 /**
130 * Delete the VPN profile configuration that was provisioned by the calling app
131 *
132 * @throws SecurityException if this would violate user settings
133 */
134 public void deleteProvisionedVpnProfile() {
135 try {
136 mService.deleteVpnProfile(mContext.getOpPackageName());
137 } catch (RemoteException e) {
138 throw e.rethrowFromSystemServer();
139 }
140 }
141
142 /**
143 * Request the startup of a previously provisioned VPN.
144 *
145 * @throws SecurityException exception if user or device settings prevent this VPN from being
146 * setup, or if user consent has not been granted
147 */
148 public void startProvisionedVpnProfile() {
149 try {
150 mService.startVpnProfile(mContext.getOpPackageName());
151 } catch (RemoteException e) {
152 throw e.rethrowFromSystemServer();
153 }
154 }
155
156 /** Tear down the VPN provided by the calling app (if any) */
157 public void stopProvisionedVpnProfile() {
158 try {
159 mService.stopVpnProfile(mContext.getOpPackageName());
160 } catch (RemoteException e) {
161 throw e.rethrowFromSystemServer();
162 }
163 }
164}