• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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;
18 
19 import static android.Manifest.permission.NETWORK_STACK;
20 
21 import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.net.ConnectivityManager;
32 import android.net.INetd;
33 import android.net.IVpnManager;
34 import android.net.LinkProperties;
35 import android.net.Network;
36 import android.net.NetworkStack;
37 import android.net.UnderlyingNetworkInfo;
38 import android.net.Uri;
39 import android.net.VpnManager;
40 import android.net.VpnService;
41 import android.net.util.NetdService;
42 import android.os.Binder;
43 import android.os.Build;
44 import android.os.Handler;
45 import android.os.HandlerThread;
46 import android.os.INetworkManagementService;
47 import android.os.ParcelFileDescriptor;
48 import android.os.Process;
49 import android.os.ServiceManager;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.security.Credentials;
53 import android.text.TextUtils;
54 import android.util.Log;
55 import android.util.SparseArray;
56 
57 import com.android.internal.annotations.GuardedBy;
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.net.LegacyVpnInfo;
60 import com.android.internal.net.VpnConfig;
61 import com.android.internal.net.VpnProfile;
62 import com.android.internal.util.DumpUtils;
63 import com.android.internal.util.IndentingPrintWriter;
64 import com.android.server.connectivity.Vpn;
65 import com.android.server.connectivity.VpnProfileStore;
66 import com.android.server.net.LockdownVpnTracker;
67 
68 import java.io.FileDescriptor;
69 import java.io.PrintWriter;
70 import java.util.List;
71 
72 /**
73  * Service that tracks and manages VPNs, and backs the VpnService and VpnManager APIs.
74  * @hide
75  */
76 public class VpnManagerService extends IVpnManager.Stub {
77     private static final String TAG = VpnManagerService.class.getSimpleName();
78 
79     @VisibleForTesting
80     protected final HandlerThread mHandlerThread;
81     private final Handler mHandler;
82 
83     private final Context mContext;
84     private final Context mUserAllContext;
85 
86     private final Dependencies mDeps;
87 
88     private final ConnectivityManager mCm;
89     private final VpnProfileStore mVpnProfileStore;
90     private final INetworkManagementService mNMS;
91     private final INetd mNetd;
92     private final UserManager mUserManager;
93 
94     @VisibleForTesting
95     @GuardedBy("mVpns")
96     protected final SparseArray<Vpn> mVpns = new SparseArray<>();
97 
98     // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
99     // a direct call to LockdownVpnTracker.isEnabled().
100     @GuardedBy("mVpns")
101     private boolean mLockdownEnabled;
102     @GuardedBy("mVpns")
103     private LockdownVpnTracker mLockdownTracker;
104 
105     /**
106      * Dependencies of VpnManager, for injection in tests.
107      */
108     @VisibleForTesting
109     public static class Dependencies {
110         /** Returns the calling UID of an IPC. */
getCallingUid()111         public int getCallingUid() {
112             return Binder.getCallingUid();
113         }
114 
115         /** Creates a HandlerThread to be used by this class. */
makeHandlerThread()116         public HandlerThread makeHandlerThread() {
117             return new HandlerThread("VpnManagerService");
118         }
119 
120         /** Return the VpnProfileStore to be used by this class */
getVpnProfileStore()121         public VpnProfileStore getVpnProfileStore() {
122             return new VpnProfileStore();
123         }
124 
getNetd()125         public INetd getNetd() {
126             return NetdService.getInstance();
127         }
128 
getINetworkManagementService()129         public INetworkManagementService getINetworkManagementService() {
130             return INetworkManagementService.Stub.asInterface(
131                     ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
132         }
133     }
134 
VpnManagerService(Context context, Dependencies deps)135     public VpnManagerService(Context context, Dependencies deps) {
136         mContext = context;
137         mDeps = deps;
138         mHandlerThread = mDeps.makeHandlerThread();
139         mHandlerThread.start();
140         mHandler = mHandlerThread.getThreadHandler();
141         mVpnProfileStore = mDeps.getVpnProfileStore();
142         mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
143         mCm = mContext.getSystemService(ConnectivityManager.class);
144         mNMS = mDeps.getINetworkManagementService();
145         mNetd = mDeps.getNetd();
146         mUserManager = mContext.getSystemService(UserManager.class);
147         registerReceivers();
148         log("VpnManagerService starting up");
149     }
150 
151     /** Creates a new VpnManagerService */
create(Context context)152     public static VpnManagerService create(Context context) {
153         return new VpnManagerService(context, new Dependencies());
154     }
155 
156     /** Informs the service that the system is ready. */
systemReady()157     public void systemReady() {
158         // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
159         // for user to unlock device too.
160         updateLockdownVpn();
161     }
162 
163     @Override
164     /** Dumps service state. */
dump(@onNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args)165     protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
166             @Nullable String[] args) {
167         if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
168         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
169         pw.println("VPNs:");
170         pw.increaseIndent();
171         synchronized (mVpns) {
172             for (int i = 0; i < mVpns.size(); i++) {
173                 pw.println(mVpns.keyAt(i) + ": " + mVpns.valueAt(i).getPackage());
174             }
175             pw.decreaseIndent();
176         }
177     }
178 
179     /**
180      * Prepare for a VPN application.
181      * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
182      * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
183      *
184      * @param oldPackage Package name of the application which currently controls VPN, which will
185      *                   be replaced. If there is no such application, this should should either be
186      *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
187      * @param newPackage Package name of the application which should gain control of VPN, or
188      *                   {@code null} to disable.
189      * @param userId User for whom to prepare the new VPN.
190      *
191      * @hide
192      */
193     @Override
prepareVpn(@ullable String oldPackage, @Nullable String newPackage, int userId)194     public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
195             int userId) {
196         enforceCrossUserPermission(userId);
197 
198         synchronized (mVpns) {
199             throwIfLockdownEnabled();
200             Vpn vpn = mVpns.get(userId);
201             if (vpn != null) {
202                 return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
203             } else {
204                 return false;
205             }
206         }
207     }
208 
209     /**
210      * Set whether the VPN package has the ability to launch VPNs without user intervention. This
211      * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
212      * class. If the caller is not {@code userId}, {@link
213      * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
214      *
215      * @param packageName The package for which authorization state should change.
216      * @param userId User for whom {@code packageName} is installed.
217      * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
218      *     permissions should be granted. When unauthorizing an app, {@link
219      *     VpnManager.TYPE_VPN_NONE} should be used.
220      * @hide
221      */
222     @Override
setVpnPackageAuthorization( String packageName, int userId, @VpnManager.VpnType int vpnType)223     public void setVpnPackageAuthorization(
224             String packageName, int userId, @VpnManager.VpnType int vpnType) {
225         enforceCrossUserPermission(userId);
226 
227         synchronized (mVpns) {
228             Vpn vpn = mVpns.get(userId);
229             if (vpn != null) {
230                 vpn.setPackageAuthorization(packageName, vpnType);
231             }
232         }
233     }
234 
235     /**
236      * Configure a TUN interface and return its file descriptor. Parameters
237      * are encoded and opaque to this class. This method is used by VpnBuilder
238      * and not available in VpnManager. Permissions are checked in
239      * Vpn class.
240      * @hide
241      */
242     @Override
establishVpn(VpnConfig config)243     public ParcelFileDescriptor establishVpn(VpnConfig config) {
244         int user = UserHandle.getUserId(mDeps.getCallingUid());
245         synchronized (mVpns) {
246             throwIfLockdownEnabled();
247             return mVpns.get(user).establish(config);
248         }
249     }
250 
251     @Override
addVpnAddress(String address, int prefixLength)252     public boolean addVpnAddress(String address, int prefixLength) {
253         int user = UserHandle.getUserId(mDeps.getCallingUid());
254         synchronized (mVpns) {
255             throwIfLockdownEnabled();
256             return mVpns.get(user).addAddress(address, prefixLength);
257         }
258     }
259 
260     @Override
removeVpnAddress(String address, int prefixLength)261     public boolean removeVpnAddress(String address, int prefixLength) {
262         int user = UserHandle.getUserId(mDeps.getCallingUid());
263         synchronized (mVpns) {
264             throwIfLockdownEnabled();
265             return mVpns.get(user).removeAddress(address, prefixLength);
266         }
267     }
268 
269     @Override
setUnderlyingNetworksForVpn(Network[] networks)270     public boolean setUnderlyingNetworksForVpn(Network[] networks) {
271         int user = UserHandle.getUserId(mDeps.getCallingUid());
272         final boolean success;
273         synchronized (mVpns) {
274             success = mVpns.get(user).setUnderlyingNetworks(networks);
275         }
276         return success;
277     }
278 
279     /**
280      * Stores the given VPN profile based on the provisioning package name.
281      *
282      * <p>If there is already a VPN profile stored for the provisioning package, this call will
283      * overwrite the profile.
284      *
285      * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
286      * exclusively by the Settings app, and passed into the platform at startup time.
287      *
288      * @return {@code true} if user consent has already been granted, {@code false} otherwise.
289      * @hide
290      */
291     @Override
provisionVpnProfile(@onNull VpnProfile profile, @NonNull String packageName)292     public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
293         final int user = UserHandle.getUserId(mDeps.getCallingUid());
294         synchronized (mVpns) {
295             return mVpns.get(user).provisionVpnProfile(packageName, profile);
296         }
297     }
298 
299     /**
300      * Deletes the stored VPN profile for the provisioning package
301      *
302      * <p>If there are no profiles for the given package, this method will silently succeed.
303      *
304      * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
305      * exclusively by the Settings app, and passed into the platform at startup time.
306      *
307      * @hide
308      */
309     @Override
deleteVpnProfile(@onNull String packageName)310     public void deleteVpnProfile(@NonNull String packageName) {
311         final int user = UserHandle.getUserId(mDeps.getCallingUid());
312         synchronized (mVpns) {
313             mVpns.get(user).deleteVpnProfile(packageName);
314         }
315     }
316 
317     // TODO : Move to a static lib to factorize with Vpn.java
getAppUid(final String app, final int userId)318     private int getAppUid(final String app, final int userId) {
319         final PackageManager pm = mContext.getPackageManager();
320         final long token = Binder.clearCallingIdentity();
321         try {
322             return pm.getPackageUidAsUser(app, userId);
323         } catch (NameNotFoundException e) {
324             return -1;
325         } finally {
326             Binder.restoreCallingIdentity(token);
327         }
328     }
329 
verifyCallingUidAndPackage(String packageName, int callingUid)330     private void verifyCallingUidAndPackage(String packageName, int callingUid) {
331         final int userId = UserHandle.getUserId(callingUid);
332         if (getAppUid(packageName, userId) != callingUid) {
333             throw new SecurityException(packageName + " does not belong to uid " + callingUid);
334         }
335     }
336 
337     /**
338      * Starts the VPN based on the stored profile for the given package
339      *
340      * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
341      * exclusively by the Settings app, and passed into the platform at startup time.
342      *
343      * @throws IllegalArgumentException if no profile was found for the given package name.
344      * @hide
345      */
346     @Override
startVpnProfile(@onNull String packageName)347     public void startVpnProfile(@NonNull String packageName) {
348         final int callingUid = Binder.getCallingUid();
349         verifyCallingUidAndPackage(packageName, callingUid);
350         final int user = UserHandle.getUserId(callingUid);
351         synchronized (mVpns) {
352             throwIfLockdownEnabled();
353             mVpns.get(user).startVpnProfile(packageName);
354         }
355     }
356 
357     /**
358      * Stops the Platform VPN if the provided package is running one.
359      *
360      * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
361      * exclusively by the Settings app, and passed into the platform at startup time.
362      *
363      * @hide
364      */
365     @Override
stopVpnProfile(@onNull String packageName)366     public void stopVpnProfile(@NonNull String packageName) {
367         final int callingUid = Binder.getCallingUid();
368         verifyCallingUidAndPackage(packageName, callingUid);
369         final int user = UserHandle.getUserId(callingUid);
370         synchronized (mVpns) {
371             mVpns.get(user).stopVpnProfile(packageName);
372         }
373     }
374 
375     /**
376      * Start legacy VPN, controlling native daemons as needed. Creates a
377      * secondary thread to perform connection work, returning quickly.
378      *
379      * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the
380      * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be
381      * thrown.
382      */
383     @SuppressWarnings("AndroidFrameworkCompatChange")  // This is not an app-visible API.
384     @Override
startLegacyVpn(VpnProfile profile)385     public void startLegacyVpn(VpnProfile profile) {
386         if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.S
387                 && VpnProfile.isLegacyType(profile.type)) {
388             throw new UnsupportedOperationException("Legacy VPN is deprecated");
389         }
390         int user = UserHandle.getUserId(mDeps.getCallingUid());
391         // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
392         // the code might not work well since getActiveNetwork might return null if the uid is
393         // blocked by NetworkPolicyManagerService.
394         final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork());
395         if (egress == null) {
396             throw new IllegalStateException("Missing active network connection");
397         }
398         synchronized (mVpns) {
399             throwIfLockdownEnabled();
400             mVpns.get(user).startLegacyVpn(profile, null /* underlying */, egress);
401         }
402     }
403 
404     /**
405      * Return the information of the ongoing legacy VPN. This method is used
406      * by VpnSettings and not available in ConnectivityManager. Permissions
407      * are checked in Vpn class.
408      */
409     @Override
getLegacyVpnInfo(int userId)410     public LegacyVpnInfo getLegacyVpnInfo(int userId) {
411         enforceCrossUserPermission(userId);
412 
413         synchronized (mVpns) {
414             return mVpns.get(userId).getLegacyVpnInfo();
415         }
416     }
417 
418     /**
419      * Returns the information of the ongoing VPN for {@code userId}. This method is used by
420      * VpnDialogs and not available in ConnectivityManager.
421      * Permissions are checked in Vpn class.
422      * @hide
423      */
424     @Override
getVpnConfig(int userId)425     public VpnConfig getVpnConfig(int userId) {
426         enforceCrossUserPermission(userId);
427         synchronized (mVpns) {
428             Vpn vpn = mVpns.get(userId);
429             if (vpn != null) {
430                 return vpn.getVpnConfig();
431             } else {
432                 return null;
433             }
434         }
435     }
436 
isLockdownVpnEnabled()437     private boolean isLockdownVpnEnabled() {
438         return mVpnProfileStore.get(Credentials.LOCKDOWN_VPN) != null;
439     }
440 
441     @Override
updateLockdownVpn()442     public boolean updateLockdownVpn() {
443         // Allow the system UID for the system server and for Settings.
444         // Also, for unit tests, allow the process that ConnectivityService is running in.
445         if (mDeps.getCallingUid() != Process.SYSTEM_UID
446                 && Binder.getCallingPid() != Process.myPid()) {
447             logw("Lockdown VPN only available to system process or AID_SYSTEM");
448             return false;
449         }
450 
451         synchronized (mVpns) {
452             // Tear down existing lockdown if profile was removed
453             mLockdownEnabled = isLockdownVpnEnabled();
454             if (!mLockdownEnabled) {
455                 setLockdownTracker(null);
456                 return true;
457             }
458 
459             byte[] profileTag = mVpnProfileStore.get(Credentials.LOCKDOWN_VPN);
460             if (profileTag == null) {
461                 loge("Lockdown VPN configured but cannot be read from keystore");
462                 return false;
463             }
464             String profileName = new String(profileTag);
465             final VpnProfile profile = VpnProfile.decode(
466                     profileName, mVpnProfileStore.get(Credentials.VPN + profileName));
467             if (profile == null) {
468                 loge("Lockdown VPN configured invalid profile " + profileName);
469                 setLockdownTracker(null);
470                 return true;
471             }
472             int user = UserHandle.getUserId(mDeps.getCallingUid());
473             Vpn vpn = mVpns.get(user);
474             if (vpn == null) {
475                 logw("VPN for user " + user + " not ready yet. Skipping lockdown");
476                 return false;
477             }
478             setLockdownTracker(
479                     new LockdownVpnTracker(mContext, mHandler, vpn,  profile));
480         }
481 
482         return true;
483     }
484 
485     /**
486      * Internally set new {@link LockdownVpnTracker}, shutting down any existing
487      * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
488      */
489     @GuardedBy("mVpns")
setLockdownTracker(LockdownVpnTracker tracker)490     private void setLockdownTracker(LockdownVpnTracker tracker) {
491         // Shutdown any existing tracker
492         final LockdownVpnTracker existing = mLockdownTracker;
493         // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
494         // necessary onBlockedStatusChanged callbacks.
495         mLockdownTracker = null;
496         if (existing != null) {
497             existing.shutdown();
498         }
499 
500         if (tracker != null) {
501             mLockdownTracker = tracker;
502             mLockdownTracker.init();
503         }
504     }
505 
506     /**
507      * Throws if there is any currently running, always-on Legacy VPN.
508      *
509      * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
510      * running across the entire system. Tracking for app-based VPNs is done on a per-user,
511      * per-package basis in Vpn.java
512      */
513     @GuardedBy("mVpns")
throwIfLockdownEnabled()514     private void throwIfLockdownEnabled() {
515         if (mLockdownEnabled) {
516             throw new IllegalStateException("Unavailable in lockdown mode");
517         }
518     }
519 
520     /**
521      * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
522      * some setup and then call {@code establish()} to connect.
523      *
524      * @return {@code true} if the service was started, the service was already connected, or there
525      *         was no always-on VPN to start. {@code false} otherwise.
526      */
startAlwaysOnVpn(int userId)527     private boolean startAlwaysOnVpn(int userId) {
528         synchronized (mVpns) {
529             Vpn vpn = mVpns.get(userId);
530             if (vpn == null) {
531                 // Shouldn't happen as all code paths that point here should have checked the Vpn
532                 // exists already.
533                 Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
534                 return false;
535             }
536 
537             return vpn.startAlwaysOnVpn();
538         }
539     }
540 
541     @Override
isAlwaysOnVpnPackageSupported(int userId, String packageName)542     public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
543         enforceSettingsPermission();
544         enforceCrossUserPermission(userId);
545 
546         synchronized (mVpns) {
547             Vpn vpn = mVpns.get(userId);
548             if (vpn == null) {
549                 logw("User " + userId + " has no Vpn configuration");
550                 return false;
551             }
552             return vpn.isAlwaysOnPackageSupported(packageName);
553         }
554     }
555 
556     @Override
setAlwaysOnVpnPackage( int userId, String packageName, boolean lockdown, List<String> lockdownAllowlist)557     public boolean setAlwaysOnVpnPackage(
558             int userId, String packageName, boolean lockdown, List<String> lockdownAllowlist) {
559         enforceControlAlwaysOnVpnPermission();
560         enforceCrossUserPermission(userId);
561 
562         synchronized (mVpns) {
563             // Can't set always-on VPN if legacy VPN is already in lockdown mode.
564             if (isLockdownVpnEnabled()) {
565                 return false;
566             }
567 
568             Vpn vpn = mVpns.get(userId);
569             if (vpn == null) {
570                 logw("User " + userId + " has no Vpn configuration");
571                 return false;
572             }
573             if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist)) {
574                 return false;
575             }
576             if (!startAlwaysOnVpn(userId)) {
577                 vpn.setAlwaysOnPackage(null, false, null);
578                 return false;
579             }
580         }
581         return true;
582     }
583 
584     @Override
getAlwaysOnVpnPackage(int userId)585     public String getAlwaysOnVpnPackage(int userId) {
586         enforceControlAlwaysOnVpnPermission();
587         enforceCrossUserPermission(userId);
588 
589         synchronized (mVpns) {
590             Vpn vpn = mVpns.get(userId);
591             if (vpn == null) {
592                 logw("User " + userId + " has no Vpn configuration");
593                 return null;
594             }
595             return vpn.getAlwaysOnPackage();
596         }
597     }
598 
599     @Override
isVpnLockdownEnabled(int userId)600     public boolean isVpnLockdownEnabled(int userId) {
601         enforceControlAlwaysOnVpnPermission();
602         enforceCrossUserPermission(userId);
603 
604         synchronized (mVpns) {
605             Vpn vpn = mVpns.get(userId);
606             if (vpn == null) {
607                 logw("User " + userId + " has no Vpn configuration");
608                 return false;
609             }
610             return vpn.getLockdown();
611         }
612     }
613 
614     @Override
getVpnLockdownAllowlist(int userId)615     public List<String> getVpnLockdownAllowlist(int userId) {
616         enforceControlAlwaysOnVpnPermission();
617         enforceCrossUserPermission(userId);
618 
619         synchronized (mVpns) {
620             Vpn vpn = mVpns.get(userId);
621             if (vpn == null) {
622                 logw("User " + userId + " has no Vpn configuration");
623                 return null;
624             }
625             return vpn.getLockdownAllowlist();
626         }
627     }
628 
629     @GuardedBy("mVpns")
getVpnIfOwner()630     private Vpn getVpnIfOwner() {
631         return getVpnIfOwner(mDeps.getCallingUid());
632     }
633 
634     // TODO: stop calling into Vpn.java and get this information from data in this class.
635     @GuardedBy("mVpns")
getVpnIfOwner(int uid)636     private Vpn getVpnIfOwner(int uid) {
637         final int user = UserHandle.getUserId(uid);
638 
639         final Vpn vpn = mVpns.get(user);
640         if (vpn == null) {
641             return null;
642         } else {
643             final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
644             return (info == null || info.getOwnerUid() != uid) ? null : vpn;
645         }
646     }
647 
registerReceivers()648     private void registerReceivers() {
649         // Set up the listener for user state for creating user VPNs.
650         // Should run on mHandler to avoid any races.
651         IntentFilter intentFilter = new IntentFilter();
652         intentFilter.addAction(Intent.ACTION_USER_STARTED);
653         intentFilter.addAction(Intent.ACTION_USER_STOPPED);
654         intentFilter.addAction(Intent.ACTION_USER_ADDED);
655         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
656         intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
657 
658         mUserAllContext.registerReceiver(
659                 mIntentReceiver,
660                 intentFilter,
661                 null /* broadcastPermission */,
662                 mHandler);
663         mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
664                 mUserPresentReceiver,
665                 new IntentFilter(Intent.ACTION_USER_PRESENT),
666                 null /* broadcastPermission */,
667                 mHandler /* scheduler */);
668 
669         // Listen to package add and removal events for all users.
670         intentFilter = new IntentFilter();
671         intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
672         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
673         intentFilter.addDataScheme("package");
674         mUserAllContext.registerReceiver(
675                 mIntentReceiver,
676                 intentFilter,
677                 null /* broadcastPermission */,
678                 mHandler);
679 
680         // Listen to lockdown VPN reset.
681         intentFilter = new IntentFilter();
682         intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
683         mUserAllContext.registerReceiver(
684                 mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
685     }
686 
687     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
688         @Override
689         public void onReceive(Context context, Intent intent) {
690             ensureRunningOnHandlerThread();
691             final String action = intent.getAction();
692             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
693             final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
694             final Uri packageData = intent.getData();
695             final String packageName =
696                     packageData != null ? packageData.getSchemeSpecificPart() : null;
697 
698             if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
699                 onVpnLockdownReset();
700             }
701 
702             // UserId should be filled for below intents, check the existence.
703             if (userId == UserHandle.USER_NULL) return;
704 
705             if (Intent.ACTION_USER_STARTED.equals(action)) {
706                 onUserStarted(userId);
707             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
708                 onUserStopped(userId);
709             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
710                 onUserAdded(userId);
711             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
712                 onUserRemoved(userId);
713             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
714                 onUserUnlocked(userId);
715             } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
716                 onPackageReplaced(packageName, uid);
717             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
718                 final boolean isReplacing = intent.getBooleanExtra(
719                         Intent.EXTRA_REPLACING, false);
720                 onPackageRemoved(packageName, uid, isReplacing);
721             } else {
722                 Log.wtf(TAG, "received unexpected intent: " + action);
723             }
724         }
725     };
726 
727     private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
728         @Override
729         public void onReceive(Context context, Intent intent) {
730             ensureRunningOnHandlerThread();
731             // Try creating lockdown tracker, since user present usually means
732             // unlocked keystore.
733             updateLockdownVpn();
734             // Use the same context that registered receiver before to unregister it. Because use
735             // different context to unregister receiver will cause exception.
736             context.unregisterReceiver(this);
737         }
738     };
739 
onUserStarted(int userId)740     private void onUserStarted(int userId) {
741         synchronized (mVpns) {
742             Vpn userVpn = mVpns.get(userId);
743             if (userVpn != null) {
744                 loge("Starting user already has a VPN");
745                 return;
746             }
747             userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId,
748                     new VpnProfileStore());
749             mVpns.put(userId, userVpn);
750             if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
751                 updateLockdownVpn();
752             }
753         }
754     }
755 
onUserStopped(int userId)756     private void onUserStopped(int userId) {
757         synchronized (mVpns) {
758             Vpn userVpn = mVpns.get(userId);
759             if (userVpn == null) {
760                 loge("Stopped user has no VPN");
761                 return;
762             }
763             userVpn.onUserStopped();
764             mVpns.delete(userId);
765         }
766     }
767 
768     @Override
isCallerCurrentAlwaysOnVpnApp()769     public boolean isCallerCurrentAlwaysOnVpnApp() {
770         synchronized (mVpns) {
771             Vpn vpn = getVpnIfOwner();
772             return vpn != null && vpn.getAlwaysOn();
773         }
774     }
775 
776     @Override
isCallerCurrentAlwaysOnVpnLockdownApp()777     public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
778         synchronized (mVpns) {
779             Vpn vpn = getVpnIfOwner();
780             return vpn != null && vpn.getLockdown();
781         }
782     }
783 
784 
onUserAdded(int userId)785     private void onUserAdded(int userId) {
786         synchronized (mVpns) {
787             final int vpnsSize = mVpns.size();
788             for (int i = 0; i < vpnsSize; i++) {
789                 Vpn vpn = mVpns.valueAt(i);
790                 vpn.onUserAdded(userId);
791             }
792         }
793     }
794 
onUserRemoved(int userId)795     private void onUserRemoved(int userId) {
796         synchronized (mVpns) {
797             final int vpnsSize = mVpns.size();
798             for (int i = 0; i < vpnsSize; i++) {
799                 Vpn vpn = mVpns.valueAt(i);
800                 vpn.onUserRemoved(userId);
801             }
802         }
803     }
804 
onPackageReplaced(String packageName, int uid)805     private void onPackageReplaced(String packageName, int uid) {
806         if (TextUtils.isEmpty(packageName) || uid < 0) {
807             Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
808             return;
809         }
810         final int userId = UserHandle.getUserId(uid);
811         synchronized (mVpns) {
812             final Vpn vpn = mVpns.get(userId);
813             if (vpn == null) {
814                 return;
815             }
816             // Legacy always-on VPN won't be affected since the package name is not set.
817             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
818                 log("Restarting always-on VPN package " + packageName + " for user "
819                         + userId);
820                 vpn.startAlwaysOnVpn();
821             }
822         }
823     }
824 
onPackageRemoved(String packageName, int uid, boolean isReplacing)825     private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
826         if (TextUtils.isEmpty(packageName) || uid < 0) {
827             Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
828             return;
829         }
830 
831         final int userId = UserHandle.getUserId(uid);
832         synchronized (mVpns) {
833             final Vpn vpn = mVpns.get(userId);
834             if (vpn == null) {
835                 return;
836             }
837             // Legacy always-on VPN won't be affected since the package name is not set.
838             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
839                 log("Removing always-on VPN package " + packageName + " for user "
840                         + userId);
841                 vpn.setAlwaysOnPackage(null, false, null);
842             }
843         }
844     }
845 
onUserUnlocked(int userId)846     private void onUserUnlocked(int userId) {
847         synchronized (mVpns) {
848             // User present may be sent because of an unlock, which might mean an unlocked keystore.
849             if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
850                 updateLockdownVpn();
851             } else {
852                 startAlwaysOnVpn(userId);
853             }
854         }
855     }
856 
onVpnLockdownReset()857     private void onVpnLockdownReset() {
858         synchronized (mVpns) {
859             if (mLockdownTracker != null) mLockdownTracker.reset();
860         }
861     }
862 
863 
864     @Override
factoryReset()865     public void factoryReset() {
866         enforceSettingsPermission();
867 
868         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)
869                 || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
870             return;
871         }
872 
873         // Remove always-on package
874         final int userId = UserHandle.getCallingUserId();
875         synchronized (mVpns) {
876             final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
877             if (alwaysOnPackage != null) {
878                 setAlwaysOnVpnPackage(userId, null, false, null);
879                 setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
880             }
881 
882             // Turn Always-on VPN off
883             if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
884                 final long ident = Binder.clearCallingIdentity();
885                 try {
886                     mVpnProfileStore.remove(Credentials.LOCKDOWN_VPN);
887                     mLockdownEnabled = false;
888                     setLockdownTracker(null);
889                 } finally {
890                     Binder.restoreCallingIdentity(ident);
891                 }
892             }
893 
894             // Turn VPN off
895             VpnConfig vpnConfig = getVpnConfig(userId);
896             if (vpnConfig != null) {
897                 if (vpnConfig.legacy) {
898                     prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
899                 } else {
900                     // Prevent this app (packagename = vpnConfig.user) from initiating
901                     // VPN connections in the future without user intervention.
902                     setVpnPackageAuthorization(
903                             vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
904 
905                     prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
906                 }
907             }
908         }
909     }
910 
ensureRunningOnHandlerThread()911     private void ensureRunningOnHandlerThread() {
912         if (mHandler.getLooper().getThread() != Thread.currentThread()) {
913             throw new IllegalStateException(
914                     "Not running on VpnManagerService thread: "
915                             + Thread.currentThread().getName());
916         }
917     }
918 
enforceControlAlwaysOnVpnPermission()919     private void enforceControlAlwaysOnVpnPermission() {
920         mContext.enforceCallingOrSelfPermission(
921                 android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
922                 "VpnManagerService");
923     }
924 
925     /**
926      * Require that the caller is either in the same user or has appropriate permission to interact
927      * across users.
928      *
929      * @param userId Target user for whatever operation the current IPC is supposed to perform.
930      */
enforceCrossUserPermission(int userId)931     private void enforceCrossUserPermission(int userId) {
932         if (userId == UserHandle.getCallingUserId()) {
933             // Not a cross-user call.
934             return;
935         }
936         mContext.enforceCallingOrSelfPermission(
937                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
938                 "VpnManagerService");
939     }
940 
enforceSettingsPermission()941     private void enforceSettingsPermission() {
942         enforceAnyPermissionOf(mContext,
943                 android.Manifest.permission.NETWORK_SETTINGS,
944                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
945     }
946 
log(String s)947     private static void log(String s) {
948         Log.d(TAG, s);
949     }
950 
logw(String s)951     private static void logw(String s) {
952         Log.w(TAG, s);
953     }
954 
loge(String s)955     private static void loge(String s) {
956         Log.e(TAG, s);
957     }
958 }
959