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