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