• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 com.android.server.connectivity;
18 
19 import static android.Manifest.permission.BIND_VPN_SERVICE;
20 import static android.Manifest.permission.CONTROL_VPN;
21 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
24 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
25 import static android.net.RouteInfo.RTN_UNREACHABLE;
26 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
27 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
28 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
29 import static android.net.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
30 import static android.os.PowerWhitelistManager.REASON_VPN;
31 import static android.os.UserHandle.PER_USER_RANGE;
32 import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
33 import static android.telephony.CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT;
34 
35 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
36 
37 import static java.util.Objects.requireNonNull;
38 
39 import android.Manifest;
40 import android.annotation.NonNull;
41 import android.annotation.Nullable;
42 import android.annotation.UserIdInt;
43 import android.app.AppOpsManager;
44 import android.app.Notification;
45 import android.app.NotificationManager;
46 import android.app.PendingIntent;
47 import android.content.ComponentName;
48 import android.content.ContentResolver;
49 import android.content.Context;
50 import android.content.Intent;
51 import android.content.ServiceConnection;
52 import android.content.pm.ApplicationInfo;
53 import android.content.pm.PackageManager;
54 import android.content.pm.PackageManager.NameNotFoundException;
55 import android.content.pm.ResolveInfo;
56 import android.content.pm.UserInfo;
57 import android.net.ConnectivityDiagnosticsManager;
58 import android.net.ConnectivityManager;
59 import android.net.INetd;
60 import android.net.INetworkManagementEventObserver;
61 import android.net.Ikev2VpnProfile;
62 import android.net.InetAddresses;
63 import android.net.IpPrefix;
64 import android.net.IpSecManager;
65 import android.net.IpSecManager.IpSecTunnelInterface;
66 import android.net.IpSecTransform;
67 import android.net.LinkAddress;
68 import android.net.LinkProperties;
69 import android.net.Network;
70 import android.net.NetworkAgent;
71 import android.net.NetworkAgentConfig;
72 import android.net.NetworkCapabilities;
73 import android.net.NetworkInfo;
74 import android.net.NetworkInfo.DetailedState;
75 import android.net.NetworkProvider;
76 import android.net.NetworkRequest;
77 import android.net.NetworkScore;
78 import android.net.NetworkSpecifier;
79 import android.net.RouteInfo;
80 import android.net.TelephonyNetworkSpecifier;
81 import android.net.TransportInfo;
82 import android.net.UidRangeParcel;
83 import android.net.UnderlyingNetworkInfo;
84 import android.net.Uri;
85 import android.net.VpnManager;
86 import android.net.VpnProfileState;
87 import android.net.VpnService;
88 import android.net.VpnTransportInfo;
89 import android.net.ipsec.ike.ChildSaProposal;
90 import android.net.ipsec.ike.ChildSessionCallback;
91 import android.net.ipsec.ike.ChildSessionConfiguration;
92 import android.net.ipsec.ike.ChildSessionParams;
93 import android.net.ipsec.ike.IkeSession;
94 import android.net.ipsec.ike.IkeSessionCallback;
95 import android.net.ipsec.ike.IkeSessionConfiguration;
96 import android.net.ipsec.ike.IkeSessionConnectionInfo;
97 import android.net.ipsec.ike.IkeSessionParams;
98 import android.net.ipsec.ike.IkeTunnelConnectionParams;
99 import android.net.ipsec.ike.exceptions.IkeIOException;
100 import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
101 import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
102 import android.net.ipsec.ike.exceptions.IkeProtocolException;
103 import android.net.ipsec.ike.exceptions.IkeTimeoutException;
104 import android.net.vcn.VcnGatewayConnectionConfig;
105 import android.net.vcn.VcnTransportInfo;
106 import android.net.vcn.util.MtuUtils;
107 import android.net.vcn.util.PersistableBundleUtils;
108 import android.os.Binder;
109 import android.os.Build.VERSION_CODES;
110 import android.os.Bundle;
111 import android.os.Handler;
112 import android.os.IBinder;
113 import android.os.INetworkManagementService;
114 import android.os.Looper;
115 import android.os.Parcel;
116 import android.os.ParcelFileDescriptor;
117 import android.os.PersistableBundle;
118 import android.os.Process;
119 import android.os.RemoteException;
120 import android.os.SystemClock;
121 import android.os.UserHandle;
122 import android.os.UserManager;
123 import android.provider.Settings;
124 import android.security.Credentials;
125 import android.security.KeyStore2;
126 import android.security.keystore.KeyProperties;
127 import android.system.keystore2.Domain;
128 import android.system.keystore2.KeyDescriptor;
129 import android.system.keystore2.KeyPermission;
130 import android.telephony.CarrierConfigManager;
131 import android.telephony.SubscriptionManager;
132 import android.telephony.TelephonyManager;
133 import android.text.TextUtils;
134 import android.util.ArraySet;
135 import android.util.IndentingPrintWriter;
136 import android.util.LocalLog;
137 import android.util.Log;
138 import android.util.Range;
139 import android.util.SparseArray;
140 
141 import com.android.internal.R;
142 import com.android.internal.annotations.GuardedBy;
143 import com.android.internal.annotations.VisibleForTesting;
144 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
145 import com.android.internal.net.LegacyVpnInfo;
146 import com.android.internal.net.VpnConfig;
147 import com.android.internal.net.VpnProfile;
148 import com.android.net.module.util.BinderUtils;
149 import com.android.net.module.util.LinkPropertiesUtils;
150 import com.android.net.module.util.NetdUtils;
151 import com.android.net.module.util.NetworkStackConstants;
152 import com.android.server.DeviceIdleInternal;
153 import com.android.server.LocalServices;
154 import com.android.server.net.BaseNetworkObserver;
155 
156 import libcore.io.IoUtils;
157 
158 import java.io.FileDescriptor;
159 import java.io.IOException;
160 import java.net.Inet4Address;
161 import java.net.Inet6Address;
162 import java.net.InetAddress;
163 import java.net.NetworkInterface;
164 import java.net.SocketException;
165 import java.net.UnknownHostException;
166 import java.nio.charset.StandardCharsets;
167 import java.security.GeneralSecurityException;
168 import java.security.KeyStore;
169 import java.security.KeyStoreException;
170 import java.security.NoSuchAlgorithmException;
171 import java.security.cert.Certificate;
172 import java.security.cert.CertificateEncodingException;
173 import java.security.cert.CertificateException;
174 import java.util.ArrayList;
175 import java.util.Arrays;
176 import java.util.Collection;
177 import java.util.Collections;
178 import java.util.HashSet;
179 import java.util.List;
180 import java.util.Objects;
181 import java.util.Set;
182 import java.util.SortedSet;
183 import java.util.TreeSet;
184 import java.util.UUID;
185 import java.util.concurrent.Executor;
186 import java.util.concurrent.RejectedExecutionException;
187 import java.util.concurrent.ScheduledFuture;
188 import java.util.concurrent.ScheduledThreadPoolExecutor;
189 import java.util.concurrent.TimeUnit;
190 
191 /**
192  * @hide
193  */
194 public class Vpn {
195     private static final String NETWORKTYPE = "VPN";
196     private static final String TAG = "Vpn";
197     private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
198     private static final boolean LOGD = true;
199     private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
200     /** Key containing prefix of vpn app excluded list */
201     @VisibleForTesting static final String VPN_APP_EXCLUDED = "VPNAPPEXCLUDED_";
202 
203     // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
204     // the device idle allowlist during service launch and VPN bootstrap.
205     private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
206 
207     // Length of time (in milliseconds) that an app registered for VpnManager events is placed on
208     // the device idle allowlist each time the VpnManager event is fired.
209     private static final long VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS = 30 * 1000;
210 
211     private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
212             Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
213 
214     /**
215      * The retries for consecutive failures.
216      *
217      * <p>If retries have exceeded the length of this array, the last entry in the array will be
218      * used as a repeating interval.
219      */
220     private static final long[] IKEV2_VPN_RETRY_DELAYS_MS =
221             {1_000L, 2_000L, 5_000L, 30_000L, 60_000L, 300_000L, 900_000L};
222 
223     /**
224      * A constant to pass to {@link IkeV2VpnRunner#scheduleStartIkeSession(long)} to mean the
225      * delay should be computed automatically with backoff.
226      */
227     private static final long RETRY_DELAY_AUTO_BACKOFF = -1;
228 
229     /**
230      * How long to wait before trying to migrate the IKE connection when NetworkCapabilities or
231      * LinkProperties change in a way that may require migration.
232      *
233      * This delay is useful to avoid multiple migration tries (e.g. when a network changes
234      * both its NC and LP at the same time, e.g. when it first connects) and to minimize the
235      * cases where an old list of addresses is detected for the network.
236      *
237      * In practice, the IKE library reads the LinkProperties of the passed network with
238      * the synchronous {@link ConnectivityManager#getLinkProperties(Network)}, which means in
239      * most cases the race would resolve correctly, but this delay increases the chance that
240      * it correctly is.
241      * Further, using the synchronous method in the IKE library is actually dangerous because
242      * it is racy (it races with {@code IkeNetworkCallbackBase#onLost} and it should be fixed
243      * by using callbacks instead. When that happens, the race within IKE is fixed but the
244      * race between that callback and the one in IkeV2VpnRunner becomes a much bigger problem,
245      * and this delay will be necessary to ensure the correct link address list is used.
246      */
247     private static final long IKE_DELAY_ON_NC_LP_CHANGE_MS = 300;
248 
249     /**
250      * Largest profile size allowable for Platform VPNs.
251      *
252      * <p>The largest platform VPN profiles use IKEv2 RSA Certificate Authentication and have two
253      * X509Certificates, and one RSAPrivateKey. This should lead to a max size of 2x 12kB for the
254      * certificates, plus a reasonable upper bound on the private key of 32kB. The rest of the
255      * profile is expected to be negligible in size.
256      */
257     @VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB
258 
259     /**
260      * Network score that VPNs will announce to ConnectivityService.
261      * TODO: remove when the network scoring refactor lands.
262      */
263     private static final int VPN_DEFAULT_SCORE = 101;
264 
265     /**
266      * The recovery timer for data stall. If a session has not successfully revalidated after
267      * the delay, the session will perform MOBIKE or be restarted in an attempt to recover. Delay
268      * counter is reset on successful validation only.
269      *
270      * <p>The first {@code MOBIKE_RECOVERY_ATTEMPT} timers are used for performing MOBIKE.
271      * System will perform session reset for the remaining timers.
272      * <p>If retries have exceeded the length of this array, the last entry in the array will be
273      * used as a repeating interval.
274      */
275     private static final long[] DATA_STALL_RECOVERY_DELAYS_MS =
276             {1000L, 5000L, 30000L, 60000L, 120000L, 240000L, 480000L, 960000L};
277     /**
278      * Maximum attempts to perform MOBIKE when the network is bad.
279      */
280     private static final int MAX_MOBIKE_RECOVERY_ATTEMPT = 2;
281     /**
282      * The initial token value of IKE session.
283      */
284     private static final int STARTING_TOKEN = -1;
285 
286     // TODO : read this from carrier config instead of a constant
287     @VisibleForTesting
288     public static final int AUTOMATIC_KEEPALIVE_DELAY_SECONDS = 30;
289 
290     // Default keepalive timeout for carrier config is 5 minutes. Mimic this.
291     @VisibleForTesting
292     static final int DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT = 5 * 60;
293 
294     /**
295      * Default keepalive value to consider long-lived TCP connections are expensive on the
296      * VPN network from battery usage point of view.
297      * TODO: consider reading from setting.
298      */
299     @VisibleForTesting
300     static final int DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC = 60;
301 
302     private static final int PREFERRED_IKE_PROTOCOL_UNKNOWN = -1;
303     /**
304      *  Prefer using {@link IkeSessionParams.ESP_IP_VERSION_AUTO} and
305      *  {@link IkeSessionParams.ESP_ENCAP_TYPE_AUTO} for ESP packets.
306      *
307      *  This is one of the possible customization values for
308      *  CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT.
309      */
310     @VisibleForTesting
311     public static final int PREFERRED_IKE_PROTOCOL_AUTO = 0;
312     /**
313      *  Prefer using {@link IkeSessionParams.ESP_IP_VERSION_IPV4} and
314      *  {@link IkeSessionParams.ESP_ENCAP_TYPE_UDP} for ESP packets.
315      *
316      *  This is one of the possible customization values for
317      *  CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT.
318      */
319     @VisibleForTesting
320     public static final int PREFERRED_IKE_PROTOCOL_IPV4_UDP = 40;
321     /**
322      *  Prefer using {@link IkeSessionParams.ESP_IP_VERSION_IPV6} and
323      *  {@link IkeSessionParams.ESP_ENCAP_TYPE_UDP} for ESP packets.
324      *
325      *  Do not use this value for production code. Its numeric value will change in future versions.
326      */
327     @VisibleForTesting
328     public static final int PREFERRED_IKE_PROTOCOL_IPV6_UDP = 60;
329     /**
330      *  Prefer using {@link IkeSessionParams.ESP_IP_VERSION_IPV6} and
331      *  {@link IkeSessionParams.ESP_ENCAP_TYPE_NONE} for ESP packets.
332      *
333      *  This is one of the possible customization values for
334      *  CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT.
335      */
336     @VisibleForTesting
337     public static final int PREFERRED_IKE_PROTOCOL_IPV6_ESP = 61;
338 
339     // TODO: create separate trackers for each unique VPN to support
340     // automated reconnection
341 
342     private final Context mContext;
343     private final ConnectivityManager mConnectivityManager;
344     private final AppOpsManager mAppOpsManager;
345     private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager;
346     private final TelephonyManager mTelephonyManager;
347 
348     // null if FEATURE_TELEPHONY_SUBSCRIPTION is not declared
349     @Nullable
350     private final CarrierConfigManager mCarrierConfigManager;
351 
352     private final SubscriptionManager mSubscriptionManager;
353 
354     // The context is for specific user which is created from mUserId
355     private final Context mUserIdContext;
356     @VisibleForTesting final Dependencies mDeps;
357     private final NetworkInfo mNetworkInfo;
358     @GuardedBy("this")
359     private int mLegacyState;
360     @GuardedBy("this")
361     @VisibleForTesting protected String mPackage;
362     private int mOwnerUID;
363     private boolean mIsPackageTargetingAtLeastQ;
364     @VisibleForTesting
365     protected String mInterface;
366     private Connection mConnection;
367 
368     /** Tracks the runners for all VPN types managed by the platform (eg. LegacyVpn, PlatformVpn) */
369     @VisibleForTesting protected VpnRunner mVpnRunner;
370 
371     private PendingIntent mStatusIntent;
372     private volatile boolean mEnableTeardown = true;
373     private final INetd mNetd;
374     @VisibleForTesting
375     @GuardedBy("this")
376     protected VpnConfig mConfig;
377     private final NetworkProvider mNetworkProvider;
378     @VisibleForTesting
379     protected NetworkAgent mNetworkAgent;
380     private final Looper mLooper;
381     @VisibleForTesting
382     protected NetworkCapabilities mNetworkCapabilities;
383     private final SystemServices mSystemServices;
384     private final Ikev2SessionCreator mIkev2SessionCreator;
385     private final UserManager mUserManager;
386 
387     private final VpnProfileStore mVpnProfileStore;
388 
389     @VisibleForTesting
getVpnProfileStore()390     VpnProfileStore getVpnProfileStore() {
391         return mVpnProfileStore;
392     }
393 
394     private static final int MAX_EVENTS_LOGS = 100;
395     private final LocalLog mEventChanges = new LocalLog(MAX_EVENTS_LOGS);
396 
397     /**
398      * Cached Map of <subscription ID, CarrierConfigInfo> since retrieving the PersistableBundle
399      * and the target value from CarrierConfigManager is somewhat expensive as it has hundreds of
400      * fields. This cache is cleared when the carrier config changes to ensure data freshness.
401      */
402     @GuardedBy("this")
403     private final SparseArray<CarrierConfigInfo> mCachedCarrierConfigInfoPerSubId =
404             new SparseArray<>();
405 
406     /**
407      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
408      * only applies to {@link VpnService} connections.
409      */
410     @GuardedBy("this")
411     @VisibleForTesting protected boolean mAlwaysOn = false;
412 
413     /**
414      * Whether to disable traffic outside of this VPN even when the VPN is not connected. System
415      * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is
416      * not set. Applies to all types of VPNs.
417      */
418     @GuardedBy("this")
419     @VisibleForTesting protected boolean mLockdown = false;
420 
421     /**
422      * Set of packages in addition to the VPN app itself that can access the network directly when
423      * VPN is not connected even if {@code mLockdown} is set.
424      */
425     private @NonNull List<String> mLockdownAllowlist = Collections.emptyList();
426 
427      /**
428      * A memory of what UIDs this class told ConnectivityService to block for the lockdown feature.
429      *
430      * Netd maintains ranges of UIDs for which network should be restricted to using only the VPN
431      * for the lockdown feature. This class manages these UIDs and sends this information to netd.
432      * To avoid sending the same commands multiple times (which would be wasteful) and to be able
433      * to revoke lists (when the rules should change), it's simplest to keep this cache of what
434      * netd knows, so it can be diffed and sent most efficiently.
435      *
436      * The contents of this list must only be changed when updating the UIDs lists with netd,
437      * since it needs to keep in sync with the picture netd has of them.
438      *
439      * @see mLockdown
440      */
441     @GuardedBy("this")
442     private final Set<UidRangeParcel> mBlockedUidsAsToldToConnectivity = new ArraySet<>();
443 
444     // The user id of initiating VPN.
445     private final int mUserId;
446 
447     private static class CarrierConfigInfo {
448         public final String mccMnc;
449         public final int keepaliveDelaySec;
450         public final int encapType;
451         public final int ipVersion;
452 
CarrierConfigInfo(String mccMnc, int keepaliveDelaySec, int encapType, int ipVersion)453         CarrierConfigInfo(String mccMnc, int keepaliveDelaySec,
454                 int encapType,
455                 int ipVersion) {
456             this.mccMnc = mccMnc;
457             this.keepaliveDelaySec = keepaliveDelaySec;
458             this.encapType = encapType;
459             this.ipVersion = ipVersion;
460         }
461 
462         @Override
toString()463         public String toString() {
464             return "CarrierConfigInfo(" + mccMnc + ") [keepaliveDelaySec=" + keepaliveDelaySec
465                     + ", encapType=" + encapType + ", ipVersion=" + ipVersion + "]";
466         }
467     }
468 
469     @VisibleForTesting
470     public static class Dependencies {
isCallerSystem()471         public boolean isCallerSystem() {
472             return Binder.getCallingUid() == Process.SYSTEM_UID;
473         }
474 
getDeviceIdleInternal()475         public DeviceIdleInternal getDeviceIdleInternal() {
476             return LocalServices.getService(DeviceIdleInternal.class);
477         }
478 
getIntentForStatusPanel(Context context)479         public PendingIntent getIntentForStatusPanel(Context context) {
480             return VpnConfig.getIntentForStatusPanel(context);
481         }
482 
483         /**
484          * @see ParcelFileDescriptor#adoptFd(int)
485          */
adoptFd(Vpn vpn, int mtu)486         public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) {
487             return ParcelFileDescriptor.adoptFd(jniCreate(vpn, mtu));
488         }
489 
490         /**
491          * Call native method to create the VPN interface and return the FileDescriptor of /dev/tun.
492          */
jniCreate(Vpn vpn, int mtu)493         public int jniCreate(Vpn vpn, int mtu) {
494             return vpn.jniCreate(mtu);
495         }
496 
497         /**
498          * Call native method to get the interface name of VPN.
499          */
jniGetName(Vpn vpn, int fd)500         public String jniGetName(Vpn vpn, int fd) {
501             return vpn.jniGetName(fd);
502         }
503 
504         /**
505          * Call native method to set the VPN addresses and return the number of addresses.
506          */
jniSetAddresses(Vpn vpn, String interfaze, String addresses)507         public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) {
508             return vpn.jniSetAddresses(interfaze, addresses);
509         }
510 
511         /**
512          * @see IoUtils#setBlocking(FileDescriptor, boolean)
513          */
setBlocking(FileDescriptor fd, boolean blocking)514         public void setBlocking(FileDescriptor fd, boolean blocking) {
515             try {
516                 IoUtils.setBlocking(fd, blocking);
517             } catch (IOException e) {
518                 throw new IllegalStateException(
519                         "Cannot set tunnel's fd as blocking=" + blocking, e);
520             }
521         }
522 
523         /**
524          * Retrieves the next retry delay
525          *
526          * <p>If retries have exceeded the size of IKEV2_VPN_RETRY_DELAYS_MS, the last entry in
527          * the array will be used as a repeating interval.
528          */
getNextRetryDelayMs(int retryCount)529         public long getNextRetryDelayMs(int retryCount) {
530             if (retryCount >= IKEV2_VPN_RETRY_DELAYS_MS.length) {
531                 return IKEV2_VPN_RETRY_DELAYS_MS[IKEV2_VPN_RETRY_DELAYS_MS.length - 1];
532             } else {
533                 return IKEV2_VPN_RETRY_DELAYS_MS[retryCount];
534             }
535         }
536 
537         /** Get single threaded executor for IKEv2 VPN */
newScheduledThreadPoolExecutor()538         public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() {
539             return new ScheduledThreadPoolExecutor(1);
540         }
541 
542         /** Get a NetworkAgent instance */
newNetworkAgent( @onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider, @Nullable ValidationStatusCallback callback)543         public NetworkAgent newNetworkAgent(
544                 @NonNull Context context,
545                 @NonNull Looper looper,
546                 @NonNull String logTag,
547                 @NonNull NetworkCapabilities nc,
548                 @NonNull LinkProperties lp,
549                 @NonNull NetworkScore score,
550                 @NonNull NetworkAgentConfig config,
551                 @Nullable NetworkProvider provider,
552                 @Nullable ValidationStatusCallback callback) {
553             return new VpnNetworkAgentWrapper(
554                     context, looper, logTag, nc, lp, score, config, provider, callback);
555         }
556 
557         /**
558          * Get the length of time to wait before perform data stall recovery when the validation
559          * result is bad.
560          */
getValidationFailRecoveryMs(int count)561         public long getValidationFailRecoveryMs(int count) {
562             if (count >= DATA_STALL_RECOVERY_DELAYS_MS.length) {
563                 return DATA_STALL_RECOVERY_DELAYS_MS[DATA_STALL_RECOVERY_DELAYS_MS.length - 1];
564             } else {
565                 return DATA_STALL_RECOVERY_DELAYS_MS[count];
566             }
567         }
568 
569         /** Gets the MTU of an interface using Java NetworkInterface primitives */
getJavaNetworkInterfaceMtu(@ullable String iface, int defaultValue)570         public int getJavaNetworkInterfaceMtu(@Nullable String iface, int defaultValue)
571                 throws SocketException {
572             if (iface == null) return defaultValue;
573 
574             final NetworkInterface networkInterface = NetworkInterface.getByName(iface);
575             return networkInterface == null ? defaultValue : networkInterface.getMTU();
576         }
577 
578         /** Calculates the VPN Network's max MTU based on underlying network and configuration */
calculateVpnMtu( @onNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu, boolean isIpv4)579         public int calculateVpnMtu(
580                 @NonNull List<ChildSaProposal> childProposals,
581                 int maxMtu,
582                 int underlyingMtu,
583                 boolean isIpv4) {
584             return MtuUtils.getMtu(childProposals, maxMtu, underlyingMtu, isIpv4);
585         }
586 
587         /** Verify the binder calling UID is the one passed in arguments */
verifyCallingUidAndPackage(Context context, String packageName, int userId)588         public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
589             final int callingUid = Binder.getCallingUid();
590             if (getAppUid(context, packageName, userId) != callingUid) {
591                 throw new SecurityException(packageName + " does not belong to uid " + callingUid);
592             }
593         }
594     }
595 
596     @VisibleForTesting
597     interface ValidationStatusCallback {
onValidationStatus(int status)598         void onValidationStatus(int status);
599     }
600 
Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, @UserIdInt int userId, VpnProfileStore vpnProfileStore)601     public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
602             @UserIdInt int userId, VpnProfileStore vpnProfileStore) {
603         this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore,
604                 new SystemServices(context), new Ikev2SessionCreator());
605     }
606 
607     @VisibleForTesting
Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, @UserIdInt int userId, VpnProfileStore vpnProfileStore)608     public Vpn(Looper looper, Context context, Dependencies deps,
609             INetworkManagementService netService, INetd netd, @UserIdInt int userId,
610             VpnProfileStore vpnProfileStore) {
611         this(looper, context, deps, netService, netd, userId, vpnProfileStore,
612                 new SystemServices(context), new Ikev2SessionCreator());
613     }
614 
615     @VisibleForTesting
Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator)616     protected Vpn(Looper looper, Context context, Dependencies deps,
617             INetworkManagementService netService, INetd netd,
618             int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices,
619             Ikev2SessionCreator ikev2SessionCreator) {
620         mVpnProfileStore = vpnProfileStore;
621         mContext = context;
622         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
623         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
624         mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
625         mConnectivityDiagnosticsManager =
626                 mContext.getSystemService(ConnectivityDiagnosticsManager.class);
627         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
628         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
629         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
630 
631         mDeps = deps;
632         mNetd = netd;
633         mUserId = userId;
634         mLooper = looper;
635         mSystemServices = systemServices;
636         mIkev2SessionCreator = ikev2SessionCreator;
637         mUserManager = mContext.getSystemService(UserManager.class);
638 
639         mPackage = VpnConfig.LEGACY_VPN;
640         mOwnerUID = getAppUid(mContext, mPackage, mUserId);
641         mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
642 
643         try {
644             netService.registerObserver(mObserver);
645         } catch (RemoteException e) {
646             Log.wtf(TAG, "Problem registering observer", e);
647         }
648 
649         mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId);
650         // This constructor is called in onUserStart and registers the provider. The provider
651         // will be unregistered in onUserStop.
652         mConnectivityManager.registerNetworkProvider(mNetworkProvider);
653         mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
654         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
655                 "" /* subtypeName */);
656         mNetworkCapabilities = new NetworkCapabilities.Builder()
657                 .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
658                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
659                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
660                 .setTransportInfo(new VpnTransportInfo(
661                         VpnManager.TYPE_VPN_NONE,
662                         null /* sessionId */,
663                         false /* bypassable */,
664                         false /* longLivedTcpConnectionsExpensive */))
665                 .build();
666 
667         loadAlwaysOnPackage();
668     }
669 
670     /**
671      * Set whether this object is responsible for watching for {@link NetworkInfo}
672      * teardown. When {@code false}, teardown is handled externally by someone
673      * else.
674      */
setEnableTeardown(boolean enableTeardown)675     public void setEnableTeardown(boolean enableTeardown) {
676         mEnableTeardown = enableTeardown;
677     }
678 
679     @VisibleForTesting
getEnableTeardown()680     public boolean getEnableTeardown() {
681         return mEnableTeardown;
682     }
683 
684     /**
685      * Update current state, dispatching event to listeners.
686      */
687     @VisibleForTesting
688     @GuardedBy("this")
updateState(DetailedState detailedState, String reason)689     protected void updateState(DetailedState detailedState, String reason) {
690         if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
691         mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
692         mNetworkInfo.setDetailedState(detailedState, reason, null);
693         // TODO : only accept transitions when the agent is in the correct state (non-null for
694         // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED).
695         // This will require a way for tests to pretend the VPN is connected that's not
696         // calling this method with CONNECTED.
697         // It will also require audit of where the code calls this method with DISCONNECTED
698         // with a null agent, which it was doing historically to make sure the agent is
699         // disconnected as this was a no-op if the agent was null.
700         switch (detailedState) {
701             case CONNECTED:
702                 if (null != mNetworkAgent) {
703                     mNetworkAgent.markConnected();
704                 }
705                 break;
706             case DISCONNECTED:
707             case FAILED:
708                 if (null != mNetworkAgent) {
709                     mNetworkAgent.unregister();
710                     mNetworkAgent = null;
711                 }
712                 break;
713             case CONNECTING:
714                 if (null != mNetworkAgent) {
715                     throw new IllegalStateException("VPN can only go to CONNECTING state when"
716                             + " the agent is null.");
717                 }
718                 break;
719             default:
720                 throw new IllegalArgumentException("Illegal state argument " + detailedState);
721         }
722         updateAlwaysOnNotification(detailedState);
723     }
724 
resetNetworkCapabilities()725     private void resetNetworkCapabilities() {
726         mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
727                 .setUids(null)
728                 .setTransportInfo(new VpnTransportInfo(
729                         VpnManager.TYPE_VPN_NONE,
730                         null /* sessionId */,
731                         false /* bypassable */,
732                         false /* longLivedTcpConnectionsExpensive */))
733                 .build();
734     }
735 
736     /**
737      * Chooses whether to force all connections to go through VPN.
738      *
739      * Used to enable/disable legacy VPN lockdown.
740      *
741      * This uses the same ip rule mechanism as
742      * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
743      * that function will be replaced and saved with the always-on state.
744      *
745      * @param lockdown whether to prevent all traffic outside of the VPN.
746      */
setLockdown(boolean lockdown)747     public synchronized void setLockdown(boolean lockdown) {
748         enforceControlPermissionOrInternalCaller();
749 
750         setVpnForcedLocked(lockdown);
751         mLockdown = lockdown;
752 
753         // Update app lockdown setting if it changed. Legacy VPN lockdown status is controlled by
754         // LockdownVpnTracker.isEnabled() which keeps track of its own state.
755         if (mAlwaysOn) {
756             saveAlwaysOnPackage();
757         }
758     }
759 
760     /** Returns the package name that is currently prepared. */
getPackage()761     public synchronized String getPackage() {
762         return mPackage;
763     }
764 
765     /**
766      * Check whether to prevent all traffic outside of a VPN even when the VPN is not connected.
767      *
768      * @return {@code true} if VPN lockdown is enabled.
769      */
getLockdown()770     public synchronized boolean getLockdown() {
771         return mLockdown;
772     }
773 
774     /**
775      * Returns whether VPN is configured as always-on.
776      */
getAlwaysOn()777     public synchronized boolean getAlwaysOn() {
778         return mAlwaysOn;
779     }
780 
781     /**
782      * Checks if a VPN app supports always-on mode.
783      *
784      * <p>In order to support the always-on feature, an app has to either have an installed
785      * PlatformVpnProfile, or:
786      *
787      * <ul>
788      *   <li>target {@link VERSION_CODES#N API 24} or above, and
789      *   <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
790      *       meta-data field.
791      * </ul>
792      *
793      * @param packageName the canonical package name of the VPN app
794      * @return {@code true} if and only if the VPN app exists and supports always-on mode
795      */
isAlwaysOnPackageSupported(String packageName)796     public boolean isAlwaysOnPackageSupported(String packageName) {
797         enforceSettingsPermission();
798 
799         if (packageName == null) {
800             return false;
801         }
802 
803         final long oldId = Binder.clearCallingIdentity();
804         try {
805             if (getVpnProfilePrivileged(packageName) != null) {
806                 return true;
807             }
808         } finally {
809             Binder.restoreCallingIdentity(oldId);
810         }
811 
812         PackageManager pm = mContext.getPackageManager();
813         ApplicationInfo appInfo = null;
814         try {
815             appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
816         } catch (NameNotFoundException unused) {
817             Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support");
818         }
819         if (appInfo == null || appInfo.targetSdkVersion < VERSION_CODES.N) {
820             return false;
821         }
822 
823         final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
824         intent.setPackage(packageName);
825         List<ResolveInfo> services =
826                 pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserId);
827         if (services == null || services.size() == 0) {
828             return false;
829         }
830 
831         for (ResolveInfo rInfo : services) {
832             final Bundle metaData = rInfo.serviceInfo.metaData;
833             if (metaData != null &&
834                     !metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) {
835                 return false;
836             }
837         }
838 
839         return true;
840     }
841 
buildVpnManagerEventIntent(@onNull String category, int errorClass, int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp)842     private Intent buildVpnManagerEventIntent(@NonNull String category, int errorClass,
843             int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
844             @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
845             @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
846         // Add log for debugging flaky test. b/242833779
847         Log.d(TAG, "buildVpnManagerEventIntent: sessionKey = " + sessionKey);
848         final Intent intent = new Intent(VpnManager.ACTION_VPN_MANAGER_EVENT);
849         intent.setPackage(packageName);
850         intent.addCategory(category);
851         intent.putExtra(VpnManager.EXTRA_VPN_PROFILE_STATE, profileState);
852         intent.putExtra(VpnManager.EXTRA_SESSION_KEY, sessionKey);
853         intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK, underlyingNetwork);
854         intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES, nc);
855         intent.putExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES, lp);
856         intent.putExtra(VpnManager.EXTRA_TIMESTAMP_MILLIS, System.currentTimeMillis());
857         if (!VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER.equals(category)
858                 || !VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED.equals(category)) {
859             intent.putExtra(VpnManager.EXTRA_ERROR_CLASS, errorClass);
860             intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode);
861         }
862 
863         return intent;
864     }
865 
sendEventToVpnManagerApp(@onNull String category, int errorClass, int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp)866     private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass,
867             int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
868             @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
869             @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
870         mEventChanges.log("[VMEvent] Event class=" + getVpnManagerEventClassName(errorClass)
871                 + ", err=" + getVpnManagerEventErrorName(errorCode) + " for " + packageName
872                 + " on session " + sessionKey);
873         final Intent intent = buildVpnManagerEventIntent(category, errorClass, errorCode,
874                 packageName, sessionKey, profileState, underlyingNetwork, nc, lp);
875         return sendEventToVpnManagerApp(intent, packageName);
876     }
877 
sendEventToVpnManagerApp(@onNull final Intent intent, @NonNull final String packageName)878     private boolean sendEventToVpnManagerApp(@NonNull final Intent intent,
879             @NonNull final String packageName) {
880         // Allow VpnManager app to temporarily run background services to handle this error.
881         // If an app requires anything beyond this grace period, they MUST either declare
882         // themselves as a foreground service, or schedule a job/workitem.
883         final long token = Binder.clearCallingIdentity();
884         try {
885             final DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
886             idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
887                     VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
888                     "VpnManager event");
889 
890             try {
891                 return mUserIdContext.startService(intent) != null;
892             } catch (RuntimeException e) {
893                 Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e);
894                 return false;
895             }
896         } finally {
897             Binder.restoreCallingIdentity(token);
898         }
899     }
900 
isVpnApp(String packageName)901     private static boolean isVpnApp(String packageName) {
902         return packageName != null && !VpnConfig.LEGACY_VPN.equals(packageName);
903     }
904 
905     /**
906      * Configures an always-on VPN connection through a specific application. This connection is
907      * automatically granted and persisted after a reboot.
908      *
909      * <p>The designated package should either have a PlatformVpnProfile installed, or declare a
910      * {@link VpnService} in its manifest guarded by {@link
911      * android.Manifest.permission.BIND_VPN_SERVICE}, otherwise the call will fail.
912      *
913      * <p>Note that this method does not check if the VPN app supports always-on mode. The check is
914      * delayed to {@link #startAlwaysOnVpn()}, which is always called immediately after this method
915      * in {@link android.net.IConnectivityManager#setAlwaysOnVpnPackage}.
916      *
917      * @param packageName the package to designate as always-on VPN supplier.
918      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
919      * @param lockdownAllowlist packages to be allowed from lockdown.
920      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
921      */
setAlwaysOnPackage( @ullable String packageName, boolean lockdown, @Nullable List<String> lockdownAllowlist)922     public synchronized boolean setAlwaysOnPackage(
923             @Nullable String packageName,
924             boolean lockdown,
925             @Nullable List<String> lockdownAllowlist) {
926         enforceControlPermissionOrInternalCaller();
927         // Store mPackage since it might be reset or might be replaced with the other VPN app.
928         final String oldPackage = mPackage;
929         final boolean isPackageChanged = !Objects.equals(packageName, oldPackage);
930         // Only notify VPN apps that were already always-on, and only if the always-on provider
931         // changed, or the lockdown mode changed.
932         final boolean shouldNotifyOldPkg = isVpnApp(oldPackage) && mAlwaysOn
933                 && (lockdown != mLockdown || isPackageChanged);
934         // Also notify the new package if there was a provider change.
935         final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
936 
937         if (!setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
938             return false;
939         }
940 
941         saveAlwaysOnPackage();
942 
943         if (shouldNotifyOldPkg) {
944             // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the
945             // always-on of old package is disabled or the old package is replaced with the new
946             // package. In this case, VpnProfileState should be disconnected.
947             sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
948                     -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
949                     null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
950                             : makeVpnProfileStateLocked(),
951                     null /* underlyingNetwork */, null /* nc */, null /* lp */);
952         }
953 
954         if (shouldNotifyNewPkg) {
955             sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
956                     -1 /* errorClass */, -1 /* errorCode*/, packageName,
957                     getSessionKeyLocked(), makeVpnProfileStateLocked(),
958                     null /* underlyingNetwork */, null /* nc */, null /* lp */);
959         }
960         return true;
961     }
962 
963     /**
964      * Configures an always-on VPN connection through a specific application, the same as {@link
965      * #setAlwaysOnPackage}.
966      *
967      * <p>Does not perform permission checks. Does not persist any of the changes to storage.
968      *
969      * @param packageName the package to designate as always-on VPN supplier.
970      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
971      * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if
972      *     {@code lockdown} is {@code true}. Packages must not contain commas.
973      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
974      */
975     @GuardedBy("this")
setAlwaysOnPackageInternal( @ullable String packageName, boolean lockdown, @Nullable List<String> lockdownAllowlist)976     private boolean setAlwaysOnPackageInternal(
977             @Nullable String packageName, boolean lockdown,
978             @Nullable List<String> lockdownAllowlist) {
979         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
980             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
981             return false;
982         }
983 
984         if (lockdownAllowlist != null) {
985             for (String pkg : lockdownAllowlist) {
986                 if (pkg.contains(",")) {
987                     Log.w(TAG, "Not setting always-on vpn, invalid allowed package: " + pkg);
988                     return false;
989                 }
990             }
991         }
992 
993         if (packageName != null) {
994             final VpnProfile profile;
995             final long oldId = Binder.clearCallingIdentity();
996             try {
997                 profile = getVpnProfilePrivileged(packageName);
998             } finally {
999                 Binder.restoreCallingIdentity(oldId);
1000             }
1001 
1002             // Pre-authorize new always-on VPN package.
1003             final int grantType =
1004                     (profile == null) ? VpnManager.TYPE_VPN_SERVICE : VpnManager.TYPE_VPN_PLATFORM;
1005             if (!setPackageAuthorization(packageName, grantType)) {
1006                 return false;
1007             }
1008             mAlwaysOn = true;
1009         } else {
1010             packageName = VpnConfig.LEGACY_VPN;
1011             mAlwaysOn = false;
1012         }
1013 
1014         final boolean oldLockdownState = mLockdown;
1015         mLockdown = (mAlwaysOn && lockdown);
1016         mLockdownAllowlist = (mLockdown && lockdownAllowlist != null)
1017                 ? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist))
1018                 : Collections.emptyList();
1019         mEventChanges.log("[LockdownAlwaysOn] Mode changed: lockdown=" + mLockdown + " alwaysOn="
1020                 + mAlwaysOn + " calling from " + Binder.getCallingUid());
1021 
1022         if (isCurrentPreparedPackage(packageName)) {
1023             updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
1024             setVpnForcedLocked(mLockdown);
1025 
1026             // Lockdown forces the VPN to be non-bypassable (see #agentConnect) because it makes
1027             // no sense for a VPN to be bypassable when connected but not when not connected.
1028             // As such, changes in lockdown need to restart the agent.
1029             if (mNetworkAgent != null && oldLockdownState != mLockdown) {
1030                 startNewNetworkAgent(mNetworkAgent, "Lockdown mode changed");
1031             }
1032         } else {
1033             // Prepare this app. The notification will update as a side-effect of updateState().
1034             // It also calls setVpnForcedLocked().
1035             prepareInternal(packageName);
1036         }
1037         return true;
1038     }
1039 
isNullOrLegacyVpn(String packageName)1040     private static boolean isNullOrLegacyVpn(String packageName) {
1041         return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName);
1042     }
1043 
1044     /**
1045      * @return the package name of the VPN controller responsible for always-on VPN,
1046      *         or {@code null} if none is set or always-on VPN is controlled through
1047      *         lockdown instead.
1048      */
getAlwaysOnPackage()1049     public synchronized String getAlwaysOnPackage() {
1050         enforceControlPermissionOrInternalCaller();
1051         return (mAlwaysOn ? mPackage : null);
1052     }
1053 
1054     /**
1055      * @return an immutable list of packages allowed to bypass always-on VPN lockdown.
1056      */
getLockdownAllowlist()1057     public synchronized List<String> getLockdownAllowlist() {
1058         return mLockdown ? mLockdownAllowlist : null;
1059     }
1060 
1061     /**
1062      * Save the always-on package and lockdown config into Settings.Secure
1063      */
1064     @GuardedBy("this")
saveAlwaysOnPackage()1065     private void saveAlwaysOnPackage() {
1066         final long token = Binder.clearCallingIdentity();
1067         try {
1068             mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
1069                     getAlwaysOnPackage(), mUserId);
1070             mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
1071                     (mAlwaysOn && mLockdown ? 1 : 0), mUserId);
1072             mSystemServices.settingsSecurePutStringForUser(
1073                     LOCKDOWN_ALLOWLIST_SETTING_NAME,
1074                     String.join(",", mLockdownAllowlist), mUserId);
1075         } finally {
1076             Binder.restoreCallingIdentity(token);
1077         }
1078     }
1079 
1080     /** Load the always-on package and lockdown config from Settings. */
1081     @GuardedBy("this")
loadAlwaysOnPackage()1082     private void loadAlwaysOnPackage() {
1083         final long token = Binder.clearCallingIdentity();
1084         try {
1085             final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
1086                     Settings.Secure.ALWAYS_ON_VPN_APP, mUserId);
1087             final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
1088                     Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserId) != 0;
1089             final String allowlistString = mSystemServices.settingsSecureGetStringForUser(
1090                     LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserId);
1091             final List<String> allowedPackages = TextUtils.isEmpty(allowlistString)
1092                     ? Collections.emptyList() : Arrays.asList(allowlistString.split(","));
1093             setAlwaysOnPackageInternal(
1094                     alwaysOnPackage, alwaysOnLockdown, allowedPackages);
1095         } finally {
1096             Binder.restoreCallingIdentity(token);
1097         }
1098     }
1099 
1100     /**
1101      * Starts the currently selected always-on VPN
1102      *
1103      * @return {@code true} if the service was started, the service was already connected, or there
1104      *     was no always-on VPN to start. {@code false} otherwise.
1105      */
startAlwaysOnVpn()1106     public boolean startAlwaysOnVpn() {
1107         final String alwaysOnPackage;
1108         synchronized (this) {
1109             alwaysOnPackage = getAlwaysOnPackage();
1110             // Skip if there is no service to start.
1111             if (alwaysOnPackage == null) {
1112                 return true;
1113             }
1114             // Remove always-on VPN if it's not supported.
1115             if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
1116                 // Do not remove the always-on setting due to the restricted ability in safe mode.
1117                 // The always-on VPN can then start after the device reboots to normal mode.
1118                 if (!mContext.getPackageManager().isSafeMode()) {
1119                     setAlwaysOnPackage(null, false, null);
1120                 }
1121                 return false;
1122             }
1123             // Skip if the service is already established. This isn't bulletproof: it's not bound
1124             // until after establish(), so if it's mid-setup onStartCommand will be sent twice,
1125             // which may restart the connection.
1126             if (getNetworkInfo().isConnected()) {
1127                 return true;
1128             }
1129         }
1130 
1131         final long oldId = Binder.clearCallingIdentity();
1132         try {
1133             // Prefer VPN profiles, if any exist.
1134             VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage);
1135             if (profile != null) {
1136                 startVpnProfilePrivileged(profile, alwaysOnPackage);
1137                 // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was
1138                 // correctly parsed, and the VPN has started running in a different thread. The only
1139                 // other possibility is that the above call threw an exception, which will be
1140                 // caught below, and returns false (clearing the always-on VPN). Once started, the
1141                 // Platform VPN cannot permanently fail, and is resilient to temporary failures. It
1142                 // will continue retrying until shut down by the user, or always-on is toggled off.
1143                 return true;
1144             }
1145 
1146             // Tell the OS that background services in this app need to be allowed for
1147             // a short time, so we can bootstrap the VPN service.
1148             DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
1149             idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
1150                     VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
1151                     "vpn");
1152 
1153             // Start the VPN service declared in the app's manifest.
1154             Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
1155             serviceIntent.setPackage(alwaysOnPackage);
1156             try {
1157                 return mUserIdContext.startService(serviceIntent) != null;
1158             } catch (RuntimeException e) {
1159                 Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
1160                 return false;
1161             }
1162         } catch (Exception e) {
1163             Log.e(TAG, "Error starting always-on VPN", e);
1164             return false;
1165         } finally {
1166             Binder.restoreCallingIdentity(oldId);
1167         }
1168     }
1169 
1170     /**
1171      * Prepare for a VPN application. This method is designed to solve
1172      * race conditions. It first compares the current prepared package
1173      * with {@code oldPackage}. If they are the same, the prepared
1174      * package is revoked and replaced with {@code newPackage}. If
1175      * {@code oldPackage} is {@code null}, the comparison is omitted.
1176      * If {@code newPackage} is the same package or {@code null}, the
1177      * revocation is omitted. This method returns {@code true} if the
1178      * operation is succeeded.
1179      *
1180      * Legacy VPN is handled specially since it is not a real package.
1181      * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
1182      * it can be revoked by itself.
1183      *
1184      * The permission checks to verify that the VPN has already been granted
1185      * user consent are dependent on the type of the VPN being prepared. See
1186      * {@link AppOpsManager#OP_ACTIVATE_VPN} and {@link
1187      * AppOpsManager#OP_ACTIVATE_PLATFORM_VPN} for more information.
1188      *
1189      * Note: when we added VPN pre-consent in
1190      * https://android.googlesource.com/platform/frameworks/base/+/0554260
1191      * the names oldPackage and newPackage became misleading, because when
1192      * an app is pre-consented, we actually prepare oldPackage, not newPackage.
1193      *
1194      * Their meanings actually are:
1195      *
1196      * - oldPackage non-null, newPackage null: App calling VpnService#prepare().
1197      * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
1198      * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
1199      *   and revoke any current app VPN and re-prepare legacy vpn.
1200      * - oldPackage null, newPackage null: always returns true for backward compatibility.
1201      *
1202      * TODO: Rename the variables - or split this method into two - and end this confusion.
1203      * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
1204      * to prepare(oldPackage=null, newPackage=LEGACY_VPN)
1205      *
1206      * @param oldPackage The package name of the old VPN application
1207      * @param newPackage The package name of the new VPN application
1208      * @param vpnType The type of VPN being prepared. One of {@link VpnManager.VpnType} Preparing a
1209      *     platform VPN profile requires only the lesser ACTIVATE_PLATFORM_VPN appop.
1210      * @return true if the operation succeeded.
1211      */
prepare( String oldPackage, String newPackage, @VpnManager.VpnType int vpnType)1212     public synchronized boolean prepare(
1213             String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) {
1214         // Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or
1215         // newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner.
1216         // See b/191382886.
1217         if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) {
1218             if (oldPackage != null) {
1219                 verifyCallingUidAndPackage(oldPackage);
1220             }
1221             if (newPackage != null) {
1222                 verifyCallingUidAndPackage(newPackage);
1223             }
1224         }
1225 
1226         if (oldPackage != null) {
1227             // Stop an existing always-on VPN from being dethroned by other apps.
1228             if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
1229                 return false;
1230             }
1231 
1232             // Package is not the same or old package was reinstalled.
1233             if (!isCurrentPreparedPackage(oldPackage)) {
1234                 // The package doesn't match. We return false (to obtain user consent) unless the
1235                 // user has already consented to that VPN package.
1236                 if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
1237                         && isVpnPreConsented(mContext, oldPackage, vpnType)) {
1238                     prepareInternal(oldPackage);
1239                     return true;
1240                 }
1241                 return false;
1242             } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
1243                     && !isVpnPreConsented(mContext, oldPackage, vpnType)) {
1244                 // Currently prepared VPN is revoked, so unprepare it and return false.
1245                 prepareInternal(VpnConfig.LEGACY_VPN);
1246                 return false;
1247             }
1248         }
1249 
1250         // Return true if we do not need to revoke.
1251         if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
1252                 isCurrentPreparedPackage(newPackage))) {
1253             return true;
1254         }
1255 
1256         // Check that the caller is authorized.
1257         enforceControlPermissionOrInternalCaller();
1258 
1259         // Stop an existing always-on VPN from being dethroned by other apps.
1260         if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) {
1261             return false;
1262         }
1263 
1264         prepareInternal(newPackage);
1265         return true;
1266     }
1267 
1268     @GuardedBy("this")
isCurrentPreparedPackage(String packageName)1269     private boolean isCurrentPreparedPackage(String packageName) {
1270         // We can't just check that packageName matches mPackage, because if the app was uninstalled
1271         // and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
1272         // calling package may not be the same as the prepared package. Check both UID and package.
1273         return getAppUid(mContext, packageName, mUserId) == mOwnerUID
1274                 && mPackage.equals(packageName);
1275     }
1276 
1277     /** Prepare the VPN for the given package. Does not perform permission checks. */
1278     @GuardedBy("this")
prepareInternal(String newPackage)1279     private void prepareInternal(String newPackage) {
1280         final long token = Binder.clearCallingIdentity();
1281         try {
1282             // Reset the interface.
1283             if (mInterface != null) {
1284                 mStatusIntent = null;
1285                 agentDisconnect();
1286                 jniReset(mInterface);
1287                 mInterface = null;
1288                 resetNetworkCapabilities();
1289             }
1290 
1291             // Revoke the connection or stop the VpnRunner.
1292             if (mConnection != null) {
1293                 try {
1294                     mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
1295                             Parcel.obtain(), null, IBinder.FLAG_ONEWAY);
1296                 } catch (Exception e) {
1297                     // ignore
1298                 }
1299                 mAppOpsManager.finishOp(
1300                         AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null);
1301                 mContext.unbindService(mConnection);
1302                 cleanupVpnStateLocked();
1303             } else if (mVpnRunner != null) {
1304                 stopVpnRunnerAndNotifyAppLocked();
1305             }
1306 
1307             try {
1308                 mNetd.networkSetProtectDeny(mOwnerUID);
1309             } catch (Exception e) {
1310                 Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
1311             }
1312 
1313             Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
1314             mPackage = newPackage;
1315             mOwnerUID = getAppUid(mContext, newPackage, mUserId);
1316             mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
1317             try {
1318                 mNetd.networkSetProtectAllow(mOwnerUID);
1319             } catch (Exception e) {
1320                 Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
1321             }
1322             mConfig = null;
1323 
1324             updateState(DetailedState.DISCONNECTED, "prepare");
1325             setVpnForcedLocked(mLockdown);
1326         } finally {
1327             Binder.restoreCallingIdentity(token);
1328         }
1329     }
1330 
1331     /** Set whether a package has the ability to launch VPNs without user intervention. */
setPackageAuthorization(String packageName, @VpnManager.VpnType int vpnType)1332     public boolean setPackageAuthorization(String packageName, @VpnManager.VpnType int vpnType) {
1333         // Check if the caller is authorized.
1334         enforceControlPermissionOrInternalCaller();
1335 
1336         final int uid = getAppUid(mContext, packageName, mUserId);
1337         if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
1338             // Authorization for nonexistent packages (or fake ones) can't be updated.
1339             return false;
1340         }
1341 
1342         final long token = Binder.clearCallingIdentity();
1343         try {
1344             final String[] toChange;
1345 
1346             // Clear all AppOps if the app is being unauthorized.
1347             switch (vpnType) {
1348                 case VpnManager.TYPE_VPN_NONE:
1349                     toChange = new String[] {
1350                             AppOpsManager.OPSTR_ACTIVATE_VPN,
1351                             AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN
1352                     };
1353                     break;
1354                 case VpnManager.TYPE_VPN_PLATFORM:
1355                     toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN};
1356                     break;
1357                 case VpnManager.TYPE_VPN_SERVICE:
1358                     toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
1359                     break;
1360                 case VpnManager.TYPE_VPN_LEGACY:
1361                     return false;
1362                 default:
1363                     Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
1364                     return false;
1365             }
1366 
1367             for (final String appOpStr : toChange) {
1368                 mAppOpsManager.setMode(
1369                         appOpStr,
1370                         uid,
1371                         packageName,
1372                         vpnType == VpnManager.TYPE_VPN_NONE
1373                                 ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED);
1374             }
1375             return true;
1376         } catch (Exception e) {
1377             Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
1378         } finally {
1379             Binder.restoreCallingIdentity(token);
1380         }
1381         return false;
1382     }
1383 
isVpnPreConsented(Context context, String packageName, int vpnType)1384     private static boolean isVpnPreConsented(Context context, String packageName, int vpnType) {
1385         switch (vpnType) {
1386             case VpnManager.TYPE_VPN_SERVICE:
1387                 return isVpnServicePreConsented(context, packageName);
1388             case VpnManager.TYPE_VPN_PLATFORM:
1389                 return isVpnProfilePreConsented(context, packageName);
1390             case VpnManager.TYPE_VPN_LEGACY:
1391                 return VpnConfig.LEGACY_VPN.equals(packageName);
1392             default:
1393                 return false;
1394         }
1395     }
1396 
doesPackageHaveAppop(Context context, String packageName, String appOpStr)1397     private static boolean doesPackageHaveAppop(Context context, String packageName,
1398             String appOpStr) {
1399         final AppOpsManager appOps =
1400                 (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
1401 
1402         // Verify that the caller matches the given package and has the required permission.
1403         return appOps.noteOpNoThrow(appOpStr, Binder.getCallingUid(), packageName,
1404                 null /* attributionTag */, null /* message */) == AppOpsManager.MODE_ALLOWED;
1405     }
1406 
isVpnServicePreConsented(Context context, String packageName)1407     private static boolean isVpnServicePreConsented(Context context, String packageName) {
1408         return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_VPN);
1409     }
1410 
isVpnProfilePreConsented(Context context, String packageName)1411     private static boolean isVpnProfilePreConsented(Context context, String packageName) {
1412         return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN)
1413                 || isVpnServicePreConsented(context, packageName);
1414     }
1415 
getAppUid(final Context context, final String app, final int userId)1416     private static int getAppUid(final Context context, final String app, final int userId) {
1417         if (VpnConfig.LEGACY_VPN.equals(app)) {
1418             return Process.myUid();
1419         }
1420         PackageManager pm = context.getPackageManager();
1421         final long token = Binder.clearCallingIdentity();
1422         try {
1423             return pm.getPackageUidAsUser(app, userId);
1424         } catch (NameNotFoundException e) {
1425             return -1;
1426         } finally {
1427             Binder.restoreCallingIdentity(token);
1428         }
1429     }
1430 
doesPackageTargetAtLeastQ(String packageName)1431     private boolean doesPackageTargetAtLeastQ(String packageName) {
1432         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
1433             return true;
1434         }
1435         PackageManager pm = mContext.getPackageManager();
1436         try {
1437             ApplicationInfo appInfo =
1438                     pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
1439             return appInfo.targetSdkVersion >= VERSION_CODES.Q;
1440         } catch (NameNotFoundException unused) {
1441             Log.w(TAG, "Can't find \"" + packageName + "\"");
1442             return false;
1443         }
1444     }
1445 
getNetworkInfo()1446     public NetworkInfo getNetworkInfo() {
1447         return mNetworkInfo;
1448     }
1449 
1450     /**
1451      * Return Network of current running VPN network.
1452      *
1453      * @return a Network if there is a running VPN network or null if there is no running VPN
1454      *         network or network is null.
1455      */
1456     @VisibleForTesting
1457     @Nullable
getNetwork()1458     public synchronized Network getNetwork() {
1459         final NetworkAgent agent = mNetworkAgent;
1460         if (null == agent) return null;
1461         final Network network = agent.getNetwork();
1462         if (null == network) return null;
1463         return network;
1464     }
1465 
1466     // TODO : this is not synchronized(this) but reads from mConfig, which is dangerous
1467     // This file makes an effort to avoid partly initializing mConfig, but this is still not great
makeLinkProperties()1468     private LinkProperties makeLinkProperties() {
1469         // The design of disabling IPv6 is only enabled for IKEv2 VPN because it needs additional
1470         // logic to handle IPv6 only VPN, and the IPv6 only VPN may be restarted when its MTU
1471         // is lower than 1280. The logic is controlled by IKEv2VpnRunner, so the design is only
1472         // enabled for IKEv2 VPN.
1473         final boolean disableIPV6 = (isIkev2VpnRunner() && mConfig.mtu < IPV6_MIN_MTU);
1474         boolean allowIPv4 = mConfig.allowIPv4;
1475         boolean allowIPv6 = mConfig.allowIPv6;
1476 
1477         LinkProperties lp = new LinkProperties();
1478 
1479         lp.setInterfaceName(mInterface);
1480 
1481         if (mConfig.addresses != null) {
1482             for (LinkAddress address : mConfig.addresses) {
1483                 if (disableIPV6 && address.isIpv6()) continue;
1484                 lp.addLinkAddress(address);
1485                 allowIPv4 |= address.getAddress() instanceof Inet4Address;
1486                 allowIPv6 |= address.getAddress() instanceof Inet6Address;
1487             }
1488         }
1489 
1490         if (mConfig.routes != null) {
1491             for (RouteInfo route : mConfig.routes) {
1492                 final InetAddress address = route.getDestination().getAddress();
1493                 if (disableIPV6 && address instanceof Inet6Address) continue;
1494                 lp.addRoute(route);
1495 
1496                 if (route.getType() == RouteInfo.RTN_UNICAST) {
1497                     allowIPv4 |= address instanceof Inet4Address;
1498                     allowIPv6 |= address instanceof Inet6Address;
1499                 }
1500             }
1501         }
1502 
1503         if (mConfig.dnsServers != null) {
1504             for (String dnsServer : mConfig.dnsServers) {
1505                 final InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
1506                 if (disableIPV6 && address instanceof Inet6Address) continue;
1507                 lp.addDnsServer(address);
1508                 allowIPv4 |= address instanceof Inet4Address;
1509                 allowIPv6 |= address instanceof Inet6Address;
1510             }
1511         }
1512 
1513         lp.setHttpProxy(mConfig.proxyInfo);
1514 
1515         if (!allowIPv4) {
1516             lp.addRoute(new RouteInfo(new IpPrefix(
1517                     NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/,
1518                     null /*iface*/, RTN_UNREACHABLE));
1519         }
1520         if (!allowIPv6 || disableIPV6) {
1521             lp.addRoute(new RouteInfo(new IpPrefix(
1522                     NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/,
1523                     null /*iface*/, RTN_UNREACHABLE));
1524         }
1525 
1526         // Concatenate search domains into a string.
1527         StringBuilder buffer = new StringBuilder();
1528         if (mConfig.searchDomains != null) {
1529             for (String domain : mConfig.searchDomains) {
1530                 buffer.append(domain).append(' ');
1531             }
1532         }
1533         lp.setDomains(buffer.toString().trim());
1534 
1535         if (mConfig.mtu > 0) {
1536             lp.setMtu(mConfig.mtu);
1537         }
1538 
1539         // TODO: Stop setting the MTU in jniCreate
1540 
1541         return lp;
1542     }
1543 
1544     /**
1545      * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
1546      * registering a new NetworkAgent. This is not always possible if the new VPN configuration
1547      * has certain changes, in which case this method would just return {@code false}.
1548      */
1549     // TODO : this method is not synchronized(this) but reads from mConfig
updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig)1550     private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
1551         // NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
1552         // Strictly speaking, bypassability is affected by lockdown and therefore it's possible
1553         // it doesn't actually change even if mConfig.allowBypass changed. It might be theoretically
1554         // possible to do handover in this case, but this is far from obvious to VPN authors and
1555         // it's simpler if the rule is just "can't update in place if you change allow bypass".
1556         if (oldConfig.allowBypass != mConfig.allowBypass) {
1557             Log.i(TAG, "Handover not possible due to changes to allowBypass");
1558             return false;
1559         }
1560 
1561         // TODO: we currently do not support seamless handover if the allowed or disallowed
1562         // applications have changed. Consider diffing UID ranges and only applying the delta.
1563         if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) ||
1564                 !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) {
1565             Log.i(TAG, "Handover not possible due to changes to allowed/denied apps");
1566             return false;
1567         }
1568 
1569         agent.sendLinkProperties(makeLinkProperties());
1570         return true;
1571     }
1572 
1573     @GuardedBy("this")
agentConnect()1574     private void agentConnect() {
1575         agentConnect(null /* validationCallback */);
1576     }
1577 
1578     @GuardedBy("this")
agentConnect(@ullable ValidationStatusCallback validationCallback)1579     private void agentConnect(@Nullable ValidationStatusCallback validationCallback) {
1580         LinkProperties lp = makeLinkProperties();
1581 
1582         // VPN either provide a default route (IPv4 or IPv6 or both), or they are a split tunnel
1583         // that falls back to the default network, which by definition provides INTERNET (unless
1584         // there is no default network, in which case none of this matters in any sense).
1585         // Also, always setting the INTERNET bit guarantees that when a VPN applies to an app,
1586         // the VPN will always be reported as the network by getDefaultNetwork and callbacks
1587         // registered with registerDefaultNetworkCallback. This in turn protects the invariant
1588         // that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork())
1589         // behaves the same as when it uses the default network.
1590         final NetworkCapabilities.Builder capsBuilder =
1591                 new NetworkCapabilities.Builder(mNetworkCapabilities);
1592         capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
1593 
1594         mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
1595         updateState(DetailedState.CONNECTING, "agentConnect");
1596 
1597         final boolean bypassable = mConfig.allowBypass && !mLockdown;
1598         final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder()
1599                 .setLegacyType(ConnectivityManager.TYPE_VPN)
1600                 .setLegacyTypeName("VPN")
1601                 .setBypassableVpn(bypassable)
1602                 .setVpnRequiresValidation(mConfig.requiresInternetValidation)
1603                 .setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes)
1604                 .setLegacyExtraInfo("VPN:" + mPackage)
1605                 .build();
1606 
1607         capsBuilder.setOwnerUid(mOwnerUID);
1608         capsBuilder.setAdministratorUids(new int[] {mOwnerUID});
1609         capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
1610                 mConfig.allowedApplications, mConfig.disallowedApplications));
1611 
1612         final boolean expensive = areLongLivedTcpConnectionsExpensive(mVpnRunner);
1613         capsBuilder.setTransportInfo(new VpnTransportInfo(
1614                 getActiveVpnType(),
1615                 mConfig.session,
1616                 bypassable,
1617                 expensive));
1618 
1619         // Only apps targeting Q and above can explicitly declare themselves as metered.
1620         // These VPNs are assumed metered unless they state otherwise.
1621         if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
1622             capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
1623         } else {
1624             capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
1625         }
1626 
1627         capsBuilder.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
1628                 ? Arrays.asList(mConfig.underlyingNetworks) : null);
1629 
1630         mNetworkCapabilities = capsBuilder.build();
1631         logUnderlyNetworkChanges(mNetworkCapabilities.getUnderlyingNetworks());
1632         mNetworkAgent = mDeps.newNetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
1633                 mNetworkCapabilities, lp,
1634                 new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
1635                 networkAgentConfig, mNetworkProvider, validationCallback);
1636         final long token = Binder.clearCallingIdentity();
1637         try {
1638             mNetworkAgent.register();
1639         } catch (final Exception e) {
1640             // If register() throws, don't keep an unregistered agent.
1641             mNetworkAgent = null;
1642             throw e;
1643         } finally {
1644             Binder.restoreCallingIdentity(token);
1645         }
1646         updateState(DetailedState.CONNECTED, "agentConnect");
1647         if (isIkev2VpnRunner()) {
1648             final IkeSessionWrapper session = ((IkeV2VpnRunner) mVpnRunner).mSession;
1649             if (null != session) session.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
1650         }
1651     }
1652 
areLongLivedTcpConnectionsExpensive(@onNull VpnRunner runner)1653     private static boolean areLongLivedTcpConnectionsExpensive(@NonNull VpnRunner runner) {
1654         if (!(runner instanceof IkeV2VpnRunner)) return false;
1655 
1656         final int delay = ((IkeV2VpnRunner) runner).getOrGuessKeepaliveDelaySeconds();
1657         return areLongLivedTcpConnectionsExpensive(delay);
1658     }
1659 
areLongLivedTcpConnectionsExpensive(int keepaliveDelaySec)1660     private static boolean areLongLivedTcpConnectionsExpensive(int keepaliveDelaySec) {
1661         return keepaliveDelaySec < DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC;
1662     }
1663 
canHaveRestrictedProfile(int userId)1664     private boolean canHaveRestrictedProfile(int userId) {
1665         final long token = Binder.clearCallingIdentity();
1666         try {
1667             final Context userContext = mContext.createContextAsUser(UserHandle.of(userId), 0);
1668             return userContext.getSystemService(UserManager.class).canHaveRestrictedProfile();
1669         } finally {
1670             Binder.restoreCallingIdentity(token);
1671         }
1672     }
1673 
logUnderlyNetworkChanges(List<Network> networks)1674     private void logUnderlyNetworkChanges(List<Network> networks) {
1675         mEventChanges.log("[UnderlyingNW] Switch to "
1676                 + ((networks != null) ? TextUtils.join(", ", networks) : "null"));
1677     }
1678 
agentDisconnect(NetworkAgent networkAgent)1679     private void agentDisconnect(NetworkAgent networkAgent) {
1680         if (networkAgent != null) {
1681             networkAgent.unregister();
1682         }
1683     }
1684 
agentDisconnect()1685     private void agentDisconnect() {
1686         updateState(DetailedState.DISCONNECTED, "agentDisconnect");
1687     }
1688 
1689     @GuardedBy("this")
startNewNetworkAgent(NetworkAgent oldNetworkAgent, String reason)1690     private void startNewNetworkAgent(NetworkAgent oldNetworkAgent, String reason) {
1691         // Initialize the state for a new agent, while keeping the old one connected
1692         // in case this new connection fails.
1693         mNetworkAgent = null;
1694         updateState(DetailedState.CONNECTING, reason);
1695         // Bringing up a new NetworkAgent to prevent the data leakage before tearing down the old
1696         // NetworkAgent.
1697         agentConnect();
1698         agentDisconnect(oldNetworkAgent);
1699     }
1700 
1701     /**
1702      * Establish a VPN network and return the file descriptor of the VPN interface. This methods
1703      * returns {@code null} if the application is revoked or not prepared.
1704      *
1705      * <p>This method supports ONLY VpnService-based VPNs. For Platform VPNs, see {@link
1706      * provisionVpnProfile} and {@link startVpnProfile}
1707      *
1708      * @param config The parameters to configure the network.
1709      * @return The file descriptor of the VPN interface.
1710      */
establish(VpnConfig config)1711     public synchronized ParcelFileDescriptor establish(VpnConfig config) {
1712         // Check if the caller is already prepared.
1713         if (Binder.getCallingUid() != mOwnerUID) {
1714             return null;
1715         }
1716         // Check to ensure consent hasn't been revoked since we were prepared.
1717         if (!isVpnServicePreConsented(mContext, mPackage)) {
1718             return null;
1719         }
1720         // Check if the service is properly declared.
1721         Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
1722         intent.setClassName(mPackage, config.user);
1723         final long token = Binder.clearCallingIdentity();
1724         try {
1725             // Restricted users are not allowed to create VPNs, they are tied to Owner
1726             enforceNotRestrictedUser();
1727 
1728             final PackageManager packageManager = mUserIdContext.getPackageManager();
1729             if (packageManager == null) {
1730                 throw new IllegalStateException("Cannot get PackageManager.");
1731             }
1732             final ResolveInfo info = packageManager.resolveService(intent, 0 /* flags */);
1733             if (info == null) {
1734                 throw new SecurityException("Cannot find " + config.user);
1735             }
1736             if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
1737                 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
1738             }
1739         } finally {
1740             Binder.restoreCallingIdentity(token);
1741         }
1742 
1743         // Save the old config in case we need to go back.
1744         VpnConfig oldConfig = mConfig;
1745         String oldInterface = mInterface;
1746         Connection oldConnection = mConnection;
1747         NetworkAgent oldNetworkAgent = mNetworkAgent;
1748         Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();
1749 
1750         // Configure the interface. Abort if any of these steps fails.
1751         final ParcelFileDescriptor tun = mDeps.adoptFd(this, config.mtu);
1752         try {
1753             final String interfaze = mDeps.jniGetName(this, tun.getFd());
1754 
1755             // TEMP use the old jni calls until there is support for netd address setting
1756             StringBuilder builder = new StringBuilder();
1757             for (LinkAddress address : config.addresses) {
1758                 builder.append(" ");
1759                 builder.append(address);
1760             }
1761             if (mDeps.jniSetAddresses(this, interfaze, builder.toString()) < 1) {
1762                 throw new IllegalArgumentException("At least one address must be specified");
1763             }
1764             Connection connection = new Connection();
1765             if (!mContext.bindServiceAsUser(intent, connection,
1766                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
1767                     new UserHandle(mUserId))) {
1768                 throw new IllegalStateException("Cannot bind " + config.user);
1769             }
1770 
1771             mConnection = connection;
1772             mInterface = interfaze;
1773 
1774             // Fill more values.
1775             config.user = mPackage;
1776             config.interfaze = mInterface;
1777             config.startTime = SystemClock.elapsedRealtime();
1778             mConfig = config;
1779 
1780             // Set up forwarding and DNS rules.
1781             // First attempt to do a seamless handover that only changes the interface name and
1782             // parameters. If that fails, disconnect.
1783             if (oldConfig != null
1784                     && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
1785                 // Update underlying networks if it is changed.
1786                 if (!Arrays.equals(oldConfig.underlyingNetworks, config.underlyingNetworks)) {
1787                     setUnderlyingNetworks(config.underlyingNetworks);
1788                 }
1789             } else {
1790                 startNewNetworkAgent(oldNetworkAgent, "establish");
1791             }
1792 
1793             if (oldConnection != null) {
1794                 mContext.unbindService(oldConnection);
1795             }
1796 
1797             if (oldInterface != null && !oldInterface.equals(interfaze)) {
1798                 jniReset(oldInterface);
1799             }
1800 
1801             mDeps.setBlocking(tun.getFileDescriptor(), config.blocking);
1802             // Record that the VPN connection is established by an app which uses VpnService API.
1803             if (oldNetworkAgent != mNetworkAgent) {
1804                 mAppOpsManager.startOp(
1805                         AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null, null);
1806             }
1807         } catch (RuntimeException e) {
1808             IoUtils.closeQuietly(tun);
1809             // If this is not seamless handover, disconnect partially-established network when error
1810             // occurs.
1811             if (oldNetworkAgent != mNetworkAgent) {
1812                 agentDisconnect();
1813             }
1814             // restore old state
1815             mConfig = oldConfig;
1816             mConnection = oldConnection;
1817             mNetworkCapabilities =
1818                     new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build();
1819             mNetworkAgent = oldNetworkAgent;
1820             mInterface = oldInterface;
1821             throw e;
1822         }
1823         Log.i(TAG, "Established by " + config.user + " on " + mInterface);
1824         return tun;
1825     }
1826 
isRunningLocked()1827     private boolean isRunningLocked() {
1828         return mNetworkAgent != null && mInterface != null;
1829     }
1830 
1831     // Returns true if the VPN has been established and the calling UID is its owner. Used to check
1832     // that a call to mutate VPN state is admissible.
1833     @VisibleForTesting
isCallerEstablishedOwnerLocked()1834     protected boolean isCallerEstablishedOwnerLocked() {
1835         return isRunningLocked() && Binder.getCallingUid() == mOwnerUID;
1836     }
1837 
1838     // Note: Return type guarantees results are deduped and sorted, which callers require.
1839     // This method also adds the SDK sandbox UIDs corresponding to the applications by default,
1840     // since apps are generally not aware of them, yet they should follow the VPN configuration
1841     // of the app they belong to.
getAppsUids(List<String> packageNames, int userId)1842     private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
1843         SortedSet<Integer> uids = new TreeSet<>();
1844         for (String app : packageNames) {
1845             int uid = getAppUid(mContext, app, userId);
1846             if (uid != -1) uids.add(uid);
1847             if (Process.isApplicationUid(uid)) {
1848                 uids.add(Process.toSdkSandboxUid(uid));
1849             }
1850         }
1851         return uids;
1852     }
1853 
1854     /**
1855      * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs
1856      * associated with one user, and any restricted profiles attached to that user.
1857      *
1858      * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
1859      * the UID ranges will match the app list specified there. Otherwise, all UIDs
1860      * in each user and profile will be included.
1861      *
1862      * @param userId The userId to create UID ranges for along with any of its restricted
1863      *                   profiles.
1864      * @param allowedApplications (optional) List of applications to allow.
1865      * @param disallowedApplications (optional) List of applications to deny.
1866      */
1867     @VisibleForTesting
createUserAndRestrictedProfilesRanges(@serIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications)1868     Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
1869             @Nullable List<String> allowedApplications,
1870             @Nullable List<String> disallowedApplications) {
1871         final Set<Range<Integer>> ranges = new ArraySet<>();
1872 
1873         // Assign the top-level user to the set of ranges
1874         addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
1875 
1876         // If the user can have restricted profiles, assign all its restricted profiles too
1877         if (canHaveRestrictedProfile(userId)) {
1878             final long token = Binder.clearCallingIdentity();
1879             List<UserInfo> users;
1880             try {
1881                 users = mUserManager.getAliveUsers();
1882             } finally {
1883                 Binder.restoreCallingIdentity(token);
1884             }
1885             for (UserInfo user : users) {
1886                 if (user.isRestricted() && (user.restrictedProfileParentId == userId)) {
1887                     addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
1888                 }
1889             }
1890         }
1891         return ranges;
1892     }
1893 
1894     /**
1895      * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs
1896      * associated with one user.
1897      *
1898      * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
1899      * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs
1900      * in the user will be included.
1901      *
1902      * @param ranges {@link Set} of {@code Range<Integer>}s to which to add.
1903      * @param userId The userId to add to {@param ranges}.
1904      * @param allowedApplications (optional) allowlist of applications to include.
1905      * @param disallowedApplications (optional) denylist of applications to exclude.
1906      */
1907     @VisibleForTesting
addUserToRanges(@onNull Set<Range<Integer>> ranges, @UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications)1908     void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId,
1909             @Nullable List<String> allowedApplications,
1910             @Nullable List<String> disallowedApplications) {
1911         if (allowedApplications != null) {
1912             // Add ranges covering all UIDs for allowedApplications.
1913             int start = -1, stop = -1;
1914             for (int uid : getAppsUids(allowedApplications, userId)) {
1915                 if (start == -1) {
1916                     start = uid;
1917                 } else if (uid != stop + 1) {
1918                     ranges.add(new Range<Integer>(start, stop));
1919                     start = uid;
1920                 }
1921                 stop = uid;
1922             }
1923             if (start != -1) ranges.add(new Range<Integer>(start, stop));
1924         } else if (disallowedApplications != null) {
1925             // Add all ranges for user skipping UIDs for disallowedApplications.
1926             final Range<Integer> userRange = createUidRangeForUser(userId);
1927             int start = userRange.getLower();
1928             for (int uid : getAppsUids(disallowedApplications, userId)) {
1929                 if (uid == start) {
1930                     start++;
1931                 } else {
1932                     ranges.add(new Range<Integer>(start, uid - 1));
1933                     start = uid + 1;
1934                 }
1935             }
1936             if (start <= userRange.getUpper()) {
1937                 ranges.add(new Range<Integer>(start, userRange.getUpper()));
1938             }
1939         } else {
1940             // Add all UIDs for the user.
1941             ranges.add(createUidRangeForUser(userId));
1942         }
1943     }
1944 
1945     // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
1946     // apply to userId.
uidRangesForUser(int userId, Set<Range<Integer>> existingRanges)1947     private static List<Range<Integer>> uidRangesForUser(int userId,
1948             Set<Range<Integer>> existingRanges) {
1949         final Range<Integer> userRange = createUidRangeForUser(userId);
1950         final List<Range<Integer>> ranges = new ArrayList<>();
1951         for (Range<Integer> range : existingRanges) {
1952             if (userRange.contains(range)) {
1953                 ranges.add(range);
1954             }
1955         }
1956         return ranges;
1957     }
1958 
1959     /**
1960      * Updates UID ranges for this VPN and also updates its internal capabilities.
1961      *
1962      * <p>Should be called on primary ConnectivityService thread.
1963      */
onUserAdded(int userId)1964     public void onUserAdded(int userId) {
1965         // If the user is restricted tie them to the parent user's VPN
1966         UserInfo user = mUserManager.getUserInfo(userId);
1967         if (user == null) {
1968             Log.e(TAG, "Can not retrieve UserInfo for userId=" + userId);
1969             return;
1970         }
1971         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
1972             synchronized(Vpn.this) {
1973                 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
1974                 if (existingRanges != null) {
1975                     try {
1976                         addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
1977                                 mConfig.disallowedApplications);
1978                         mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
1979                                 .setUids(existingRanges).build();
1980                     } catch (Exception e) {
1981                         Log.wtf(TAG, "Failed to add restricted user to owner", e);
1982                     }
1983                     if (mNetworkAgent != null) {
1984                         doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
1985                     }
1986                 }
1987                 setVpnForcedLocked(mLockdown);
1988             }
1989         }
1990     }
1991 
1992     /**
1993      * Updates UID ranges for this VPN and also updates its capabilities.
1994      *
1995      * <p>Should be called on primary ConnectivityService thread.
1996      */
onUserRemoved(int userId)1997     public void onUserRemoved(int userId) {
1998         // clean up if restricted
1999         UserInfo user = mUserManager.getUserInfo(userId);
2000         // TODO: Retrieving UserInfo upon receiving the USER_REMOVED intent is not guaranteed.
2001         //  This could prevent the removal of associated ranges. To ensure proper range removal,
2002         //  store the user info when adding ranges. This allows using the user ID in the
2003         //  USER_REMOVED intent to handle the removal process.
2004         if (user == null) {
2005             Log.e(TAG, "Can not retrieve UserInfo for userId=" + userId);
2006             return;
2007         }
2008         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
2009             synchronized(Vpn.this) {
2010                 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
2011                 if (existingRanges != null) {
2012                     try {
2013                         final List<Range<Integer>> removedRanges =
2014                                 uidRangesForUser(userId, existingRanges);
2015                         existingRanges.removeAll(removedRanges);
2016                         mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
2017                                 .setUids(existingRanges).build();
2018                     } catch (Exception e) {
2019                         Log.wtf(TAG, "Failed to remove restricted user to owner", e);
2020                     }
2021                     if (mNetworkAgent != null) {
2022                         doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
2023                     }
2024                 }
2025                 setVpnForcedLocked(mLockdown);
2026             }
2027         }
2028     }
2029 
2030     /**
2031      * Called when the user associated with this VPN has just been stopped.
2032      */
onUserStopped()2033     public synchronized void onUserStopped() {
2034         // Switch off networking lockdown (if it was enabled)
2035         setVpnForcedLocked(false);
2036         mAlwaysOn = false;
2037 
2038         // Quit any active connections
2039         agentDisconnect();
2040 
2041         // The provider has been registered in the constructor, which is called in onUserStart.
2042         mConnectivityManager.unregisterNetworkProvider(mNetworkProvider);
2043     }
2044 
2045     /**
2046      * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN
2047      * service app itself and allowed packages, to only sockets that have had {@code protect()}
2048      * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the
2049      * kernel.
2050      *
2051      * The exception for the VPN UID isn't technically necessary -- setup should use protected
2052      * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
2053      *
2054      * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to
2055      * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}.
2056      *
2057      * @param enforce {@code true} to require that all traffic under the jurisdiction of this
2058      *                {@link Vpn} goes through a VPN connection or is blocked until one is
2059      *                available, {@code false} to lift the requirement.
2060      *
2061      * @see #mBlockedUidsAsToldToConnectivity
2062      */
2063     @GuardedBy("this")
setVpnForcedLocked(boolean enforce)2064     private void setVpnForcedLocked(boolean enforce) {
2065         final List<String> exemptedPackages;
2066         if (isNullOrLegacyVpn(mPackage)) {
2067             exemptedPackages = null;
2068         } else {
2069             exemptedPackages = new ArrayList<>(mLockdownAllowlist);
2070             exemptedPackages.add(mPackage);
2071         }
2072         final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity);
2073         final Set<UidRangeParcel> rangesToAdd;
2074         if (enforce) {
2075             final Set<Range<Integer>> restrictedProfilesRanges =
2076                     createUserAndRestrictedProfilesRanges(mUserId,
2077                     /* allowedApplications */ null,
2078                     /* disallowedApplications */ exemptedPackages);
2079             final Set<UidRangeParcel> rangesThatShouldBeBlocked = new ArraySet<>();
2080 
2081             // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
2082             // directly from the kernel and is marked as uid=0. So we adjust the range to allow
2083             // it through (b/69873852).
2084             for (Range<Integer> range : restrictedProfilesRanges) {
2085                 if (range.getLower() == 0 && range.getUpper() != 0) {
2086                     rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper()));
2087                 } else if (range.getLower() != 0) {
2088                     rangesThatShouldBeBlocked.add(
2089                             new UidRangeParcel(range.getLower(), range.getUpper()));
2090                 }
2091             }
2092 
2093             rangesToRemove.removeAll(rangesThatShouldBeBlocked);
2094             rangesToAdd = rangesThatShouldBeBlocked;
2095             // The ranges to tell ConnectivityService to add are the ones that should be blocked
2096             // minus the ones it already knows to block. Note that this will change the contents of
2097             // rangesThatShouldBeBlocked, but the list of ranges that should be blocked is
2098             // not used after this so it's fine to destroy it.
2099             rangesToAdd.removeAll(mBlockedUidsAsToldToConnectivity);
2100         } else {
2101             rangesToAdd = Collections.emptySet();
2102         }
2103 
2104         // If mBlockedUidsAsToldToNetd used to be empty, this will always be a no-op.
2105         setAllowOnlyVpnForUids(false, rangesToRemove);
2106         // If nothing should be blocked now, this will now be a no-op.
2107         setAllowOnlyVpnForUids(true, rangesToAdd);
2108     }
2109 
2110     /**
2111      * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of
2112      * UIDs that are only allowed to make connections through sockets that have had
2113      * {@code protect()} called on them.
2114      *
2115      * @param enforce {@code true} to add to the denylist, {@code false} to remove.
2116      * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is
2117      *               {@code true}) or to remove.
2118      * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
2119      *         including added ranges that already existed or removed ones that didn't.
2120      */
2121     @GuardedBy("this")
setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges)2122     private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges) {
2123         if (ranges.size() == 0) {
2124             return true;
2125         }
2126         // Convert to Collection<Range> which is what the ConnectivityManager API takes.
2127         ArrayList<Range<Integer>> integerRanges = new ArrayList<>(ranges.size());
2128         for (UidRangeParcel uidRange : ranges) {
2129             integerRanges.add(new Range<>(uidRange.start, uidRange.stop));
2130         }
2131         try {
2132             mConnectivityManager.setRequireVpnForUids(enforce, integerRanges);
2133         } catch (RuntimeException e) {
2134             Log.e(TAG, "Updating blocked=" + enforce
2135                     + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e);
2136             return false;
2137         }
2138         if (enforce) {
2139             mBlockedUidsAsToldToConnectivity.addAll(ranges);
2140         } else {
2141             mBlockedUidsAsToldToConnectivity.removeAll(ranges);
2142         }
2143         return true;
2144     }
2145 
2146     /**
2147      * Return the configuration of the currently running VPN.
2148      */
getVpnConfig()2149     public synchronized VpnConfig getVpnConfig() {
2150         enforceControlPermission();
2151         // Constructor of VpnConfig cannot take a null parameter. Return null directly if mConfig is
2152         // null
2153         if (mConfig == null) return null;
2154         // mConfig is guarded by "this" and can be modified by another thread as soon as
2155         // this method returns, so this method must return a copy.
2156         return new VpnConfig(mConfig);
2157     }
2158 
2159     @Deprecated
interfaceStatusChanged(String iface, boolean up)2160     public synchronized void interfaceStatusChanged(String iface, boolean up) {
2161         try {
2162             mObserver.interfaceStatusChanged(iface, up);
2163         } catch (RemoteException e) {
2164             // ignored; target is local
2165         }
2166     }
2167 
2168     private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
2169         @Override
2170         public void interfaceRemoved(String interfaze) {
2171             synchronized (Vpn.this) {
2172                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
2173                     if (mConnection != null) {
2174                         mAppOpsManager.finishOp(
2175                                 AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage,
2176                                 null);
2177                         mContext.unbindService(mConnection);
2178                         cleanupVpnStateLocked();
2179                     } else if (mVpnRunner != null) {
2180                         if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
2181                             mAppOpsManager.finishOp(
2182                                     AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage,
2183                                     null);
2184                         }
2185                         // cleanupVpnStateLocked() is called from mVpnRunner.exit()
2186                         mVpnRunner.exit();
2187                     }
2188                 }
2189             }
2190         }
2191     };
2192 
2193     @GuardedBy("this")
cleanupVpnStateLocked()2194     private void cleanupVpnStateLocked() {
2195         mStatusIntent = null;
2196         resetNetworkCapabilities();
2197         mConfig = null;
2198         mInterface = null;
2199 
2200         // Unconditionally clear both VpnService and VpnRunner fields.
2201         mVpnRunner = null;
2202         mConnection = null;
2203         agentDisconnect();
2204     }
2205 
enforceControlPermission()2206     private void enforceControlPermission() {
2207         mContext.enforceCallingPermission(CONTROL_VPN, "Unauthorized Caller");
2208     }
2209 
enforceControlPermissionOrInternalCaller()2210     private void enforceControlPermissionOrInternalCaller() {
2211         // Require the caller to be either an application with CONTROL_VPN permission or a process
2212         // in the system server.
2213         mContext.enforceCallingOrSelfPermission(CONTROL_VPN, "Unauthorized Caller");
2214     }
2215 
enforceSettingsPermission()2216     private void enforceSettingsPermission() {
2217         mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_SETTINGS,
2218                 "Unauthorized Caller");
2219     }
2220 
2221     private class Connection implements ServiceConnection {
2222         private IBinder mService;
2223 
2224         @Override
onServiceConnected(ComponentName name, IBinder service)2225         public void onServiceConnected(ComponentName name, IBinder service) {
2226             mService = service;
2227         }
2228 
2229         @Override
onServiceDisconnected(ComponentName name)2230         public void onServiceDisconnected(ComponentName name) {
2231             mService = null;
2232         }
2233     }
2234 
prepareStatusIntent()2235     private void prepareStatusIntent() {
2236         final long token = Binder.clearCallingIdentity();
2237         try {
2238             mStatusIntent = mDeps.getIntentForStatusPanel(mContext);
2239         } finally {
2240             Binder.restoreCallingIdentity(token);
2241         }
2242     }
2243 
addAddress(String address, int prefixLength)2244     public synchronized boolean addAddress(String address, int prefixLength) {
2245         if (!isCallerEstablishedOwnerLocked()) {
2246             return false;
2247         }
2248         boolean success = jniAddAddress(mInterface, address, prefixLength);
2249         doSendLinkProperties(mNetworkAgent, makeLinkProperties());
2250         return success;
2251     }
2252 
removeAddress(String address, int prefixLength)2253     public synchronized boolean removeAddress(String address, int prefixLength) {
2254         if (!isCallerEstablishedOwnerLocked()) {
2255             return false;
2256         }
2257         boolean success = jniDelAddress(mInterface, address, prefixLength);
2258         doSendLinkProperties(mNetworkAgent, makeLinkProperties());
2259         return success;
2260     }
2261 
2262     /**
2263      * Updates underlying network set.
2264      */
setUnderlyingNetworks(@ullable Network[] networks)2265     public synchronized boolean setUnderlyingNetworks(@Nullable Network[] networks) {
2266         if (!isCallerEstablishedOwnerLocked()) {
2267             return false;
2268         }
2269         // Make defensive copy since the content of array might be altered by the caller.
2270         mConfig.underlyingNetworks =
2271                 (networks != null) ? Arrays.copyOf(networks, networks.length) : null;
2272         doSetUnderlyingNetworks(
2273                 mNetworkAgent,
2274                 (mConfig.underlyingNetworks != null)
2275                         ? Arrays.asList(mConfig.underlyingNetworks)
2276                         : null);
2277         return true;
2278     }
2279 
2280     /**
2281      * This method should not be called if underlying interfaces field is needed, because it doesn't
2282      * have enough data to fill VpnInfo.underlyingIfaces field.
2283      */
getUnderlyingNetworkInfo()2284     public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
2285         if (!isRunningLocked()) {
2286             return null;
2287         }
2288 
2289         return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>());
2290     }
2291 
appliesToUid(int uid)2292     public synchronized boolean appliesToUid(int uid) {
2293         if (!isRunningLocked()) {
2294             return false;
2295         }
2296         final Set<Range<Integer>> uids = mNetworkCapabilities.getUids();
2297         if (uids == null) return true;
2298         for (final Range<Integer> range : uids) {
2299             if (range.contains(uid)) return true;
2300         }
2301         return false;
2302     }
2303 
2304     /**
2305      * Gets the currently running VPN type
2306      *
2307      * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running a
2308      *     VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
2309      *     Settings-based, the Platform VPNs can be initiated by both apps and Settings.
2310      */
getActiveVpnType()2311     public synchronized int getActiveVpnType() {
2312         if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE;
2313         if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE;
2314         return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY;
2315     }
2316 
2317     @GuardedBy("this")
updateAlwaysOnNotification(DetailedState networkState)2318     private void updateAlwaysOnNotification(DetailedState networkState) {
2319         final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
2320 
2321         final UserHandle user = UserHandle.of(mUserId);
2322         final long token = Binder.clearCallingIdentity();
2323         try {
2324             final NotificationManager notificationManager =
2325                     mUserIdContext.getSystemService(NotificationManager.class);
2326             if (!visible) {
2327                 notificationManager.cancel(TAG, SystemMessage.NOTE_VPN_DISCONNECTED);
2328                 return;
2329             }
2330             final Intent intent = new Intent();
2331             intent.setComponent(ComponentName.unflattenFromString(mContext.getString(
2332                     R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)));
2333             intent.putExtra("lockdown", mLockdown);
2334             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2335             final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
2336                     intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
2337             final Notification.Builder builder =
2338                     new Notification.Builder(mContext, NOTIFICATION_CHANNEL_VPN)
2339                             .setSmallIcon(R.drawable.vpn_connected)
2340                             .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
2341                             .setContentText(mContext.getString(R.string.vpn_lockdown_config))
2342                             .setContentIntent(configIntent)
2343                             .setCategory(Notification.CATEGORY_SYSTEM)
2344                             .setVisibility(Notification.VISIBILITY_PUBLIC)
2345                             .setOngoing(true)
2346                             .setColor(mContext.getColor(
2347                                     android.R.color.system_notification_accent_color));
2348             notificationManager.notify(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, builder.build());
2349         } finally {
2350             Binder.restoreCallingIdentity(token);
2351         }
2352     }
2353 
2354     /**
2355      * Facade for system service calls that change, or depend on, state outside of
2356      * {@link ConnectivityService} and have hard-to-mock interfaces.
2357      *
2358      * @see com.android.server.connectivity.VpnTest
2359      */
2360     @VisibleForTesting
2361     public static class SystemServices {
2362         private final Context mContext;
2363 
SystemServices(@onNull Context context)2364         public SystemServices(@NonNull Context context) {
2365             mContext = context;
2366         }
2367 
2368         /**
2369          * @see PendingIntent#getActivityAsUser()
2370          */
pendingIntentGetActivityAsUser( Intent intent, int flags, UserHandle user)2371         public PendingIntent pendingIntentGetActivityAsUser(
2372                 Intent intent, int flags, UserHandle user) {
2373             return PendingIntent.getActivity(
2374                     mContext.createContextAsUser(user, 0 /* flags */), 0 /* requestCode */,
2375                     intent, flags);
2376         }
2377 
2378         /**
2379          * @see Settings.Secure#putStringForUser
2380          */
settingsSecurePutStringForUser(String key, String value, int userId)2381         public void settingsSecurePutStringForUser(String key, String value, int userId) {
2382             Settings.Secure.putString(getContentResolverAsUser(userId), key, value);
2383         }
2384 
2385         /**
2386          * @see Settings.Secure#putIntForUser
2387          */
settingsSecurePutIntForUser(String key, int value, int userId)2388         public void settingsSecurePutIntForUser(String key, int value, int userId) {
2389             Settings.Secure.putInt(getContentResolverAsUser(userId), key, value);
2390         }
2391 
2392         /**
2393          * @see Settings.Secure#getStringForUser
2394          */
settingsSecureGetStringForUser(String key, int userId)2395         public String settingsSecureGetStringForUser(String key, int userId) {
2396             return Settings.Secure.getString(getContentResolverAsUser(userId), key);
2397         }
2398 
2399         /**
2400          * @see Settings.Secure#getIntForUser
2401          */
settingsSecureGetIntForUser(String key, int def, int userId)2402         public int settingsSecureGetIntForUser(String key, int def, int userId) {
2403             return Settings.Secure.getInt(getContentResolverAsUser(userId), key, def);
2404         }
2405 
getContentResolverAsUser(int userId)2406         private ContentResolver getContentResolverAsUser(int userId) {
2407             return mContext.createContextAsUser(
2408                     UserHandle.of(userId), 0 /* flags */).getContentResolver();
2409         }
2410     }
2411 
jniCreate(int mtu)2412     private native int jniCreate(int mtu);
jniGetName(int tun)2413     private native String jniGetName(int tun);
jniSetAddresses(String interfaze, String addresses)2414     private native int jniSetAddresses(String interfaze, String addresses);
jniReset(String interfaze)2415     private native void jniReset(String interfaze);
jniCheck(String interfaze)2416     private native int jniCheck(String interfaze);
jniAddAddress(String interfaze, String address, int prefixLen)2417     private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
jniDelAddress(String interfaze, String address, int prefixLen)2418     private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
2419 
enforceNotRestrictedUser()2420     private void enforceNotRestrictedUser() {
2421         final long token = Binder.clearCallingIdentity();
2422         try {
2423             final UserInfo user = mUserManager.getUserInfo(mUserId);
2424 
2425             if (user.isRestricted()) {
2426                 throw new SecurityException("Restricted users cannot configure VPNs");
2427             }
2428         } finally {
2429             Binder.restoreCallingIdentity(token);
2430         }
2431     }
2432 
2433     /**
2434      * Start legacy VPN, controlling native daemons as needed. Creates a
2435      * secondary thread to perform connection work, returning quickly.
2436      *
2437      * Should only be called to respond to Binder requests as this enforces caller permission. Use
2438      * {@link #startLegacyVpnPrivileged(VpnProfile)} to skip the
2439      * permission check only when the caller is trusted (or the call is initiated by the system).
2440      */
startLegacyVpn(VpnProfile profile)2441     public void startLegacyVpn(VpnProfile profile) {
2442         enforceControlPermission();
2443         final long token = Binder.clearCallingIdentity();
2444         try {
2445             startLegacyVpnPrivileged(profile);
2446         } finally {
2447             Binder.restoreCallingIdentity(token);
2448         }
2449     }
2450 
makeKeystoreEngineGrantString(String alias)2451     private String makeKeystoreEngineGrantString(String alias) {
2452         if (alias == null) {
2453             return null;
2454         }
2455         final KeyStore2 keystore2 = KeyStore2.getInstance();
2456 
2457         KeyDescriptor key = new KeyDescriptor();
2458         key.domain = Domain.APP;
2459         key.nspace = KeyProperties.NAMESPACE_APPLICATION;
2460         key.alias = alias;
2461         key.blob = null;
2462 
2463         final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO;
2464 
2465         try {
2466             // The native vpn daemon is running as VPN_UID. This tells Keystore 2.0
2467             // to allow a process running with this UID to access the key designated by
2468             // the KeyDescriptor `key`. `grant` returns a new KeyDescriptor with a grant
2469             // identifier. This identifier needs to be communicated to the vpn daemon.
2470             key = keystore2.grant(key, android.os.Process.VPN_UID, grantAccessVector);
2471         } catch (android.security.KeyStoreException e) {
2472             Log.e(TAG, "Failed to get grant for keystore key.", e);
2473             throw new IllegalStateException("Failed to get grant for keystore key.", e);
2474         }
2475 
2476         // Turn the grant identifier into a string as understood by the keystore boringssl engine
2477         // in system/security/keystore-engine.
2478         return KeyStore2.makeKeystoreEngineGrantString(key.nspace);
2479     }
2480 
getCaCertificateFromKeystoreAsPem(@onNull KeyStore keystore, @NonNull String alias)2481     private String getCaCertificateFromKeystoreAsPem(@NonNull KeyStore keystore,
2482             @NonNull String alias)
2483             throws KeyStoreException, IOException, CertificateEncodingException {
2484         if (keystore.isCertificateEntry(alias)) {
2485             final Certificate cert = keystore.getCertificate(alias);
2486             if (cert == null) return null;
2487             return new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
2488         } else {
2489             final Certificate[] certs = keystore.getCertificateChain(alias);
2490             // If there is none or one entry it means there is no CA entry associated with this
2491             // alias.
2492             if (certs == null || certs.length <= 1) {
2493                 return null;
2494             }
2495             // If this is not a (pure) certificate entry, then there is a user certificate which
2496             // will be included at the beginning of the certificate chain. But the caller of this
2497             // function does not expect this certificate to be included, so we cut it off.
2498             return new String(Credentials.convertToPem(
2499                     Arrays.copyOfRange(certs, 1, certs.length)), StandardCharsets.UTF_8);
2500         }
2501     }
2502 
2503     /**
2504      * Like {@link #startLegacyVpn(VpnProfile)}, but does not check permissions under
2505      * the assumption that the caller is the system.
2506      *
2507      * Callers are responsible for checking permissions if needed.
2508      */
startLegacyVpnPrivileged(VpnProfile profileToStart)2509     public void startLegacyVpnPrivileged(VpnProfile profileToStart) {
2510         final VpnProfile profile = profileToStart.clone();
2511         UserInfo user = mUserManager.getUserInfo(mUserId);
2512         if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
2513                     new UserHandle(mUserId))) {
2514             throw new SecurityException("Restricted users cannot establish VPNs");
2515         }
2516 
2517         // Load certificates.
2518         String privateKey = "";
2519         String userCert = "";
2520         String caCert = "";
2521         String serverCert = "";
2522 
2523         try {
2524             final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
2525             keystore.load(null);
2526             if (!profile.ipsecUserCert.isEmpty()) {
2527                 privateKey = profile.ipsecUserCert;
2528                 final Certificate cert = keystore.getCertificate(profile.ipsecUserCert);
2529                 userCert = (cert == null) ? null
2530                          : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
2531             }
2532             if (!profile.ipsecCaCert.isEmpty()) {
2533                 caCert = getCaCertificateFromKeystoreAsPem(keystore, profile.ipsecCaCert);
2534             }
2535             if (!profile.ipsecServerCert.isEmpty()) {
2536                 final Certificate cert = keystore.getCertificate(profile.ipsecServerCert);
2537                 serverCert = (cert == null) ? null
2538                         : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
2539             }
2540         } catch (CertificateException | KeyStoreException | IOException
2541                 | NoSuchAlgorithmException e) {
2542             throw new IllegalStateException("Failed to load credentials from AndroidKeyStore", e);
2543         }
2544         if (userCert == null || caCert == null || serverCert == null) {
2545             throw new IllegalStateException("Cannot load credentials");
2546         }
2547 
2548         switch (profile.type) {
2549             case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
2550                 // Secret key is still just the alias (not the actual private key). The private key
2551                 // is retrieved from the KeyStore during conversion of the VpnProfile to an
2552                 // Ikev2VpnProfile.
2553                 profile.ipsecSecret = Ikev2VpnProfile.PREFIX_KEYSTORE_ALIAS + privateKey;
2554                 profile.ipsecUserCert = userCert;
2555                 // Fallthrough
2556             case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
2557                 profile.ipsecCaCert = caCert;
2558 
2559                 // Start VPN profile
2560                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
2561                 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
2562                 return;
2563             case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
2564                 // Ikev2VpnProfiles expect a base64-encoded preshared key.
2565                 profile.ipsecSecret =
2566                         Ikev2VpnProfile.encodeForIpsecSecret(profile.ipsecSecret.getBytes());
2567 
2568                 // Start VPN profile
2569                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
2570                 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
2571                 return;
2572             case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
2573                 // All the necessary IKE options should come from IkeTunnelConnectionParams in the
2574                 // profile.
2575                 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
2576                 return;
2577         }
2578 
2579         throw new UnsupportedOperationException("Legacy VPN is deprecated");
2580     }
2581 
2582     /**
2583      * Checks if this the currently running VPN (if any) was started by the Settings app
2584      *
2585      * <p>This includes both Legacy VPNs and Platform VPNs.
2586      */
isSettingsVpnLocked()2587     private boolean isSettingsVpnLocked() {
2588         return mVpnRunner != null && VpnConfig.LEGACY_VPN.equals(mPackage);
2589     }
2590 
2591     /** Stop VPN runner. Permissions must be checked by callers. */
stopVpnRunnerPrivileged()2592     public synchronized void stopVpnRunnerPrivileged() {
2593         if (!isSettingsVpnLocked()) {
2594             return;
2595         }
2596 
2597         mVpnRunner.exit();
2598     }
2599 
2600     /**
2601      * Return the information of the current ongoing legacy VPN.
2602      */
getLegacyVpnInfo()2603     public synchronized LegacyVpnInfo getLegacyVpnInfo() {
2604         // Check if the caller is authorized.
2605         enforceControlPermission();
2606         return getLegacyVpnInfoPrivileged();
2607     }
2608 
2609     /**
2610      * Return the information of the current ongoing legacy VPN.
2611      * Callers are responsible for checking permissions if needed.
2612      */
getLegacyVpnInfoPrivileged()2613     private synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
2614         if (!isSettingsVpnLocked()) return null;
2615 
2616         final LegacyVpnInfo info = new LegacyVpnInfo();
2617         info.key = mConfig.user;
2618         info.state = mLegacyState;
2619         if (mNetworkInfo.isConnected()) {
2620             info.intent = mStatusIntent;
2621         }
2622         return info;
2623     }
2624 
getLegacyVpnConfig()2625     public synchronized VpnConfig getLegacyVpnConfig() {
2626         if (isSettingsVpnLocked()) {
2627             return mConfig;
2628         } else {
2629             return null;
2630         }
2631     }
2632 
2633     @Nullable
getRedactedNetworkCapabilities( NetworkCapabilities nc)2634     private synchronized NetworkCapabilities getRedactedNetworkCapabilities(
2635             NetworkCapabilities nc) {
2636         if (nc == null) return null;
2637         return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage(
2638                 nc, mOwnerUID, mPackage);
2639     }
2640 
2641     @Nullable
getRedactedLinkProperties(LinkProperties lp)2642     private synchronized LinkProperties getRedactedLinkProperties(LinkProperties lp) {
2643         if (lp == null) return null;
2644         return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage);
2645     }
2646 
2647     /** This class represents the common interface for all VPN runners. */
2648     @VisibleForTesting
2649     abstract class VpnRunner extends Thread {
2650 
VpnRunner(String name)2651         protected VpnRunner(String name) {
2652             super(name);
2653         }
2654 
run()2655         public abstract void run();
2656 
2657         /**
2658          * Disconnects the NetworkAgent and cleans up all state related to the VpnRunner.
2659          *
2660          * <p>All outer Vpn instance state is cleaned up in cleanupVpnStateLocked()
2661          */
exitVpnRunner()2662         protected abstract void exitVpnRunner();
2663 
2664         /**
2665          * Triggers the cleanup of the VpnRunner, and additionally cleans up Vpn instance-wide state
2666          *
2667          * <p>This method ensures that simple calls to exit() will always clean up global state
2668          * properly.
2669          */
exit()2670         protected final void exit() {
2671             synchronized (Vpn.this) {
2672                 exitVpnRunner();
2673                 cleanupVpnStateLocked();
2674             }
2675         }
2676     }
2677 
2678     interface IkeV2VpnRunnerCallback {
onDefaultNetworkChanged(@onNull Network network)2679         void onDefaultNetworkChanged(@NonNull Network network);
2680 
onDefaultNetworkCapabilitiesChanged(@onNull NetworkCapabilities nc)2681         void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc);
2682 
onDefaultNetworkLinkPropertiesChanged(@onNull LinkProperties lp)2683         void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
2684 
onDefaultNetworkLost(@onNull Network network)2685         void onDefaultNetworkLost(@NonNull Network network);
2686 
onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration)2687         void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration);
2688 
onIkeConnectionInfoChanged( int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo)2689         void onIkeConnectionInfoChanged(
2690                 int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo);
2691 
onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig)2692         void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig);
2693 
onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction)2694         void onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction);
2695 
onChildMigrated( int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform)2696         void onChildMigrated(
2697                 int token,
2698                 @NonNull IpSecTransform inTransform,
2699                 @NonNull IpSecTransform outTransform);
2700 
onSessionLost(int token, @Nullable Exception exception)2701         void onSessionLost(int token, @Nullable Exception exception);
2702     }
2703 
isIPv6Only(List<LinkAddress> linkAddresses)2704     private static boolean isIPv6Only(List<LinkAddress> linkAddresses) {
2705         boolean hasIPV6 = false;
2706         boolean hasIPV4 = false;
2707         for (final LinkAddress address : linkAddresses) {
2708             hasIPV6 |= address.isIpv6();
2709             hasIPV4 |= address.isIpv4();
2710         }
2711 
2712         return hasIPV6 && !hasIPV4;
2713     }
2714 
setVpnNetworkPreference(String session, Set<Range<Integer>> ranges)2715     private void setVpnNetworkPreference(String session, Set<Range<Integer>> ranges) {
2716         BinderUtils.withCleanCallingIdentity(
2717                 () -> mConnectivityManager.setVpnDefaultForUids(session, ranges));
2718     }
2719 
clearVpnNetworkPreference(String session)2720     private void clearVpnNetworkPreference(String session) {
2721         BinderUtils.withCleanCallingIdentity(
2722                 () -> mConnectivityManager.setVpnDefaultForUids(session, Collections.EMPTY_LIST));
2723     }
2724 
2725     /**
2726      * Internal class managing IKEv2/IPsec VPN connectivity
2727      *
2728      * <p>The IKEv2 VPN will listen to, and run based on the lifecycle of Android's default Network.
2729      * As a new default is selected, old IKE sessions will be torn down, and a new one will be
2730      * started.
2731      *
2732      * <p>This class uses locking minimally - the Vpn instance lock is only ever held when fields of
2733      * the outer class are modified. As such, care must be taken to ensure that no calls are added
2734      * that might modify the outer class' state without acquiring a lock.
2735      *
2736      * <p>The overall structure of the Ikev2VpnRunner is as follows:
2737      *
2738      * <ol>
2739      *   <li>Upon startup, a NetworkRequest is registered with ConnectivityManager. This is called
2740      *       any time a new default network is selected
2741      *   <li>When a new default is connected, an IKE session is started on that Network. If there
2742      *       were any existing IKE sessions on other Networks, they are torn down before starting
2743      *       the new IKE session
2744      *   <li>Upon establishment, the onChildTransformCreated() callback is called twice, one for
2745      *       each direction, and finally onChildOpened() is called
2746      *   <li>Upon the onChildOpened() call, the VPN is fully set up.
2747      *   <li>Subsequent Network changes result in new onDefaultNetworkChanged() callbacks. See (2).
2748      * </ol>
2749      */
2750     class IkeV2VpnRunner extends VpnRunner implements IkeV2VpnRunnerCallback {
2751         @NonNull private static final String TAG = "IkeV2VpnRunner";
2752 
2753         // 5 seconds grace period before tearing down the IKE Session in case new default network
2754         // will come up
2755         private static final long NETWORK_LOST_TIMEOUT_MS = 5000L;
2756 
2757         @NonNull private final IpSecManager mIpSecManager;
2758         @NonNull private final Ikev2VpnProfile mProfile;
2759         @NonNull private final ConnectivityManager.NetworkCallback mNetworkCallback;
2760 
2761         /**
2762          * Executor upon which ALL callbacks must be run.
2763          *
2764          * <p>This executor MUST be a single threaded executor, in order to ensure the consistency
2765          * of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by
2766          * virtue of everything being serialized on this executor.
2767          */
2768         @NonNull private final ScheduledThreadPoolExecutor mExecutor;
2769 
2770         @Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostFuture;
2771         @Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionFuture;
2772         @Nullable private ScheduledFuture<?> mScheduledHandleDataStallFuture;
2773         /** Signal to ensure shutdown is honored even if a new Network is connected. */
2774         private boolean mIsRunning = true;
2775 
2776         /**
2777          * The token that identifies the most recently created IKE session.
2778          *
2779          * <p>This token is monotonically increasing and will never be reset in the lifetime of this
2780          * Ikev2VpnRunner, but it does get reset across runs. It also MUST be accessed on the
2781          * executor thread and updated when a new IKE session is created.
2782          */
2783         private int mCurrentToken = STARTING_TOKEN;
2784 
2785         @Nullable private IpSecTunnelInterface mTunnelIface;
2786         @Nullable private Network mActiveNetwork;
2787         @Nullable private NetworkCapabilities mUnderlyingNetworkCapabilities;
2788         @Nullable private LinkProperties mUnderlyingLinkProperties;
2789         private final String mSessionKey;
2790 
2791         @Nullable private IkeSessionWrapper mSession;
2792         @Nullable private IkeSessionConnectionInfo mIkeConnectionInfo;
2793 
2794         // mMobikeEnabled can only be updated after IKE AUTH is finished.
2795         private boolean mMobikeEnabled = false;
2796 
2797         /**
2798          * The number of attempts to reset the IKE session since the last successful connection.
2799          *
2800          * <p>This variable controls the retry delay, and is reset when the VPN pass network
2801          * validation.
2802          */
2803         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
2804         int mValidationFailRetryCount = 0;
2805 
2806         /**
2807          * The number of attempts since the last successful connection.
2808          *
2809          * <p>This variable controls the retry delay, and is reset when a new IKE session is
2810          * opened or when there is a new default network.
2811          */
2812         private int mRetryCount = 0;
2813 
2814         private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
2815                 new CarrierConfigManager.CarrierConfigChangeListener() {
2816                     @Override
2817                     public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId,
2818                             int specificCarrierId) {
2819                         mEventChanges.log("[CarrierConfig] Changed on slot " + slotIndex + " subId="
2820                                 + subId + " carrerId=" + carrierId
2821                                 + " specificCarrierId=" + specificCarrierId);
2822                         synchronized (Vpn.this) {
2823                             mCachedCarrierConfigInfoPerSubId.remove(subId);
2824 
2825                             // Ignore stale runner.
2826                             if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;
2827 
2828                             maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
2829                         }
2830                     }
2831         };
2832 
2833         // GuardedBy("Vpn.this") (annotation can't be applied to constructor)
IkeV2VpnRunner( @onNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor)2834         IkeV2VpnRunner(
2835                 @NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) {
2836             super(TAG);
2837             mProfile = profile;
2838             mExecutor = executor;
2839             mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
2840             mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor);
2841             mSessionKey = UUID.randomUUID().toString();
2842             // Add log for debugging flaky test. b/242833779
2843             Log.d(TAG, "Generate session key = " + mSessionKey);
2844 
2845             // Set the policy so that cancelled tasks will be removed from the work queue
2846             mExecutor.setRemoveOnCancelPolicy(true);
2847 
2848             // Set the policy so that all delayed tasks will not be executed
2849             mExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
2850 
2851             // To avoid hitting RejectedExecutionException upon shutdown of the mExecutor */
2852             mExecutor.setRejectedExecutionHandler(
2853                     (r, exe) -> {
2854                         Log.d(TAG, "Runnable " + r + " rejected by the mExecutor");
2855                     });
2856             setVpnNetworkPreference(mSessionKey,
2857                     createUserAndRestrictedProfilesRanges(mUserId,
2858                             mConfig.allowedApplications, mConfig.disallowedApplications));
2859 
2860             if (mCarrierConfigManager != null) {
2861                 mCarrierConfigManager.registerCarrierConfigChangeListener(mExecutor,
2862                         mCarrierConfigChangeListener);
2863             }
2864         }
2865 
2866         @Override
run()2867         public void run() {
2868             // Unless the profile is restricted to test networks, explicitly use only the network
2869             // that ConnectivityService thinks is the "best." In other words, only ever use the
2870             // currently selected default network. This does mean that in both onLost() and
2871             // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs.
2872             //
2873             // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
2874             // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
2875             // this is considered safe.
2876 
2877             if (mProfile.isRestrictedToTestNetworks()) {
2878                 final NetworkRequest req = new NetworkRequest.Builder()
2879                         .clearCapabilities()
2880                         .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
2881                         .addCapability(NET_CAPABILITY_NOT_VPN)
2882                         .build();
2883                 mConnectivityManager.requestNetwork(req, mNetworkCallback);
2884             } else {
2885                 mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback,
2886                         new Handler(mLooper));
2887             }
2888         }
2889 
isActiveNetwork(@ullable Network network)2890         private boolean isActiveNetwork(@Nullable Network network) {
2891             return Objects.equals(mActiveNetwork, network) && mIsRunning;
2892         }
2893 
isActiveToken(int token)2894         private boolean isActiveToken(int token) {
2895             return (mCurrentToken == token) && mIsRunning;
2896         }
2897 
2898         /**
2899          * Called when an IKE session has been opened
2900          *
2901          * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
2902          * thread in order to ensure consistency of the Ikev2VpnRunner fields.
2903          */
onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration)2904         public void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration) {
2905             if (!isActiveToken(token)) {
2906                 mEventChanges.log("[IKEEvent-" + mSessionKey + "] onIkeOpened obsolete token="
2907                         + token);
2908                 Log.d(TAG, "onIkeOpened called for obsolete token " + token);
2909                 return;
2910             }
2911 
2912             mMobikeEnabled =
2913                     ikeConfiguration.isIkeExtensionEnabled(
2914                             IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE);
2915             final IkeSessionConnectionInfo info = ikeConfiguration.getIkeSessionConnectionInfo();
2916             mEventChanges.log("[IKEEvent-" + mSessionKey + "] onIkeOpened token=" + token
2917                     + ", localAddr=" + info.getLocalAddress()
2918                     + ", network=" + info.getNetwork()
2919                     + ", mobikeEnabled= " + mMobikeEnabled);
2920             onIkeConnectionInfoChanged(token, info);
2921         }
2922 
2923         /**
2924          * Called when an IKE session's {@link IkeSessionConnectionInfo} is available or updated
2925          *
2926          * <p>This callback is usually fired when an IKE session has been opened or migrated.
2927          *
2928          * <p>This method is called multiple times over the lifetime of an IkeSession, and MUST run
2929          * on the mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields.
2930          */
onIkeConnectionInfoChanged( int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo)2931         public void onIkeConnectionInfoChanged(
2932                 int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
2933 
2934             if (!isActiveToken(token)) {
2935                 mEventChanges.log("[IKEEvent-" + mSessionKey
2936                         + "] onIkeConnectionInfoChanged obsolete token=" + token);
2937                 Log.d(TAG, "onIkeConnectionInfoChanged called for obsolete token " + token);
2938                 return;
2939             }
2940             mEventChanges.log("[IKEEvent-" + mSessionKey
2941                     + "] onIkeConnectionInfoChanged token=" + token
2942                     + ", localAddr=" + ikeConnectionInfo.getLocalAddress()
2943                     + ", network=" + ikeConnectionInfo.getNetwork());
2944             // The update on VPN and the IPsec tunnel will be done when migration is fully complete
2945             // in onChildMigrated
2946             mIkeConnectionInfo = ikeConnectionInfo;
2947         }
2948 
2949         /**
2950          * Called when an IKE Child session has been opened, signalling completion of the startup.
2951          *
2952          * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
2953          * thread in order to ensure consistency of the Ikev2VpnRunner fields.
2954          */
onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig)2955         public void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
2956             if (!isActiveToken(token)) {
2957                 mEventChanges.log("[IKEEvent-" + mSessionKey
2958                         + "] onChildOpened obsolete token=" + token);
2959                 Log.d(TAG, "onChildOpened called for obsolete token " + token);
2960 
2961                 // Do nothing; this signals that either: (1) a new/better Network was found,
2962                 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
2963                 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
2964                 // or an error was encountered somewhere else). In both cases, all resources and
2965                 // sessions are torn down via resetIkeState().
2966                 return;
2967             }
2968             mEventChanges.log("[IKEEvent-" + mSessionKey + "] onChildOpened token=" + token
2969                     + ", addr=" + TextUtils.join(", ", childConfig.getInternalAddresses())
2970                     + " dns=" + TextUtils.join(", ", childConfig.getInternalDnsServers()));
2971             try {
2972                 final String interfaceName = mTunnelIface.getInterfaceName();
2973                 final List<LinkAddress> internalAddresses = childConfig.getInternalAddresses();
2974                 final List<String> dnsAddrStrings = new ArrayList<>();
2975                 int vpnMtu;
2976                 vpnMtu = calculateVpnMtu();
2977 
2978                 // If the VPN is IPv6 only and its MTU is lower than 1280, mark the network as lost
2979                 // and send the VpnManager event to the VPN app.
2980                 if (isIPv6Only(internalAddresses) && vpnMtu < IPV6_MIN_MTU) {
2981                     onSessionLost(
2982                             token,
2983                             new IkeIOException(
2984                                     new IOException("No valid addresses for MTU < 1280")));
2985                     return;
2986                 }
2987 
2988                 final Collection<RouteInfo> newRoutes = VpnIkev2Utils.getRoutesFromTrafficSelectors(
2989                         childConfig.getOutboundTrafficSelectors());
2990                 for (final LinkAddress address : internalAddresses) {
2991                     mTunnelIface.addAddress(address.getAddress(), address.getPrefixLength());
2992                 }
2993 
2994                 for (InetAddress addr : childConfig.getInternalDnsServers()) {
2995                     dnsAddrStrings.add(addr.getHostAddress());
2996                 }
2997 
2998                 // The actual network of this IKE session has been set up with is
2999                 // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because
3000                 // mActiveNetwork might have been updated after the setup was triggered.
3001                 final Network network = mIkeConnectionInfo.getNetwork();
3002 
3003                 final NetworkAgent networkAgent;
3004                 final LinkProperties lp;
3005 
3006                 synchronized (Vpn.this) {
3007                     // Ignore stale runner.
3008                     if (mVpnRunner != this) return;
3009 
3010                     mInterface = interfaceName;
3011                     mConfig.mtu = vpnMtu;
3012                     mConfig.interfaze = mInterface;
3013 
3014                     mConfig.addresses.clear();
3015                     mConfig.addresses.addAll(internalAddresses);
3016 
3017                     mConfig.routes.clear();
3018                     mConfig.routes.addAll(newRoutes);
3019 
3020                     if (mConfig.dnsServers == null) mConfig.dnsServers = new ArrayList<>();
3021                     mConfig.dnsServers.clear();
3022                     mConfig.dnsServers.addAll(dnsAddrStrings);
3023 
3024                     mConfig.underlyingNetworks = new Network[] {network};
3025 
3026                     networkAgent = mNetworkAgent;
3027 
3028                     // The below must be done atomically with the mConfig update, otherwise
3029                     // isRunningLocked() will be racy.
3030                     if (networkAgent == null) {
3031                         if (isSettingsVpnLocked()) {
3032                             prepareStatusIntent();
3033                         }
3034                         agentConnect(this::onValidationStatus);
3035                         return; // Link properties are already sent.
3036                     }
3037 
3038                     lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
3039                 }
3040 
3041                 doSendLinkProperties(networkAgent, lp);
3042                 mRetryCount = 0;
3043             } catch (Exception e) {
3044                 Log.d(TAG, "Error in ChildOpened for token " + token, e);
3045                 onSessionLost(token, e);
3046             }
3047         }
3048 
3049         /**
3050          * Called when an IPsec transform has been created, and should be applied.
3051          *
3052          * <p>This method is called multiple times over the lifetime of an IkeSession (or default
3053          * network), and MUST always be called on the mExecutor thread in order to ensure
3054          * consistency of the Ikev2VpnRunner fields.
3055          */
onChildTransformCreated( int token, @NonNull IpSecTransform transform, int direction)3056         public void onChildTransformCreated(
3057                 int token, @NonNull IpSecTransform transform, int direction) {
3058             if (!isActiveToken(token)) {
3059                 mEventChanges.log("[IKEEvent-" + mSessionKey
3060                         + "] onChildTransformCreated obsolete token=" + token);
3061                 Log.d(TAG, "ChildTransformCreated for obsolete token " + token);
3062 
3063                 // Do nothing; this signals that either: (1) a new/better Network was found,
3064                 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
3065                 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
3066                 // or an error was encountered somewhere else). In both cases, all resources and
3067                 // sessions are torn down via resetIkeState().
3068                 return;
3069             }
3070             mEventChanges.log("[IKEEvent-" + mSessionKey
3071                     + "] onChildTransformCreated token=" + token + ", direction=" + direction
3072                     + ", transform=" + transform);
3073             try {
3074                 mTunnelIface.setUnderlyingNetwork(mIkeConnectionInfo.getNetwork());
3075 
3076                 // Transforms do not need to be persisted; the IkeSession will keep
3077                 // them alive for us
3078                 mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
3079             } catch (IOException | IllegalArgumentException e) {
3080                 Log.d(TAG, "Transform application failed for token " + token, e);
3081                 onSessionLost(token, e);
3082             }
3083         }
3084 
3085         /**
3086          * Called when an IPsec transform has been created, and should be re-applied.
3087          *
3088          * <p>This method is called multiple times over the lifetime of an IkeSession (or default
3089          * network), and MUST always be called on the mExecutor thread in order to ensure
3090          * consistency of the Ikev2VpnRunner fields.
3091          */
onChildMigrated( int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform)3092         public void onChildMigrated(
3093                 int token,
3094                 @NonNull IpSecTransform inTransform,
3095                 @NonNull IpSecTransform outTransform) {
3096             if (!isActiveToken(token)) {
3097                 mEventChanges.log("[IKEEvent-" + mSessionKey
3098                         + "] onChildMigrated obsolete token=" + token);
3099                 Log.d(TAG, "onChildMigrated for obsolete token " + token);
3100                 return;
3101             }
3102             mEventChanges.log("[IKEEvent-" + mSessionKey
3103                     + "] onChildMigrated token=" + token
3104                     + ", in=" + inTransform + ", out=" + outTransform);
3105             // The actual network of this IKE session has migrated to is
3106             // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because mActiveNetwork
3107             // might have been updated after the migration was triggered.
3108             final Network network = mIkeConnectionInfo.getNetwork();
3109 
3110             try {
3111                 synchronized (Vpn.this) {
3112                     // Ignore stale runner.
3113                     if (mVpnRunner != this) return;
3114 
3115                     final LinkProperties oldLp = makeLinkProperties();
3116 
3117                     mConfig.underlyingNetworks = new Network[] {network};
3118                     mConfig.mtu = calculateVpnMtu();
3119 
3120                     final LinkProperties newLp = makeLinkProperties();
3121 
3122                     // If MTU is < 1280, IPv6 addresses will be removed. If there are no addresses
3123                     // left (e.g. IPv6-only VPN network), mark VPN as having lost the session.
3124                     if (newLp.getLinkAddresses().isEmpty()) {
3125                         onSessionLost(
3126                                 token,
3127                                 new IkeIOException(
3128                                         new IOException("No valid addresses for MTU < 1280")));
3129                         return;
3130                     }
3131 
3132                     final Set<LinkAddress> removedAddrs = new HashSet<>(oldLp.getLinkAddresses());
3133                     removedAddrs.removeAll(newLp.getLinkAddresses());
3134 
3135                     // If addresses were removed despite no IKE config change, IPv6 addresses must
3136                     // have been removed due to MTU size. Restart the VPN to ensure all IPv6
3137                     // unconnected sockets on the new VPN network are closed and retried on the new
3138                     // VPN network.
3139                     if (!removedAddrs.isEmpty()) {
3140                         startNewNetworkAgent(
3141                                 mNetworkAgent, "MTU too low for IPv6; restarting network agent");
3142 
3143                         for (LinkAddress removed : removedAddrs) {
3144                             mTunnelIface.removeAddress(
3145                                     removed.getAddress(), removed.getPrefixLength());
3146                         }
3147                     } else {
3148                         // Put below update into else block is because agentConnect() will do
3149                         // the same things, so there is no need to do the redundant work.
3150                         if (!newLp.equals(oldLp)) doSendLinkProperties(mNetworkAgent, newLp);
3151                     }
3152                 }
3153 
3154                 mTunnelIface.setUnderlyingNetwork(network);
3155 
3156                 // Transforms do not need to be persisted; the IkeSession will keep them alive for
3157                 // us
3158                 mIpSecManager.applyTunnelModeTransform(
3159                         mTunnelIface, IpSecManager.DIRECTION_IN, inTransform);
3160                 mIpSecManager.applyTunnelModeTransform(
3161                         mTunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
3162             } catch (IOException | IllegalArgumentException e) {
3163                 Log.d(TAG, "Transform application failed for token " + token, e);
3164                 onSessionLost(token, e);
3165             }
3166         }
3167 
3168         /**
3169          * Called when a new default network is connected.
3170          *
3171          * <p>The Ikev2VpnRunner will unconditionally switch to the new network. If the IKE session
3172          * has mobility, Ikev2VpnRunner will migrate the existing IkeSession to the new network.
3173          * Otherwise, Ikev2VpnRunner will kill the old IKE state, and start a new IkeSession
3174          * instance.
3175          *
3176          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3177          * consistency of the Ikev2VpnRunner fields.
3178          */
onDefaultNetworkChanged(@onNull Network network)3179         public void onDefaultNetworkChanged(@NonNull Network network) {
3180             mEventChanges.log("[UnderlyingNW] Default network changed to " + network);
3181             Log.d(TAG, "onDefaultNetworkChanged: " + network);
3182 
3183             // If there is a new default network brought up, cancel the retry task to prevent
3184             // establishing an unnecessary IKE session.
3185             cancelRetryNewIkeSessionFuture();
3186 
3187             // If there is a new default network brought up, cancel the obsolete reset and retry
3188             // task.
3189             cancelHandleNetworkLostTimeout();
3190 
3191             if (!mIsRunning) {
3192                 Log.d(TAG, "onDefaultNetworkChanged after exit");
3193                 return; // VPN has been shut down.
3194             }
3195 
3196             mActiveNetwork = network;
3197             mUnderlyingLinkProperties = null;
3198             mUnderlyingNetworkCapabilities = null;
3199             mRetryCount = 0;
3200         }
3201 
3202         @NonNull
getIkeSessionParams(@onNull Network underlyingNetwork)3203         private IkeSessionParams getIkeSessionParams(@NonNull Network underlyingNetwork) {
3204             final IkeTunnelConnectionParams ikeTunConnParams =
3205                     mProfile.getIkeTunnelConnectionParams();
3206             final IkeSessionParams.Builder builder;
3207             if (ikeTunConnParams != null) {
3208                 builder = new IkeSessionParams.Builder(ikeTunConnParams.getIkeSessionParams())
3209                         .setNetwork(underlyingNetwork);
3210             } else {
3211                 builder = VpnIkev2Utils.makeIkeSessionParamsBuilder(mContext, mProfile,
3212                         underlyingNetwork);
3213             }
3214             if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
3215                 builder.setNattKeepAliveDelaySeconds(guessNattKeepaliveTimerForNetwork());
3216             }
3217             if (mProfile.isAutomaticIpVersionSelectionEnabled()) {
3218                 builder.setIpVersion(guessEspIpVersionForNetwork());
3219                 builder.setEncapType(guessEspEncapTypeForNetwork());
3220             }
3221             return builder.build();
3222         }
3223 
3224         @NonNull
getChildSessionParams()3225         private ChildSessionParams getChildSessionParams() {
3226             final IkeTunnelConnectionParams ikeTunConnParams =
3227                     mProfile.getIkeTunnelConnectionParams();
3228             if (ikeTunConnParams != null) {
3229                 return ikeTunConnParams.getTunnelModeChildSessionParams();
3230             } else {
3231                 return VpnIkev2Utils.buildChildSessionParams(mProfile.getAllowedAlgorithms());
3232             }
3233         }
3234 
calculateVpnMtu()3235         private int calculateVpnMtu() {
3236             final Network underlyingNetwork = mIkeConnectionInfo.getNetwork();
3237             final LinkProperties lp = mConnectivityManager.getLinkProperties(underlyingNetwork);
3238             if (underlyingNetwork == null || lp == null) {
3239                 // Return the max MTU defined in VpnProfile as the fallback option when there is no
3240                 // underlying network or LinkProperties is null.
3241                 return mProfile.getMaxMtu();
3242             }
3243 
3244             int underlyingMtu = lp.getMtu();
3245 
3246             // Try to get MTU from kernel if MTU is not set in LinkProperties.
3247             if (underlyingMtu == 0) {
3248                 try {
3249                     underlyingMtu = mDeps.getJavaNetworkInterfaceMtu(lp.getInterfaceName(),
3250                             mProfile.getMaxMtu());
3251                 } catch (SocketException e) {
3252                     Log.d(TAG, "Got a SocketException when getting MTU from kernel: " + e);
3253                     return mProfile.getMaxMtu();
3254                 }
3255             }
3256 
3257             return mDeps.calculateVpnMtu(
3258                     getChildSessionParams().getSaProposals(),
3259                     mProfile.getMaxMtu(),
3260                     underlyingMtu,
3261                     mIkeConnectionInfo.getLocalAddress() instanceof Inet4Address);
3262         }
3263 
3264         /**
3265          * Start a new IKE session.
3266          *
3267          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3268          * consistency of the Ikev2VpnRunner fields.
3269          *
3270          * @param underlyingNetwork if the value is {@code null}, which means there is no active
3271          *              network can be used, do nothing and return immediately. Otherwise, use the
3272          *              given network to start a new IKE session.
3273          */
startOrMigrateIkeSession(@ullable Network underlyingNetwork)3274         private void startOrMigrateIkeSession(@Nullable Network underlyingNetwork) {
3275             synchronized (Vpn.this) {
3276                 // Ignore stale runner.
3277                 if (mVpnRunner != this) return;
3278                 setVpnNetworkPreference(mSessionKey,
3279                         createUserAndRestrictedProfilesRanges(mUserId,
3280                                 mConfig.allowedApplications, mConfig.disallowedApplications));
3281             }
3282             if (underlyingNetwork == null) {
3283                 // For null underlyingNetwork case, there will not be a NetworkAgent available so
3284                 // no underlying network update is necessary here. Note that updating
3285                 // mNetworkCapabilities here would also be reasonable, but it will be updated next
3286                 // time the VPN connects anyway.
3287                 Log.d(TAG, "There is no active network for starting an IKE session");
3288                 return;
3289             }
3290 
3291             final List<Network> networks = Collections.singletonList(underlyingNetwork);
3292             // Update network capabilities if underlying network is changed.
3293             if (!networks.equals(mNetworkCapabilities.getUnderlyingNetworks())) {
3294                 mNetworkCapabilities =
3295                         new NetworkCapabilities.Builder(mNetworkCapabilities)
3296                                 .setUnderlyingNetworks(networks)
3297                                 .build();
3298                 // No NetworkAgent case happens when Vpn tries to start a new VPN. The underlying
3299                 // network update will be done later with NetworkAgent connected event.
3300                 if (mNetworkAgent != null) {
3301                     doSetUnderlyingNetworks(mNetworkAgent, networks);
3302                 }
3303             }
3304 
3305             if (maybeMigrateIkeSessionAndUpdateVpnTransportInfo(underlyingNetwork)) return;
3306 
3307             startIkeSession(underlyingNetwork);
3308         }
3309 
guessEspIpVersionForNetwork()3310         private int guessEspIpVersionForNetwork() {
3311             if (mUnderlyingNetworkCapabilities.getTransportInfo() instanceof VcnTransportInfo) {
3312                 Log.d(TAG, "Running over VCN, esp IP version is auto");
3313                 return ESP_IP_VERSION_AUTO;
3314             }
3315             final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
3316             final int ipVersion = (carrierconfig != null)
3317                     ? carrierconfig.ipVersion : ESP_IP_VERSION_AUTO;
3318             if (carrierconfig != null) {
3319                 Log.d(TAG, "Get customized IP version (" + ipVersion + ") on SIM (mccmnc="
3320                         + carrierconfig.mccMnc + ")");
3321             }
3322             return ipVersion;
3323         }
3324 
guessEspEncapTypeForNetwork()3325         private int guessEspEncapTypeForNetwork() {
3326             if (mUnderlyingNetworkCapabilities.getTransportInfo() instanceof VcnTransportInfo) {
3327                 Log.d(TAG, "Running over VCN, encap type is auto");
3328                 return ESP_ENCAP_TYPE_AUTO;
3329             }
3330             final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
3331             final int encapType = (carrierconfig != null)
3332                     ? carrierconfig.encapType : ESP_ENCAP_TYPE_AUTO;
3333             if (carrierconfig != null) {
3334                 Log.d(TAG, "Get customized encap type (" + encapType + ") on SIM (mccmnc="
3335                         + carrierconfig.mccMnc + ")");
3336             }
3337             return encapType;
3338         }
3339 
3340 
guessNattKeepaliveTimerForNetwork()3341         private int guessNattKeepaliveTimerForNetwork() {
3342             final TransportInfo transportInfo = mUnderlyingNetworkCapabilities.getTransportInfo();
3343             if (transportInfo instanceof VcnTransportInfo) {
3344                 final int nattKeepaliveSec =
3345                         ((VcnTransportInfo) transportInfo).getMinUdpPort4500NatTimeoutSeconds();
3346                 Log.d(TAG, "Running over VCN, keepalive timer : " + nattKeepaliveSec + "s");
3347                 if (VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
3348                         != nattKeepaliveSec) {
3349                     return nattKeepaliveSec;
3350                 }
3351                 // else fall back to carrier config, if any
3352             }
3353             final CarrierConfigInfo carrierconfig = getCarrierConfigForUnderlyingNetwork();
3354             final int nattKeepaliveSec = (carrierconfig != null)
3355                     ? carrierconfig.keepaliveDelaySec : AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
3356             if (carrierconfig != null) {
3357                 Log.d(TAG, "Get customized keepalive (" + nattKeepaliveSec + "s) on SIM (mccmnc="
3358                         + carrierconfig.mccMnc + ")");
3359             }
3360             return nattKeepaliveSec;
3361         }
3362 
3363         /**
3364          * Returns the carrier config for the underlying network, or null if not a cell network.
3365          */
3366         @Nullable
getCarrierConfigForUnderlyingNetwork()3367         private CarrierConfigInfo getCarrierConfigForUnderlyingNetwork() {
3368             if (mCarrierConfigManager == null) {
3369                 return null;
3370             }
3371 
3372             final int subId = getCellSubIdForNetworkCapabilities(mUnderlyingNetworkCapabilities);
3373             if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
3374                 Log.d(TAG, "Underlying network is not a cellular network");
3375                 return null;
3376             }
3377 
3378             synchronized (Vpn.this) {
3379                 if (mCachedCarrierConfigInfoPerSubId.contains(subId)) {
3380                     Log.d(TAG, "Get cached config");
3381                     return mCachedCarrierConfigInfoPerSubId.get(subId);
3382                 }
3383             }
3384 
3385             final TelephonyManager perSubTm = mTelephonyManager.createForSubscriptionId(subId);
3386             if (perSubTm.getSimApplicationState() != TelephonyManager.SIM_STATE_LOADED) {
3387                 Log.d(TAG, "SIM card is not ready on sub " + subId);
3388                 return null;
3389             }
3390 
3391             final PersistableBundle carrierConfig =
3392                     mCarrierConfigManager.getConfigForSubId(subId);
3393             if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
3394                 return null;
3395             }
3396 
3397             final int natKeepalive =
3398                     carrierConfig.getInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT);
3399             final int preferredIpProtocol = carrierConfig.getInt(
3400                     KEY_PREFERRED_IKE_PROTOCOL_INT, PREFERRED_IKE_PROTOCOL_UNKNOWN);
3401             final String mccMnc = perSubTm.getSimOperator(subId);
3402             final CarrierConfigInfo info =
3403                     buildCarrierConfigInfo(mccMnc, natKeepalive, preferredIpProtocol);
3404             synchronized (Vpn.this) {
3405                 mCachedCarrierConfigInfoPerSubId.put(subId, info);
3406             }
3407 
3408             return info;
3409         }
3410 
buildCarrierConfigInfo(String mccMnc, int natKeepalive, int preferredIpPortocol)3411         private CarrierConfigInfo buildCarrierConfigInfo(String mccMnc,
3412                 int natKeepalive, int preferredIpPortocol) {
3413             final int ipVersion;
3414             final int encapType;
3415             switch (preferredIpPortocol) {
3416                 case PREFERRED_IKE_PROTOCOL_AUTO:
3417                     ipVersion = IkeSessionParams.ESP_IP_VERSION_AUTO;
3418                     encapType = IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
3419                     break;
3420                 case PREFERRED_IKE_PROTOCOL_IPV4_UDP:
3421                     ipVersion = IkeSessionParams.ESP_IP_VERSION_IPV4;
3422                     encapType = IkeSessionParams.ESP_ENCAP_TYPE_UDP;
3423                     break;
3424                 case PREFERRED_IKE_PROTOCOL_IPV6_UDP:
3425                     ipVersion = IkeSessionParams.ESP_IP_VERSION_IPV6;
3426                     encapType = IkeSessionParams.ESP_ENCAP_TYPE_UDP;
3427                     break;
3428                 case PREFERRED_IKE_PROTOCOL_IPV6_ESP:
3429                     ipVersion = IkeSessionParams.ESP_IP_VERSION_IPV6;
3430                     encapType = IkeSessionParams.ESP_ENCAP_TYPE_NONE;
3431                     break;
3432                 default:
3433                     // By default, PREFERRED_IKE_PROTOCOL_IPV4_UDP is used for safety. This is
3434                     // because some carriers' networks do not support IPv6 very well, and using
3435                     // IPv4 can help to prevent problems.
3436                     ipVersion = IkeSessionParams.ESP_IP_VERSION_IPV4;
3437                     encapType = IkeSessionParams.ESP_ENCAP_TYPE_UDP;
3438                     break;
3439             }
3440             return new CarrierConfigInfo(mccMnc, natKeepalive, encapType, ipVersion);
3441         }
3442 
getOrGuessKeepaliveDelaySeconds()3443         private int getOrGuessKeepaliveDelaySeconds() {
3444             if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
3445                 return guessNattKeepaliveTimerForNetwork();
3446             } else if (mProfile.getIkeTunnelConnectionParams() != null) {
3447                 return mProfile.getIkeTunnelConnectionParams()
3448                         .getIkeSessionParams().getNattKeepAliveDelaySeconds();
3449             }
3450             return DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
3451         }
3452 
maybeMigrateIkeSessionAndUpdateVpnTransportInfo( @onNull Network underlyingNetwork)3453         boolean maybeMigrateIkeSessionAndUpdateVpnTransportInfo(
3454                 @NonNull Network underlyingNetwork) {
3455             final int keepaliveDelaySec = getOrGuessKeepaliveDelaySeconds();
3456             final boolean migrated = maybeMigrateIkeSession(underlyingNetwork, keepaliveDelaySec);
3457             if (migrated) {
3458                 updateVpnTransportInfoAndNetCap(keepaliveDelaySec);
3459             }
3460             return migrated;
3461         }
3462 
updateVpnTransportInfoAndNetCap(int keepaliveDelaySec)3463         public void updateVpnTransportInfoAndNetCap(int keepaliveDelaySec) {
3464             final VpnTransportInfo info;
3465             synchronized (Vpn.this) {
3466                 info = new VpnTransportInfo(
3467                         getActiveVpnType(),
3468                         mConfig.session,
3469                         mConfig.allowBypass && !mLockdown,
3470                         areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
3471             }
3472             final boolean ncUpdateRequired = !info.equals(mNetworkCapabilities.getTransportInfo());
3473             if (ncUpdateRequired) {
3474                 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
3475                         .setTransportInfo(info)
3476                         .build();
3477                 mEventChanges.log("[VPNRunner] Update agent caps " + mNetworkCapabilities);
3478                 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
3479             }
3480         }
3481 
maybeMigrateIkeSession(@onNull Network underlyingNetwork, int keepaliveDelaySeconds)3482         private boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork,
3483                 int keepaliveDelaySeconds) {
3484             if (mSession == null || !mMobikeEnabled) return false;
3485 
3486             // IKE session can schedule a migration event only when IKE AUTH is finished
3487             // and mMobikeEnabled is true.
3488             Log.d(TAG, "Migrate IKE Session with token "
3489                     + mCurrentToken
3490                     + " to network "
3491                     + underlyingNetwork);
3492 
3493             final int ipVersion;
3494             final int encapType;
3495             if (mProfile.isAutomaticIpVersionSelectionEnabled()) {
3496                 ipVersion = guessEspIpVersionForNetwork();
3497                 encapType = guessEspEncapTypeForNetwork();
3498             } else if (mProfile.getIkeTunnelConnectionParams() != null) {
3499                 ipVersion = mProfile.getIkeTunnelConnectionParams()
3500                         .getIkeSessionParams().getIpVersion();
3501                 encapType = mProfile.getIkeTunnelConnectionParams()
3502                         .getIkeSessionParams().getEncapType();
3503             } else {
3504                 ipVersion = ESP_IP_VERSION_AUTO;
3505                 encapType = ESP_ENCAP_TYPE_AUTO;
3506             }
3507 
3508             mSession.setNetwork(underlyingNetwork, ipVersion, encapType, keepaliveDelaySeconds);
3509             return true;
3510         }
3511 
startIkeSession(@onNull Network underlyingNetwork)3512         private void startIkeSession(@NonNull Network underlyingNetwork) {
3513             Log.d(TAG, "Start new IKE session on network " + underlyingNetwork);
3514             mEventChanges.log("[IKE] Start IKE session over " + underlyingNetwork);
3515 
3516             try {
3517                 // Clear mInterface to prevent Ikev2VpnRunner being cleared when
3518                 // interfaceRemoved() is called.
3519                 synchronized (Vpn.this) {
3520                     // Ignore stale runner.
3521                     if (mVpnRunner != this) return;
3522 
3523                     mInterface = null;
3524                 }
3525                 // Without MOBIKE, we have no way to seamlessly migrate. Close on old
3526                 // (non-default) network, and start the new one.
3527                 resetIkeState();
3528 
3529                 // TODO: Remove the need for adding two unused addresses with
3530                 // IPsec tunnels.
3531                 final InetAddress address = InetAddress.getLocalHost();
3532 
3533                 // When onChildOpened is called and transforms are applied, it is
3534                 // guaranteed that the underlying network is still "network", because the
3535                 // all the network switch events will be deferred before onChildOpened is
3536                 // called. Thus it is safe to build a mTunnelIface before IKE setup.
3537                 mTunnelIface =
3538                         mIpSecManager.createIpSecTunnelInterface(
3539                                 address /* unused */, address /* unused */, underlyingNetwork);
3540                 NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
3541 
3542                 final int token = ++mCurrentToken;
3543                 mSession =
3544                         mIkev2SessionCreator.createIkeSession(
3545                                 mContext,
3546                                 getIkeSessionParams(underlyingNetwork),
3547                                 getChildSessionParams(),
3548                                 mExecutor,
3549                                 new VpnIkev2Utils.IkeSessionCallbackImpl(
3550                                         TAG, IkeV2VpnRunner.this, token),
3551                                 new VpnIkev2Utils.ChildSessionCallbackImpl(
3552                                         TAG, IkeV2VpnRunner.this, token));
3553                 Log.d(TAG, "IKE session started for token " + token);
3554             } catch (Exception e) {
3555                 Log.i(TAG, "Setup failed for token " + mCurrentToken + ". Aborting", e);
3556                 onSessionLost(mCurrentToken, e);
3557             }
3558         }
3559 
3560         /**
3561          * Schedule starting an IKE session.
3562          * @param delayMs the delay after which to try starting the session. This should be
3563          *                RETRY_DELAY_AUTO_BACKOFF for automatic retries with backoff.
3564          */
scheduleStartIkeSession(final long delayMs)3565         private void scheduleStartIkeSession(final long delayMs) {
3566             if (mScheduledHandleRetryIkeSessionFuture != null) {
3567                 Log.d(TAG, "There is a pending retrying task, skip the new retrying task");
3568                 return;
3569             }
3570             final long retryDelayMs = RETRY_DELAY_AUTO_BACKOFF != delayMs
3571                     ? delayMs
3572                     : mDeps.getNextRetryDelayMs(mRetryCount++);
3573             Log.d(TAG, "Retry new IKE session after " + retryDelayMs + " milliseconds.");
3574             // If the default network is lost during the retry delay, the mActiveNetwork will be
3575             // null, and the new IKE session won't be established until there is a new default
3576             // network bringing up.
3577             mScheduledHandleRetryIkeSessionFuture =
3578                     mExecutor.schedule(() -> {
3579                         startOrMigrateIkeSession(mActiveNetwork);
3580 
3581                         // Reset mScheduledHandleRetryIkeSessionFuture since it's already run on
3582                         // executor thread.
3583                         mScheduledHandleRetryIkeSessionFuture = null;
3584                     }, retryDelayMs, TimeUnit.MILLISECONDS);
3585         }
3586 
significantCapsChange(@ullable final NetworkCapabilities left, @Nullable final NetworkCapabilities right)3587         private boolean significantCapsChange(@Nullable final NetworkCapabilities left,
3588                 @Nullable final NetworkCapabilities right) {
3589             if (left == right) return false;
3590             return null == left
3591                     || null == right
3592                     || !Arrays.equals(left.getTransportTypes(), right.getTransportTypes())
3593                     || !Arrays.equals(left.getCapabilities(), right.getCapabilities())
3594                     || !Arrays.equals(left.getEnterpriseIds(), right.getEnterpriseIds())
3595                     || !Objects.equals(left.getTransportInfo(), right.getTransportInfo())
3596                     || !Objects.equals(left.getAllowedUids(), right.getAllowedUids())
3597                     || !Objects.equals(left.getUnderlyingNetworks(), right.getUnderlyingNetworks())
3598                     || !Objects.equals(left.getNetworkSpecifier(), right.getNetworkSpecifier());
3599         }
3600 
3601         /** Called when the NetworkCapabilities of underlying network is changed */
onDefaultNetworkCapabilitiesChanged(@onNull NetworkCapabilities nc)3602         public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) {
3603             if (significantCapsChange(mUnderlyingNetworkCapabilities, nc)) {
3604                 // TODO : make this log terser
3605                 mEventChanges.log("[UnderlyingNW] Cap changed from "
3606                         + mUnderlyingNetworkCapabilities + " to " + nc);
3607             }
3608             final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities;
3609             mUnderlyingNetworkCapabilities = nc;
3610             if (oldNc == null || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) {
3611                 // A new default network is available, or the subscription has changed.
3612                 // Try to migrate the session, or failing that, start a new one.
3613                 scheduleStartIkeSession(IKE_DELAY_ON_NC_LP_CHANGE_MS);
3614             }
3615         }
3616 
3617         /** Called when the LinkProperties of underlying network is changed */
onDefaultNetworkLinkPropertiesChanged(@onNull LinkProperties lp)3618         public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
3619             final LinkProperties oldLp = mUnderlyingLinkProperties;
3620             mEventChanges.log("[UnderlyingNW] Lp changed from " + oldLp + " to " + lp);
3621             mUnderlyingLinkProperties = lp;
3622             if (oldLp == null || !LinkPropertiesUtils.isIdenticalAllLinkAddresses(oldLp, lp)) {
3623                 // If some of the link addresses changed, the IKE session may need to be migrated
3624                 // or restarted, for example if the available IP families have changed or if the
3625                 // source address used has gone away. See IkeConnectionController#onNetworkSetByUser
3626                 // and IkeConnectionController#selectAndSetRemoteAddress for where this ends up
3627                 // re-evaluating the session.
3628                 scheduleStartIkeSession(IKE_DELAY_ON_NC_LP_CHANGE_MS);
3629             }
3630         }
3631 
onValidationStatus(int status)3632         public void onValidationStatus(int status) {
3633             mEventChanges.log("[Validation] validation status " + status);
3634             if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
3635                 // No data stall now. Reset it.
3636                 mExecutor.execute(() -> {
3637                     mValidationFailRetryCount = 0;
3638                     if (mScheduledHandleDataStallFuture != null) {
3639                         Log.d(TAG, "Recovered from stall. Cancel pending reset action.");
3640                         mScheduledHandleDataStallFuture.cancel(false /* mayInterruptIfRunning */);
3641                         mScheduledHandleDataStallFuture = null;
3642                     }
3643                 });
3644             } else {
3645                 // Skip other invalid status if the scheduled recovery exists.
3646                 if (mScheduledHandleDataStallFuture != null) return;
3647 
3648                 // Trigger network validation on the underlying network to possibly cause system
3649                 // switch default network or try recover if the current default network is broken.
3650                 //
3651                 // For the same underlying network, the first validation result should clarify if
3652                 // it's caused by broken underlying network. So only perform underlying network
3653                 // re-evaluation after first validation failure to prevent extra network resource
3654                 // costs on sending probes.
3655                 if (mValidationFailRetryCount == 0) {
3656                     mConnectivityManager.reportNetworkConnectivity(
3657                             mActiveNetwork, false /* hasConnectivity */);
3658                 }
3659 
3660                 if (mValidationFailRetryCount < MAX_MOBIKE_RECOVERY_ATTEMPT) {
3661                     Log.d(TAG, "Validation failed");
3662 
3663                     // Trigger MOBIKE to recover first.
3664                     mExecutor.schedule(() -> {
3665                         maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
3666                     }, mDeps.getValidationFailRecoveryMs(mValidationFailRetryCount++),
3667                             TimeUnit.MILLISECONDS);
3668                     return;
3669                 }
3670 
3671                 // Data stall is not recovered by MOBIKE. Try to reset session to recover it.
3672                 mScheduledHandleDataStallFuture = mExecutor.schedule(() -> {
3673                     // Only perform the recovery when the network is still bad.
3674                     if (mValidationFailRetryCount > 0) {
3675                         Log.d(TAG, "Reset session to recover stalled network");
3676                         // This will reset old state if it exists.
3677                         startIkeSession(mActiveNetwork);
3678                     }
3679 
3680                     // Reset mScheduledHandleDataStallFuture since it's already run on executor
3681                     // thread.
3682                     mScheduledHandleDataStallFuture = null;
3683                     // TODO: compute the delay based on the last recovery timestamp
3684                 }, mDeps.getValidationFailRecoveryMs(mValidationFailRetryCount++),
3685                         TimeUnit.MILLISECONDS);
3686             }
3687         }
3688 
3689         /**
3690          * Handles loss of the default underlying network
3691          *
3692          * <p>If the IKE Session has mobility, Ikev2VpnRunner will schedule a teardown event with a
3693          * delay so that the IKE Session can migrate if a new network is available soon. Otherwise,
3694          * Ikev2VpnRunner will kill the IKE session and reset the VPN.
3695          *
3696          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3697          * consistency of the Ikev2VpnRunner fields.
3698          */
onDefaultNetworkLost(@onNull Network network)3699         public void onDefaultNetworkLost(@NonNull Network network) {
3700             mEventChanges.log("[UnderlyingNW] Network lost " + network);
3701             // If the default network is torn down, there is no need to call
3702             // startOrMigrateIkeSession() since it will always check if there is an active network
3703             // can be used or not.
3704             cancelRetryNewIkeSessionFuture();
3705 
3706             if (!isActiveNetwork(network)) {
3707                 Log.d(TAG, "onDefaultNetworkLost called for obsolete network " + network);
3708 
3709                 // Do nothing; this signals that either: (1) a new/better Network was found,
3710                 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
3711                 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
3712                 // or an error was encountered somewhere else). In both cases, all resources and
3713                 // sessions are torn down via resetIkeState().
3714                 return;
3715             } else {
3716                 mActiveNetwork = null;
3717                 mUnderlyingNetworkCapabilities = null;
3718                 mUnderlyingLinkProperties = null;
3719             }
3720 
3721             if (mScheduledHandleNetworkLostFuture != null) {
3722                 final IllegalStateException exception =
3723                         new IllegalStateException(
3724                                 "Found a pending mScheduledHandleNetworkLostFuture");
3725                 Log.i(
3726                         TAG,
3727                         "Unexpected error in onDefaultNetworkLost. Tear down session",
3728                         exception);
3729                 handleSessionLost(exception, network);
3730                 return;
3731             }
3732 
3733             Log.d(TAG, "Schedule a delay handleSessionLost for losing network "
3734                             + network
3735                             + " on session with token "
3736                             + mCurrentToken);
3737 
3738             final int token = mCurrentToken;
3739             // Delay the teardown in case a new network will be available soon. For example,
3740             // during handover between two WiFi networks, Android will disconnect from the
3741             // first WiFi and then connects to the second WiFi.
3742             mScheduledHandleNetworkLostFuture =
3743                     mExecutor.schedule(
3744                             () -> {
3745                                 if (isActiveToken(token)) {
3746                                     handleSessionLost(new IkeNetworkLostException(network),
3747                                             network);
3748 
3749                                     synchronized (Vpn.this) {
3750                                         // Ignore stale runner.
3751                                         if (mVpnRunner != this) return;
3752 
3753                                         updateState(DetailedState.DISCONNECTED,
3754                                                 "Network lost");
3755                                     }
3756                                 } else {
3757                                     Log.d(
3758                                             TAG,
3759                                             "Scheduled handleSessionLost fired for "
3760                                                     + "obsolete token "
3761                                                     + token);
3762                                 }
3763 
3764                                 // Reset mScheduledHandleNetworkLostFuture since it's
3765                                 // already run on executor thread.
3766                                 mScheduledHandleNetworkLostFuture = null;
3767                             },
3768                             NETWORK_LOST_TIMEOUT_MS,
3769                             TimeUnit.MILLISECONDS);
3770 
3771         }
3772 
cancelHandleNetworkLostTimeout()3773         private void cancelHandleNetworkLostTimeout() {
3774             if (mScheduledHandleNetworkLostFuture != null) {
3775                 // It does not matter what to put in #cancel(boolean), because it is impossible
3776                 // that the task tracked by mScheduledHandleNetworkLostFuture is
3777                 // in-progress since both that task and onDefaultNetworkChanged are submitted to
3778                 // mExecutor who has only one thread.
3779                 Log.d(TAG, "Cancel the task for handling network lost timeout");
3780                 mScheduledHandleNetworkLostFuture.cancel(false /* mayInterruptIfRunning */);
3781                 mScheduledHandleNetworkLostFuture = null;
3782             }
3783         }
3784 
cancelRetryNewIkeSessionFuture()3785         private void cancelRetryNewIkeSessionFuture() {
3786             if (mScheduledHandleRetryIkeSessionFuture != null) {
3787                 // It does not matter what to put in #cancel(boolean), because it is impossible
3788                 // that the task tracked by mScheduledHandleRetryIkeSessionFuture is
3789                 // in-progress since both that task and onDefaultNetworkChanged are submitted to
3790                 // mExecutor who has only one thread.
3791                 Log.d(TAG, "Cancel the task for handling new ike session timeout");
3792                 mScheduledHandleRetryIkeSessionFuture.cancel(false /* mayInterruptIfRunning */);
3793                 mScheduledHandleRetryIkeSessionFuture = null;
3794             }
3795         }
3796 
3797         /** Marks the state as FAILED, and disconnects. */
markFailedAndDisconnect(Exception exception)3798         private void markFailedAndDisconnect(Exception exception) {
3799             synchronized (Vpn.this) {
3800                 // Ignore stale runner.
3801                 if (mVpnRunner != this) return;
3802 
3803                 updateState(DetailedState.FAILED, exception.getMessage());
3804             }
3805 
3806             clearVpnNetworkPreference(mSessionKey);
3807             disconnectVpnRunner();
3808         }
3809 
3810         /**
3811          * Handles loss of a session
3812          *
3813          * <p>The loss of a session might be due to an onLost() call, the IKE session getting torn
3814          * down for any reason, or an error in updating state (transform application, VPN setup)
3815          *
3816          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3817          * consistency of the Ikev2VpnRunner fields.
3818          */
onSessionLost(int token, @Nullable Exception exception)3819         public void onSessionLost(int token, @Nullable Exception exception) {
3820             mEventChanges.log("[IKE] Session lost on network " + mActiveNetwork
3821                     + (null == exception ? "" : " reason " + exception.getMessage()));
3822             Log.d(TAG, "onSessionLost() called for token " + token);
3823 
3824             if (!isActiveToken(token)) {
3825                 Log.d(TAG, "onSessionLost() called for obsolete token " + token);
3826 
3827                 // Do nothing; this signals that either: (1) a new/better Network was found,
3828                 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in
3829                 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited,
3830                 // or an error was encountered somewhere else). In both cases, all resources and
3831                 // sessions are torn down via resetIkeState().
3832                 return;
3833             }
3834 
3835             handleSessionLost(exception, mActiveNetwork);
3836         }
3837 
handleSessionLost(@ullable Exception exception, @Nullable Network network)3838         private void handleSessionLost(@Nullable Exception exception, @Nullable Network network) {
3839             // Cancel mScheduledHandleNetworkLostFuture if the session it is going to terminate is
3840             // already terminated due to other failures.
3841             cancelHandleNetworkLostTimeout();
3842 
3843             String category = null;
3844             int errorClass = -1;
3845             int errorCode = -1;
3846             if (exception instanceof IllegalArgumentException) {
3847                 // Failed to build IKE/ChildSessionParams; fatal profile configuration error
3848                 markFailedAndDisconnect(exception);
3849                 return;
3850             }
3851 
3852             if (exception instanceof IkeProtocolException) {
3853                 final IkeProtocolException ikeException = (IkeProtocolException) exception;
3854                 category = VpnManager.CATEGORY_EVENT_IKE_ERROR;
3855                 errorCode = ikeException.getErrorType();
3856 
3857                 switch (ikeException.getErrorType()) {
3858                     case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
3859                     case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
3860                     case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
3861                     case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
3862                     case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
3863                     case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
3864                         // All the above failures are configuration errors, and are terminal
3865                         errorClass = VpnManager.ERROR_CLASS_NOT_RECOVERABLE;
3866                         break;
3867                     // All other cases possibly recoverable.
3868                     default:
3869                         errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
3870                 }
3871             } else if (exception instanceof IkeNetworkLostException) {
3872                 category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR;
3873                 errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
3874                 errorCode = VpnManager.ERROR_CODE_NETWORK_LOST;
3875             } else if (exception instanceof IkeNonProtocolException) {
3876                 category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR;
3877                 errorClass = VpnManager.ERROR_CLASS_RECOVERABLE;
3878                 if (exception.getCause() instanceof UnknownHostException) {
3879                     errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST;
3880                 } else if (exception.getCause() instanceof IkeTimeoutException) {
3881                     errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT;
3882                 } else if (exception.getCause() instanceof IOException) {
3883                     errorCode = VpnManager.ERROR_CODE_NETWORK_IO;
3884                 }
3885             } else if (exception != null) {
3886                 Log.wtf(TAG, "onSessionLost: exception = " + exception);
3887             }
3888 
3889             synchronized (Vpn.this) {
3890                 // Ignore stale runner.
3891                 if (mVpnRunner != this) return;
3892 
3893                 if (category != null && isVpnApp(mPackage)) {
3894                     sendEventToVpnManagerApp(category, errorClass, errorCode,
3895                             getPackage(), mSessionKey, makeVpnProfileStateLocked(),
3896                             mActiveNetwork,
3897                             getRedactedNetworkCapabilities(mUnderlyingNetworkCapabilities),
3898                             getRedactedLinkProperties(mUnderlyingLinkProperties));
3899                 }
3900             }
3901 
3902             if (errorClass == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
3903                 markFailedAndDisconnect(exception);
3904                 return;
3905             } else {
3906                 scheduleStartIkeSession(RETRY_DELAY_AUTO_BACKOFF);
3907             }
3908 
3909             // Close all obsolete state, but keep VPN alive incase a usable network comes up.
3910             // (Mirrors VpnService behavior)
3911             Log.d(TAG, "Resetting state for token: " + mCurrentToken);
3912 
3913             synchronized (Vpn.this) {
3914                 // Ignore stale runner.
3915                 if (mVpnRunner != this) return;
3916 
3917                 // Since this method handles non-fatal errors only, set mInterface to null to
3918                 // prevent the NetworkManagementEventObserver from killing this VPN based on the
3919                 // interface going down (which we expect).
3920                 mInterface = null;
3921                 if (mConfig != null) {
3922                     mConfig.interfaze = null;
3923 
3924                     // Set as unroutable to prevent traffic leaking while the interface is down.
3925                     if (mConfig.routes != null) {
3926                         final List<RouteInfo> oldRoutes = new ArrayList<>(mConfig.routes);
3927 
3928                         mConfig.routes.clear();
3929                         for (final RouteInfo route : oldRoutes) {
3930                             mConfig.routes.add(new RouteInfo(route.getDestination(),
3931                                     null /*gateway*/, null /*iface*/, RTN_UNREACHABLE));
3932                         }
3933                         if (mNetworkAgent != null) {
3934                             doSendLinkProperties(mNetworkAgent, makeLinkProperties());
3935                         }
3936                     }
3937                 }
3938             }
3939 
3940             resetIkeState();
3941             if (errorCode != VpnManager.ERROR_CODE_NETWORK_LOST
3942                     // Clear the VPN network preference when the retry delay is higher than 5s.
3943                     // mRetryCount was increased when scheduleRetryNewIkeSession() is called,
3944                     // therefore use mRetryCount - 1 here.
3945                     && mDeps.getNextRetryDelayMs(mRetryCount - 1) > 5_000L) {
3946                 clearVpnNetworkPreference(mSessionKey);
3947             }
3948         }
3949 
3950         /**
3951          * Cleans up all IKE state
3952          *
3953          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3954          * consistency of the Ikev2VpnRunner fields.
3955          */
resetIkeState()3956         private void resetIkeState() {
3957             if (mTunnelIface != null) {
3958                 // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
3959                 mTunnelIface.close();
3960                 mTunnelIface = null;
3961             }
3962             if (mSession != null) {
3963                 mSession.kill(); // Kill here to make sure all resources are released immediately
3964                 mSession = null;
3965             }
3966             mIkeConnectionInfo = null;
3967             mMobikeEnabled = false;
3968         }
3969 
3970         /**
3971          * Disconnects and shuts down this VPN.
3972          *
3973          * <p>This method resets all internal Ikev2VpnRunner state, but unless called via
3974          * VpnRunner#exit(), this Ikev2VpnRunner will still be listed as the active VPN of record
3975          * until the next VPN is started, or the Ikev2VpnRunner is explicitly exited. This is
3976          * necessary to ensure that the detailed state is shown in the Settings VPN menus; if the
3977          * active VPN is cleared, Settings VPNs will not show the resultant state or errors.
3978          *
3979          * <p>This method MUST always be called on the mExecutor thread in order to ensure
3980          * consistency of the Ikev2VpnRunner fields.
3981          */
disconnectVpnRunner()3982         private void disconnectVpnRunner() {
3983             mEventChanges.log("[VPNRunner] Disconnect runner, underlying net " + mActiveNetwork);
3984             mActiveNetwork = null;
3985             mUnderlyingNetworkCapabilities = null;
3986             mUnderlyingLinkProperties = null;
3987             mIsRunning = false;
3988 
3989             resetIkeState();
3990 
3991             if (mCarrierConfigManager != null) {
3992                 mCarrierConfigManager.unregisterCarrierConfigChangeListener(
3993                         mCarrierConfigChangeListener);
3994             }
3995             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
3996 
3997             mExecutor.shutdown();
3998         }
3999 
4000         @Override
exitVpnRunner()4001         public void exitVpnRunner() {
4002             // mSessionKey won't be changed since the Ikev2VpnRunner is created, so it's ok to use
4003             // it outside the mExecutor. And clearing the VPN network preference here can prevent
4004             // the case that the VPN network preference isn't cleared when Ikev2VpnRunner became
4005             // stale.
4006             clearVpnNetworkPreference(mSessionKey);
4007             try {
4008                 mExecutor.execute(() -> {
4009                     disconnectVpnRunner();
4010                 });
4011             } catch (RejectedExecutionException ignored) {
4012                 // The Ikev2VpnRunner has already shut down.
4013             }
4014         }
4015     }
4016 
verifyCallingUidAndPackage(String packageName)4017     private void verifyCallingUidAndPackage(String packageName) {
4018         mDeps.verifyCallingUidAndPackage(mContext, packageName, mUserId);
4019     }
4020 
4021     @VisibleForTesting
getProfileNameForPackage(String packageName)4022     String getProfileNameForPackage(String packageName) {
4023         return Credentials.PLATFORM_VPN + mUserId + "_" + packageName;
4024     }
4025 
4026     @VisibleForTesting
validateRequiredFeatures(VpnProfile profile)4027     void validateRequiredFeatures(VpnProfile profile) {
4028         switch (profile.type) {
4029             case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
4030             case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
4031             case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
4032             case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
4033                 if (!mContext.getPackageManager().hasSystemFeature(
4034                         PackageManager.FEATURE_IPSEC_TUNNELS)) {
4035                     throw new UnsupportedOperationException(
4036                             "Ikev2VpnProfile(s) requires PackageManager.FEATURE_IPSEC_TUNNELS");
4037                 }
4038                 break;
4039             default:
4040                 return;
4041         }
4042     }
4043 
4044     /**
4045      * Stores an app-provisioned VPN profile and returns whether the app is already prepared.
4046      *
4047      * @param packageName the package name of the app provisioning this profile
4048      * @param profile the profile to be stored and provisioned
4049      * @returns whether or not the app has already been granted user consent
4050      */
provisionVpnProfile( @onNull String packageName, @NonNull VpnProfile profile)4051     public synchronized boolean provisionVpnProfile(
4052             @NonNull String packageName, @NonNull VpnProfile profile) {
4053         requireNonNull(packageName, "No package name provided");
4054         requireNonNull(profile, "No profile provided");
4055 
4056         verifyCallingUidAndPackage(packageName);
4057         enforceNotRestrictedUser();
4058         validateRequiredFeatures(profile);
4059 
4060         if (profile.isRestrictedToTestNetworks) {
4061             mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS,
4062                     "Test-mode profiles require the MANAGE_TEST_NETWORKS permission");
4063         }
4064 
4065         final byte[] encodedProfile = profile.encode();
4066         if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) {
4067             throw new IllegalArgumentException("Profile too big");
4068         }
4069 
4070         // Permissions checked during startVpnProfile()
4071         final long token = Binder.clearCallingIdentity();
4072         try {
4073             getVpnProfileStore().put(getProfileNameForPackage(packageName), encodedProfile);
4074         } finally {
4075             Binder.restoreCallingIdentity(token);
4076         }
4077 
4078         // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop.
4079         // This mirrors the prepareAndAuthorize that is used by VpnService.
4080 
4081         // Return whether the app is already pre-consented
4082         return isVpnProfilePreConsented(mContext, packageName);
4083     }
4084 
isCurrentIkev2VpnLocked(@onNull String packageName)4085     private boolean isCurrentIkev2VpnLocked(@NonNull String packageName) {
4086         return isCurrentPreparedPackage(packageName) && isIkev2VpnRunner();
4087     }
4088 
4089     /**
4090      * Deletes an app-provisioned VPN profile.
4091      *
4092      * @param packageName the package name of the app provisioning this profile
4093      */
deleteVpnProfile( @onNull String packageName)4094     public synchronized void deleteVpnProfile(
4095             @NonNull String packageName) {
4096         requireNonNull(packageName, "No package name provided");
4097 
4098         verifyCallingUidAndPackage(packageName);
4099         enforceNotRestrictedUser();
4100 
4101         final long token = Binder.clearCallingIdentity();
4102         try {
4103             // If this profile is providing the current VPN, turn it off, disabling
4104             // always-on as well if enabled.
4105             if (isCurrentIkev2VpnLocked(packageName)) {
4106                 if (mAlwaysOn) {
4107                     // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN).
4108                     setAlwaysOnPackage(null, false, null);
4109                 } else {
4110                     prepareInternal(VpnConfig.LEGACY_VPN);
4111                 }
4112             }
4113 
4114             getVpnProfileStore().remove(getProfileNameForPackage(packageName));
4115         } finally {
4116             Binder.restoreCallingIdentity(token);
4117         }
4118     }
4119 
4120     /**
4121      * Retrieves the VpnProfile.
4122      *
4123      * <p>Must be used only as SYSTEM_UID, otherwise the key/UID pair will not match anything in the
4124      * keystore.
4125      */
4126     @VisibleForTesting
4127     @Nullable
getVpnProfilePrivileged(@onNull String packageName)4128     VpnProfile getVpnProfilePrivileged(@NonNull String packageName) {
4129         if (!mDeps.isCallerSystem()) {
4130             Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID ");
4131             return null;
4132         }
4133 
4134         final byte[] encoded = getVpnProfileStore().get(getProfileNameForPackage(packageName));
4135         if (encoded == null) return null;
4136 
4137         return VpnProfile.decode("" /* Key unused */, encoded);
4138     }
4139 
isIkev2VpnRunner()4140     private boolean isIkev2VpnRunner() {
4141         return (mVpnRunner instanceof IkeV2VpnRunner);
4142     }
4143 
4144     @GuardedBy("this")
4145     @Nullable
getSessionKeyLocked()4146     private String getSessionKeyLocked() {
4147         // Add log for debugging flaky test. b/242833779
4148         final boolean isIkev2VpnRunner = isIkev2VpnRunner();
4149         final String sessionKey =
4150                 isIkev2VpnRunner ? ((IkeV2VpnRunner) mVpnRunner).mSessionKey : null;
4151         Log.d(TAG, "getSessionKeyLocked: isIkev2VpnRunner = " + isIkev2VpnRunner
4152                 + ", sessionKey = " + sessionKey);
4153         return sessionKey;
4154     }
4155 
4156     /**
4157      * Starts an already provisioned VPN Profile, keyed by package name.
4158      *
4159      * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService).
4160      * Privileged (system) callers should use startVpnProfilePrivileged instead. Otherwise the UIDs
4161      * will not match during appop checks.
4162      *
4163      * @param packageName the package name of the app provisioning this profile
4164      */
startVpnProfile(@onNull String packageName)4165     public synchronized String startVpnProfile(@NonNull String packageName) {
4166         requireNonNull(packageName, "No package name provided");
4167 
4168         enforceNotRestrictedUser();
4169 
4170         // Prepare VPN for startup
4171         if (!prepare(packageName, null /* newPackage */, VpnManager.TYPE_VPN_PLATFORM)) {
4172             throw new SecurityException("User consent not granted for package " + packageName);
4173         }
4174 
4175         final long token = Binder.clearCallingIdentity();
4176         try {
4177             final VpnProfile profile = getVpnProfilePrivileged(packageName);
4178             if (profile == null) {
4179                 throw new IllegalArgumentException("No profile found for " + packageName);
4180             }
4181 
4182             startVpnProfilePrivileged(profile, packageName);
4183             if (!isIkev2VpnRunner()) {
4184                 throw new IllegalStateException("mVpnRunner shouldn't be null and should also be "
4185                         + "an instance of Ikev2VpnRunner");
4186             }
4187             return getSessionKeyLocked();
4188         } finally {
4189             Binder.restoreCallingIdentity(token);
4190         }
4191     }
4192 
startVpnProfilePrivileged( @onNull VpnProfile profile, @NonNull String packageName)4193     private synchronized void startVpnProfilePrivileged(
4194             @NonNull VpnProfile profile, @NonNull String packageName) {
4195         // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(),
4196         // by the Setting app via startLegacyVpn(), or by ConnectivityService via
4197         // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the
4198         // nice property of ensuring there are no other VpnRunner instances running.
4199         prepareInternal(packageName);
4200         updateState(DetailedState.CONNECTING, "startPlatformVpn");
4201 
4202         try {
4203             // Build basic config
4204             final VpnConfig config = new VpnConfig();
4205             if (VpnConfig.LEGACY_VPN.equals(packageName)) {
4206                 config.legacy = true;
4207                 config.session = profile.name;
4208                 config.user = profile.key;
4209 
4210                 // TODO: Add support for configuring meteredness via Settings. Until then, use a
4211                 // safe default.
4212                 config.isMetered = true;
4213             } else {
4214                 config.user = packageName;
4215                 config.isMetered = profile.isMetered;
4216             }
4217             config.startTime = SystemClock.elapsedRealtime();
4218             config.proxyInfo = profile.proxy;
4219             config.requiresInternetValidation = profile.requiresInternetValidation;
4220             config.excludeLocalRoutes = profile.excludeLocalRoutes;
4221             config.allowBypass = profile.isBypassable;
4222             config.disallowedApplications = getAppExclusionList(mPackage);
4223             mConfig = config;
4224 
4225             switch (profile.type) {
4226                 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
4227                 case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
4228                 case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
4229                 case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
4230                     mVpnRunner =
4231                             new IkeV2VpnRunner(
4232                                     Ikev2VpnProfile.fromVpnProfile(profile),
4233                                     mDeps.newScheduledThreadPoolExecutor());
4234                     mVpnRunner.start();
4235                     break;
4236                 default:
4237                     mConfig = null;
4238                     updateState(DetailedState.FAILED, "Invalid platform VPN type");
4239                     Log.d(TAG, "Unknown VPN profile type: " + profile.type);
4240                     break;
4241             }
4242 
4243             // Record that the VPN connection is established by an app which uses VpnManager API.
4244             if (!VpnConfig.LEGACY_VPN.equals(packageName)) {
4245                 mAppOpsManager.startOp(
4246                         AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null,
4247                         null);
4248             }
4249         } catch (GeneralSecurityException e) {
4250             // Reset mConfig
4251             mConfig = null;
4252 
4253             updateState(DetailedState.FAILED, "VPN startup failed");
4254             throw new IllegalArgumentException("VPN startup failed", e);
4255         }
4256     }
4257 
4258     @GuardedBy("this")
stopVpnRunnerAndNotifyAppLocked()4259     private void stopVpnRunnerAndNotifyAppLocked() {
4260         // Build intent first because the sessionKey will be reset after performing
4261         // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in
4262         // VpnRunner.exit() to prevent design being changed in the future.
4263         final int ownerUid = mOwnerUID;
4264         Intent intent = null;
4265         if (isVpnApp(mPackage)) {
4266             intent = buildVpnManagerEventIntent(
4267                     VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
4268                     -1 /* errorClass */, -1 /* errorCode*/, mPackage,
4269                     getSessionKeyLocked(), makeVpnProfileStateLocked(),
4270                     null /* underlyingNetwork */, null /* nc */, null /* lp */);
4271         }
4272         // cleanupVpnStateLocked() is called from mVpnRunner.exit()
4273         mVpnRunner.exit();
4274         if (intent != null && isVpnApp(mPackage)) {
4275             notifyVpnManagerVpnStopped(mPackage, ownerUid, intent);
4276         }
4277     }
4278 
4279     /**
4280      * Stops an already running VPN Profile for the given package.
4281      *
4282      * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService).
4283      * Privileged (system) callers should (re-)prepare the LEGACY_VPN instead.
4284      *
4285      * @param packageName the package name of the app provisioning this profile
4286      */
stopVpnProfile(@onNull String packageName)4287     public synchronized void stopVpnProfile(@NonNull String packageName) {
4288         requireNonNull(packageName, "No package name provided");
4289 
4290         enforceNotRestrictedUser();
4291 
4292         // To stop the VPN profile, the caller must be the current prepared package and must be
4293         // running an Ikev2VpnProfile.
4294         if (isCurrentIkev2VpnLocked(packageName)) {
4295             stopVpnRunnerAndNotifyAppLocked();
4296         }
4297     }
4298 
notifyVpnManagerVpnStopped(String packageName, int ownerUID, Intent intent)4299     private synchronized void notifyVpnManagerVpnStopped(String packageName, int ownerUID,
4300             Intent intent) {
4301         mAppOpsManager.finishOp(
4302                 AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, ownerUID, packageName, null);
4303         // The underlying network, NetworkCapabilities and LinkProperties are not
4304         // necessary to send to VPN app since the purpose of this event is to notify
4305         // VPN app that VPN is deactivated by the user.
4306         mEventChanges.log("[VMEvent] " + packageName + " stopped");
4307         sendEventToVpnManagerApp(intent, packageName);
4308     }
4309 
storeAppExclusionList(@onNull String packageName, @NonNull List<String> excludedApps)4310     private boolean storeAppExclusionList(@NonNull String packageName,
4311             @NonNull List<String> excludedApps) {
4312         byte[] data;
4313         try {
4314             final PersistableBundle bundle = PersistableBundleUtils.fromList(
4315                     excludedApps, PersistableBundleUtils.STRING_SERIALIZER);
4316             data = PersistableBundleUtils.toDiskStableBytes(bundle);
4317         } catch (IOException e) {
4318             Log.e(TAG, "problem writing into stream", e);
4319             return false;
4320         }
4321 
4322         final long oldId = Binder.clearCallingIdentity();
4323         try {
4324             getVpnProfileStore().put(getVpnAppExcludedForPackage(packageName), data);
4325         } finally {
4326             Binder.restoreCallingIdentity(oldId);
4327         }
4328         return true;
4329     }
4330 
4331     @VisibleForTesting
getVpnAppExcludedForPackage(String packageName)4332     String getVpnAppExcludedForPackage(String packageName) {
4333         return VPN_APP_EXCLUDED + mUserId + "_" + packageName;
4334     }
4335 
4336     /**
4337      * Set the application exclusion list for the specified VPN profile.
4338      *
4339      * @param packageName the package name of the app provisioning this profile
4340      * @param excludedApps the list of excluded packages
4341      *
4342      * @return whether setting the list is successful or not
4343      */
setAppExclusionList(@onNull String packageName, @NonNull List<String> excludedApps)4344     public synchronized boolean setAppExclusionList(@NonNull String packageName,
4345             @NonNull List<String> excludedApps) {
4346         enforceNotRestrictedUser();
4347         if (!storeAppExclusionList(packageName, excludedApps)) return false;
4348 
4349         updateAppExclusionList(excludedApps);
4350 
4351         return true;
4352     }
4353 
4354     /**
4355      * Triggers an update of the VPN network's excluded UIDs if a VPN is running.
4356      */
refreshPlatformVpnAppExclusionList()4357     public synchronized void refreshPlatformVpnAppExclusionList() {
4358         updateAppExclusionList(getAppExclusionList(mPackage));
4359     }
4360 
updateAppExclusionList(@onNull List<String> excludedApps)4361     private synchronized void updateAppExclusionList(@NonNull List<String> excludedApps) {
4362         // Re-build and update NetworkCapabilities via NetworkAgent.
4363         if (mNetworkAgent != null) {
4364             // Only update the platform VPN
4365             if (isIkev2VpnRunner()) {
4366                 mConfig.disallowedApplications = List.copyOf(excludedApps);
4367                 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
4368                         .setUids(createUserAndRestrictedProfilesRanges(
4369                                 mUserId, null /* allowedApplications */, excludedApps))
4370                         .build();
4371                 setVpnNetworkPreference(getSessionKeyLocked(),
4372                         createUserAndRestrictedProfilesRanges(mUserId,
4373                                 mConfig.allowedApplications, mConfig.disallowedApplications));
4374                 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
4375             }
4376         }
4377     }
4378 
4379     /**
4380      * Gets the application exclusion list for the specified VPN profile.
4381      *
4382      * @param packageName the package name of the app provisioning this profile
4383      * @return the list of excluded packages for the specified VPN profile or empty list if there is
4384      *         no provisioned VPN profile.
4385      */
4386     @NonNull
getAppExclusionList(@onNull String packageName)4387     public synchronized List<String> getAppExclusionList(@NonNull String packageName) {
4388         final long oldId = Binder.clearCallingIdentity();
4389         try {
4390             final byte[] bytes = getVpnProfileStore().get(getVpnAppExcludedForPackage(packageName));
4391 
4392             if (bytes == null || bytes.length == 0) return new ArrayList<>();
4393 
4394             final PersistableBundle bundle = PersistableBundleUtils.fromDiskStableBytes(bytes);
4395             return PersistableBundleUtils.toList(bundle, STRING_DESERIALIZER);
4396         } catch (IOException e) {
4397             Log.e(TAG, "problem reading from stream", e);
4398         }  finally {
4399             Binder.restoreCallingIdentity(oldId);
4400         }
4401 
4402         return new ArrayList<>();
4403     }
4404 
getStateFromLegacyState(int legacyState)4405     private @VpnProfileState.State int getStateFromLegacyState(int legacyState) {
4406         switch (legacyState) {
4407             case LegacyVpnInfo.STATE_CONNECTING:
4408                 return VpnProfileState.STATE_CONNECTING;
4409             case LegacyVpnInfo.STATE_CONNECTED:
4410                 return VpnProfileState.STATE_CONNECTED;
4411             case LegacyVpnInfo.STATE_DISCONNECTED:
4412                 return VpnProfileState.STATE_DISCONNECTED;
4413             case LegacyVpnInfo.STATE_FAILED:
4414                 return VpnProfileState.STATE_FAILED;
4415             default:
4416                 Log.wtf(TAG, "Unhandled state " + legacyState
4417                         + ", treat it as STATE_DISCONNECTED");
4418                 return VpnProfileState.STATE_DISCONNECTED;
4419         }
4420     }
4421 
4422     @GuardedBy("this")
4423     @NonNull
makeVpnProfileStateLocked()4424     private VpnProfileState makeVpnProfileStateLocked() {
4425         return new VpnProfileState(getStateFromLegacyState(mLegacyState),
4426                 isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown);
4427     }
4428 
4429     @NonNull
makeDisconnectedVpnProfileState()4430     private VpnProfileState makeDisconnectedVpnProfileState() {
4431         return new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, null /* sessionKey */,
4432                 false /* alwaysOn */, false /* lockdown */);
4433     }
4434 
4435     /**
4436      * Retrieve the VpnProfileState for the profile provisioned by the given package.
4437      *
4438      * @return the VpnProfileState with current information, or null if there was no profile
4439      *         provisioned and started by the given package.
4440      */
4441     @Nullable
getProvisionedVpnProfileState( @onNull String packageName)4442     public synchronized VpnProfileState getProvisionedVpnProfileState(
4443             @NonNull String packageName) {
4444         requireNonNull(packageName, "No package name provided");
4445         enforceNotRestrictedUser();
4446         return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
4447     }
4448 
4449     /** Proxy to allow different testing setups */
4450     // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when
4451     // NetworkAgent#sendLinkProperties can be un-finalized.
doSendLinkProperties( @onNull NetworkAgent agent, @NonNull LinkProperties lp)4452     private static void doSendLinkProperties(
4453             @NonNull NetworkAgent agent, @NonNull LinkProperties lp) {
4454         if (agent instanceof VpnNetworkAgentWrapper) {
4455             ((VpnNetworkAgentWrapper) agent).doSendLinkProperties(lp);
4456         } else {
4457             agent.sendLinkProperties(lp);
4458         }
4459     }
4460 
4461     /** Proxy to allow different testing setups */
4462     // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when
4463     // NetworkAgent#sendNetworkCapabilities can be un-finalized.
doSendNetworkCapabilities( @onNull NetworkAgent agent, @NonNull NetworkCapabilities nc)4464     private static void doSendNetworkCapabilities(
4465             @NonNull NetworkAgent agent, @NonNull NetworkCapabilities nc) {
4466         if (agent instanceof VpnNetworkAgentWrapper) {
4467             ((VpnNetworkAgentWrapper) agent).doSendNetworkCapabilities(nc);
4468         } else {
4469             agent.sendNetworkCapabilities(nc);
4470         }
4471     }
4472 
4473     /** Proxy to allow different testing setups */
4474     // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when
4475     // NetworkAgent#setUnderlyingNetworks can be un-finalized.
doSetUnderlyingNetworks( @onNull NetworkAgent agent, @NonNull List<Network> networks)4476     private void doSetUnderlyingNetworks(
4477             @NonNull NetworkAgent agent, @NonNull List<Network> networks) {
4478         logUnderlyNetworkChanges(networks);
4479 
4480         if (agent instanceof VpnNetworkAgentWrapper) {
4481             ((VpnNetworkAgentWrapper) agent).doSetUnderlyingNetworks(networks);
4482         } else {
4483             agent.setUnderlyingNetworks(networks);
4484         }
4485     }
4486 
4487     /**
4488      * Proxy to allow testing
4489      *
4490      * @hide
4491      */
4492     // TODO: b/240492694 Remove VpnNetworkAgentWrapper when NetworkAgent's methods can be
4493     // un-finalized.
4494     @VisibleForTesting
4495     public static class VpnNetworkAgentWrapper extends NetworkAgent {
4496         private final ValidationStatusCallback mCallback;
4497         /** Create an VpnNetworkAgentWrapper */
VpnNetworkAgentWrapper( @onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider, @Nullable ValidationStatusCallback callback)4498         public VpnNetworkAgentWrapper(
4499                 @NonNull Context context,
4500                 @NonNull Looper looper,
4501                 @NonNull String logTag,
4502                 @NonNull NetworkCapabilities nc,
4503                 @NonNull LinkProperties lp,
4504                 @NonNull NetworkScore score,
4505                 @NonNull NetworkAgentConfig config,
4506                 @Nullable NetworkProvider provider,
4507                 @Nullable ValidationStatusCallback callback) {
4508             super(context, looper, logTag, nc, lp, score, config, provider);
4509             mCallback = callback;
4510         }
4511 
4512         /** Update the LinkProperties */
doSendLinkProperties(@onNull LinkProperties lp)4513         public void doSendLinkProperties(@NonNull LinkProperties lp) {
4514             sendLinkProperties(lp);
4515         }
4516 
4517         /** Update the NetworkCapabilities */
doSendNetworkCapabilities(@onNull NetworkCapabilities nc)4518         public void doSendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
4519             sendNetworkCapabilities(nc);
4520         }
4521 
4522         /** Set the underlying networks */
doSetUnderlyingNetworks(@onNull List<Network> networks)4523         public void doSetUnderlyingNetworks(@NonNull List<Network> networks) {
4524             setUnderlyingNetworks(networks);
4525         }
4526 
4527         @Override
onNetworkUnwanted()4528         public void onNetworkUnwanted() {
4529             // We are user controlled, not driven by NetworkRequest.
4530         }
4531 
4532         @Override
onValidationStatus(int status, Uri redirectUri)4533         public void onValidationStatus(int status, Uri redirectUri) {
4534             if (mCallback != null) {
4535                 mCallback.onValidationStatus(status);
4536             }
4537         }
4538     }
4539 
4540     /**
4541      * Proxy to allow testing
4542      *
4543      * @hide
4544      */
4545     @VisibleForTesting
4546     public static class IkeSessionWrapper {
4547         private final IkeSession mImpl;
4548 
4549         /** Create an IkeSessionWrapper */
IkeSessionWrapper(IkeSession session)4550         public IkeSessionWrapper(IkeSession session) {
4551             mImpl = session;
4552         }
4553 
4554         /** Update the underlying network of the IKE Session */
setNetwork(@onNull Network network, int ipVersion, int encapType, int keepaliveDelaySeconds)4555         public void setNetwork(@NonNull Network network, int ipVersion, int encapType,
4556                 int keepaliveDelaySeconds) {
4557             mImpl.setNetwork(network, ipVersion, encapType, keepaliveDelaySeconds);
4558         }
4559 
4560         /** Set the underpinned network */
setUnderpinnedNetwork(@onNull Network underpinnedNetwork)4561         public void setUnderpinnedNetwork(@NonNull Network underpinnedNetwork) {
4562             mImpl.setUnderpinnedNetwork(underpinnedNetwork);
4563         }
4564 
4565         /** Forcibly terminate the IKE Session */
kill()4566         public void kill() {
4567             mImpl.kill();
4568         }
4569     }
4570 
4571     /**
4572      * Proxy to allow testing
4573      *
4574      * @hide
4575      */
4576     @VisibleForTesting
4577     public static class Ikev2SessionCreator {
4578         /** Creates a IKE session */
createIkeSession( @onNull Context context, @NonNull IkeSessionParams ikeSessionParams, @NonNull ChildSessionParams firstChildSessionParams, @NonNull Executor userCbExecutor, @NonNull IkeSessionCallback ikeSessionCallback, @NonNull ChildSessionCallback firstChildSessionCallback)4579         public IkeSessionWrapper createIkeSession(
4580                 @NonNull Context context,
4581                 @NonNull IkeSessionParams ikeSessionParams,
4582                 @NonNull ChildSessionParams firstChildSessionParams,
4583                 @NonNull Executor userCbExecutor,
4584                 @NonNull IkeSessionCallback ikeSessionCallback,
4585                 @NonNull ChildSessionCallback firstChildSessionCallback) {
4586             return new IkeSessionWrapper(
4587                     new IkeSession(
4588                             context,
4589                             ikeSessionParams,
4590                             firstChildSessionParams,
4591                             userCbExecutor,
4592                             ikeSessionCallback,
4593                             firstChildSessionCallback));
4594         }
4595     }
4596 
4597     /**
4598      * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999.
4599      */
4600     @VisibleForTesting
createUidRangeForUser(int userId)4601     static Range<Integer> createUidRangeForUser(int userId) {
4602         return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
4603     }
4604 
getVpnManagerEventClassName(int code)4605     private String getVpnManagerEventClassName(int code) {
4606         switch (code) {
4607             case VpnManager.ERROR_CLASS_NOT_RECOVERABLE:
4608                 return "ERROR_CLASS_NOT_RECOVERABLE";
4609             case VpnManager.ERROR_CLASS_RECOVERABLE:
4610                 return "ERROR_CLASS_RECOVERABLE";
4611             default:
4612                 return "UNKNOWN_CLASS";
4613         }
4614     }
4615 
getVpnManagerEventErrorName(int code)4616     private String getVpnManagerEventErrorName(int code) {
4617         switch (code) {
4618             case VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST:
4619                 return "ERROR_CODE_NETWORK_UNKNOWN_HOST";
4620             case VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT:
4621                 return "ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT";
4622             case VpnManager.ERROR_CODE_NETWORK_IO:
4623                 return "ERROR_CODE_NETWORK_IO";
4624             case VpnManager.ERROR_CODE_NETWORK_LOST:
4625                 return "ERROR_CODE_NETWORK_LOST";
4626             default:
4627                 return "UNKNOWN_ERROR";
4628         }
4629     }
4630 
4631     /** Dumps VPN state. */
dump(IndentingPrintWriter pw)4632     public void dump(IndentingPrintWriter pw) {
4633         synchronized (Vpn.this) {
4634             pw.println("Active package name: " + mPackage);
4635             pw.println("Active vpn type: " + getActiveVpnType());
4636             pw.println("NetworkCapabilities: " + mNetworkCapabilities);
4637             if (isIkev2VpnRunner()) {
4638                 final IkeV2VpnRunner runner = ((IkeV2VpnRunner) mVpnRunner);
4639                 pw.println("SessionKey: " + runner.mSessionKey);
4640                 pw.println("MOBIKE " + (runner.mMobikeEnabled ? "enabled" : "disabled"));
4641                 pw.println("Profile: " + runner.mProfile);
4642                 pw.println("Token: " + runner.mCurrentToken);
4643                 pw.println("Validation failed retry count:" + runner.mValidationFailRetryCount);
4644                 if (runner.mScheduledHandleDataStallFuture != null) {
4645                     pw.println("Reset session scheduled");
4646                 }
4647             }
4648             pw.println();
4649             pw.println("mCachedCarrierConfigInfoPerSubId=" + mCachedCarrierConfigInfoPerSubId);
4650 
4651             pw.println("mEventChanges (most recent first):");
4652             pw.increaseIndent();
4653             mEventChanges.reverseDump(pw);
4654             pw.decreaseIndent();
4655         }
4656     }
4657 
getCellSubIdForNetworkCapabilities(@ullable NetworkCapabilities nc)4658     private static int getCellSubIdForNetworkCapabilities(@Nullable NetworkCapabilities nc) {
4659         if (nc == null) return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
4660 
4661         if (!nc.hasTransport(TRANSPORT_CELLULAR)) {
4662             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
4663         }
4664 
4665         final NetworkSpecifier specifier = nc.getNetworkSpecifier();
4666         if (specifier instanceof TelephonyNetworkSpecifier) {
4667             return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
4668         }
4669 
4670         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
4671     }
4672 }
4673