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