Vpn.java revision 0784eeab28da094a87437ed454fe3dca01b1f9f2
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
17package com.android.server.connectivity;
18
19import static android.Manifest.permission.BIND_VPN_SERVICE;
20import static android.os.UserHandle.PER_USER_RANGE;
21import static android.system.OsConstants.AF_INET;
22import static android.system.OsConstants.AF_INET6;
23
24import android.app.AppGlobals;
25import android.app.AppOpsManager;
26import android.app.PendingIntent;
27import android.content.BroadcastReceiver;
28import android.content.ComponentName;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
33import android.content.pm.ApplicationInfo;
34import android.content.pm.PackageManager;
35import android.content.pm.PackageManager.NameNotFoundException;
36import android.content.pm.ResolveInfo;
37import android.content.pm.UserInfo;
38import android.net.ConnectivityManager;
39import android.net.IConnectivityManager;
40import android.net.INetworkManagementEventObserver;
41import android.net.LinkAddress;
42import android.net.LinkProperties;
43import android.net.LocalSocket;
44import android.net.LocalSocketAddress;
45import android.net.NetworkAgent;
46import android.net.NetworkCapabilities;
47import android.net.NetworkInfo;
48import android.net.NetworkInfo.DetailedState;
49import android.net.NetworkMisc;
50import android.net.RouteInfo;
51import android.net.UidRange;
52import android.os.Binder;
53import android.os.FileUtils;
54import android.os.IBinder;
55import android.os.INetworkManagementService;
56import android.os.Looper;
57import android.os.Parcel;
58import android.os.ParcelFileDescriptor;
59import android.os.Process;
60import android.os.RemoteException;
61import android.os.SystemClock;
62import android.os.SystemService;
63import android.os.UserHandle;
64import android.os.UserManager;
65import android.security.Credentials;
66import android.security.KeyStore;
67import android.util.Log;
68
69import com.android.internal.annotations.GuardedBy;
70import com.android.internal.net.LegacyVpnInfo;
71import com.android.internal.net.VpnConfig;
72import com.android.internal.net.VpnProfile;
73import com.android.server.net.BaseNetworkObserver;
74
75import libcore.io.IoUtils;
76
77import java.io.File;
78import java.io.IOException;
79import java.io.InputStream;
80import java.io.OutputStream;
81import java.net.Inet4Address;
82import java.net.Inet6Address;
83import java.net.InetAddress;
84import java.nio.charset.StandardCharsets;
85import java.util.ArrayList;
86import java.util.Arrays;
87import java.util.List;
88import java.util.SortedSet;
89import java.util.TreeSet;
90import java.util.concurrent.atomic.AtomicInteger;
91
92/**
93 * @hide
94 */
95public class Vpn {
96    private static final String NETWORKTYPE = "VPN";
97    private static final String TAG = "Vpn";
98    private static final boolean LOGD = true;
99
100    // TODO: create separate trackers for each unique VPN to support
101    // automated reconnection
102
103    private Context mContext;
104    private NetworkInfo mNetworkInfo;
105    private String mPackage;
106    private int mOwnerUID;
107    private String mInterface;
108    private boolean mAllowIPv4;
109    private boolean mAllowIPv6;
110    private Connection mConnection;
111    private LegacyVpnRunner mLegacyVpnRunner;
112    private PendingIntent mStatusIntent;
113    private volatile boolean mEnableTeardown = true;
114    private final IConnectivityManager mConnService;
115    private final INetworkManagementService mNetd;
116    private VpnConfig mConfig;
117    private NetworkAgent mNetworkAgent;
118    private final Looper mLooper;
119    private final NetworkCapabilities mNetworkCapabilities;
120
121    /* list of users using this VPN. */
122    @GuardedBy("this")
123    private List<UidRange> mVpnUsers = null;
124    private BroadcastReceiver mUserIntentReceiver = null;
125
126    // Handle of user initiating VPN.
127    private final int mUserHandle;
128
129    public Vpn(Looper looper, Context context, INetworkManagementService netService,
130            IConnectivityManager connService, int userHandle) {
131        mContext = context;
132        mNetd = netService;
133        mConnService = connService;
134        mUserHandle = userHandle;
135        mLooper = looper;
136
137        mPackage = VpnConfig.LEGACY_VPN;
138        mOwnerUID = getAppUid(mPackage, mUserHandle);
139
140        try {
141            netService.registerObserver(mObserver);
142        } catch (RemoteException e) {
143            Log.wtf(TAG, "Problem registering observer", e);
144        }
145        if (userHandle == UserHandle.USER_OWNER) {
146            // Owner's VPN also needs to handle restricted users
147            mUserIntentReceiver = new BroadcastReceiver() {
148                @Override
149                public void onReceive(Context context, Intent intent) {
150                    final String action = intent.getAction();
151                    final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
152                            UserHandle.USER_NULL);
153                    if (userHandle == UserHandle.USER_NULL) return;
154
155                    if (Intent.ACTION_USER_ADDED.equals(action)) {
156                        onUserAdded(userHandle);
157                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
158                        onUserRemoved(userHandle);
159                    }
160                }
161            };
162
163            IntentFilter intentFilter = new IntentFilter();
164            intentFilter.addAction(Intent.ACTION_USER_ADDED);
165            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
166            mContext.registerReceiverAsUser(
167                    mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
168        }
169
170        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
171        // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
172        mNetworkCapabilities = new NetworkCapabilities();
173        mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
174        mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
175    }
176
177    /**
178     * Set if this object is responsible for watching for {@link NetworkInfo}
179     * teardown. When {@code false}, teardown is handled externally by someone
180     * else.
181     */
182    public void setEnableTeardown(boolean enableTeardown) {
183        mEnableTeardown = enableTeardown;
184    }
185
186    /**
187     * Update current state, dispaching event to listeners.
188     */
189    private void updateState(DetailedState detailedState, String reason) {
190        if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
191        mNetworkInfo.setDetailedState(detailedState, reason, null);
192        if (mNetworkAgent != null) {
193            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
194        }
195    }
196
197    /**
198     * Prepare for a VPN application. This method is designed to solve
199     * race conditions. It first compares the current prepared package
200     * with {@code oldPackage}. If they are the same, the prepared
201     * package is revoked and replaced with {@code newPackage}. If
202     * {@code oldPackage} is {@code null}, the comparison is omitted.
203     * If {@code newPackage} is the same package or {@code null}, the
204     * revocation is omitted. This method returns {@code true} if the
205     * operation is succeeded.
206     *
207     * Legacy VPN is handled specially since it is not a real package.
208     * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
209     * it can be revoked by itself.
210     *
211     * @param oldPackage The package name of the old VPN application.
212     * @param newPackage The package name of the new VPN application.
213     * @return true if the operation is succeeded.
214     */
215    public synchronized boolean prepare(String oldPackage, String newPackage) {
216        // Return false if the package does not match.
217        if (oldPackage != null && !oldPackage.equals(mPackage)) {
218            // The package doesn't match. If this VPN was not previously authorized, return false
219            // to force user authorization. Otherwise, revoke the VPN anyway.
220            if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
221                long token = Binder.clearCallingIdentity();
222                try {
223                    // This looks bizarre, but it is what ConfirmDialog in VpnDialogs is doing when
224                    // the user clicks through to allow the VPN to consent. So we are emulating the
225                    // action of the dialog without actually showing it.
226                    prepare(null, oldPackage);
227                } finally {
228                    Binder.restoreCallingIdentity(token);
229                }
230                return true;
231            }
232            return false;
233        }
234
235        // Return true if we do not need to revoke.
236        if (newPackage == null ||
237                (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) {
238            return true;
239        }
240
241        // Check if the caller is authorized.
242        enforceControlPermission();
243
244        // Reset the interface.
245        if (mInterface != null) {
246            mStatusIntent = null;
247            agentDisconnect();
248            jniReset(mInterface);
249            mInterface = null;
250            mVpnUsers = null;
251        }
252
253        // Revoke the connection or stop LegacyVpnRunner.
254        if (mConnection != null) {
255            try {
256                mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
257                        Parcel.obtain(), null, IBinder.FLAG_ONEWAY);
258            } catch (Exception e) {
259                // ignore
260            }
261            mContext.unbindService(mConnection);
262            mConnection = null;
263        } else if (mLegacyVpnRunner != null) {
264            mLegacyVpnRunner.exit();
265            mLegacyVpnRunner = null;
266        }
267
268        long token = Binder.clearCallingIdentity();
269        try {
270            mNetd.denyProtect(mOwnerUID);
271        } catch (Exception e) {
272            Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
273        } finally {
274            Binder.restoreCallingIdentity(token);
275        }
276
277        Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
278        mPackage = newPackage;
279        mOwnerUID = getAppUid(newPackage, mUserHandle);
280        token = Binder.clearCallingIdentity();
281        try {
282            mNetd.allowProtect(mOwnerUID);
283        } catch (Exception e) {
284            Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
285        } finally {
286            Binder.restoreCallingIdentity(token);
287        }
288        mConfig = null;
289
290        updateState(DetailedState.IDLE, "prepare");
291        return true;
292    }
293
294    /**
295     * Set whether the current package has the ability to launch VPNs without user intervention.
296     */
297    public void setPackageAuthorization(boolean authorized) {
298        // Check if the caller is authorized.
299        enforceControlPermission();
300
301        if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
302            return;
303        }
304
305        long token = Binder.clearCallingIdentity();
306        try {
307            AppOpsManager appOps =
308                    (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
309            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
310                    authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
311        } catch (Exception e) {
312            Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
313        } finally {
314            Binder.restoreCallingIdentity(token);
315        }
316    }
317
318    private boolean isVpnUserPreConsented(String packageName) {
319        AppOpsManager appOps =
320                (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
321
322        // Verify that the caller matches the given package and has permission to activate VPNs.
323        return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(),
324                packageName) == AppOpsManager.MODE_ALLOWED;
325    }
326
327    private int getAppUid(String app, int userHandle) {
328        if (VpnConfig.LEGACY_VPN.equals(app)) {
329            return Process.myUid();
330        }
331        PackageManager pm = mContext.getPackageManager();
332        int result;
333        try {
334            result = pm.getPackageUid(app, userHandle);
335        } catch (NameNotFoundException e) {
336            result = -1;
337        }
338        return result;
339    }
340
341    public NetworkInfo getNetworkInfo() {
342        return mNetworkInfo;
343    }
344
345    private void agentConnect() {
346        LinkProperties lp = new LinkProperties();
347        lp.setInterfaceName(mInterface);
348
349        boolean hasDefaultRoute = false;
350        for (RouteInfo route : mConfig.routes) {
351            lp.addRoute(route);
352            if (route.isDefaultRoute()) hasDefaultRoute = true;
353        }
354        if (hasDefaultRoute) {
355            mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
356        } else {
357            mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
358        }
359
360        if (mConfig.dnsServers != null) {
361            for (String dnsServer : mConfig.dnsServers) {
362                InetAddress address = InetAddress.parseNumericAddress(dnsServer);
363                lp.addDnsServer(address);
364                if (address instanceof Inet4Address) {
365                    mAllowIPv4 = true;
366                } else {
367                    mAllowIPv6 = true;
368                }
369            }
370        }
371
372        // Concatenate search domains into a string.
373        StringBuilder buffer = new StringBuilder();
374        if (mConfig.searchDomains != null) {
375            for (String domain : mConfig.searchDomains) {
376                buffer.append(domain).append(' ');
377            }
378        }
379        lp.setDomains(buffer.toString().trim());
380
381        mNetworkInfo.setIsAvailable(true);
382        mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
383
384        NetworkMisc networkMisc = new NetworkMisc();
385        networkMisc.allowBypass = mConfig.allowBypass;
386
387        long token = Binder.clearCallingIdentity();
388        try {
389            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
390                    mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
391                            @Override
392                            public void unwanted() {
393                                // We are user controlled, not driven by NetworkRequest.
394                            }
395                        };
396        } finally {
397            Binder.restoreCallingIdentity(token);
398        }
399
400        if (!mAllowIPv4) {
401            mNetworkAgent.blockAddressFamily(AF_INET);
402        }
403        if (!mAllowIPv6) {
404            mNetworkAgent.blockAddressFamily(AF_INET6);
405        }
406
407        addVpnUserLocked(mUserHandle);
408        // If we are owner assign all Restricted Users to this VPN
409        if (mUserHandle == UserHandle.USER_OWNER) {
410            token = Binder.clearCallingIdentity();
411            List<UserInfo> users;
412            try {
413                users = UserManager.get(mContext).getUsers();
414            } finally {
415                Binder.restoreCallingIdentity(token);
416            }
417            for (UserInfo user : users) {
418                if (user.isRestricted()) {
419                    addVpnUserLocked(user.id);
420                }
421            }
422        }
423        mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
424    }
425
426    private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
427        networkInfo.setIsAvailable(false);
428        networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
429        if (networkAgent != null) {
430            networkAgent.sendNetworkInfo(networkInfo);
431        }
432    }
433
434    private void agentDisconnect(NetworkAgent networkAgent) {
435        NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
436        agentDisconnect(networkInfo, networkAgent);
437    }
438
439    private void agentDisconnect() {
440        if (mNetworkInfo.isConnected()) {
441            agentDisconnect(mNetworkInfo, mNetworkAgent);
442            mNetworkAgent = null;
443        }
444    }
445
446    /**
447     * Establish a VPN network and return the file descriptor of the VPN
448     * interface. This methods returns {@code null} if the application is
449     * revoked or not prepared.
450     *
451     * @param config The parameters to configure the network.
452     * @return The file descriptor of the VPN interface.
453     */
454    public synchronized ParcelFileDescriptor establish(VpnConfig config) {
455        // Check if the caller is already prepared.
456        UserManager mgr = UserManager.get(mContext);
457        if (Binder.getCallingUid() != mOwnerUID) {
458            return null;
459        }
460        // Check if the service is properly declared.
461        Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
462        intent.setClassName(mPackage, config.user);
463        long token = Binder.clearCallingIdentity();
464        try {
465            // Restricted users are not allowed to create VPNs, they are tied to Owner
466            UserInfo user = mgr.getUserInfo(mUserHandle);
467            if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
468                throw new SecurityException("Restricted users cannot establish VPNs");
469            }
470
471            ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
472                                                                        null, 0, mUserHandle);
473            if (info == null) {
474                throw new SecurityException("Cannot find " + config.user);
475            }
476            if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
477                throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
478            }
479        } catch (RemoteException e) {
480                throw new SecurityException("Cannot find " + config.user);
481        } finally {
482            Binder.restoreCallingIdentity(token);
483        }
484
485        // Save the old config in case we need to go back.
486        VpnConfig oldConfig = mConfig;
487        String oldInterface = mInterface;
488        Connection oldConnection = mConnection;
489        NetworkAgent oldNetworkAgent = mNetworkAgent;
490        mNetworkAgent = null;
491        List<UidRange> oldUsers = mVpnUsers;
492        boolean oldAllowIPv4 = mAllowIPv4;
493        boolean oldAllowIPv6 = mAllowIPv6;
494
495        // Configure the interface. Abort if any of these steps fails.
496        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
497        try {
498            updateState(DetailedState.CONNECTING, "establish");
499            String interfaze = jniGetName(tun.getFd());
500
501            // TEMP use the old jni calls until there is support for netd address setting
502            StringBuilder builder = new StringBuilder();
503            for (LinkAddress address : config.addresses) {
504                builder.append(" " + address);
505            }
506            if (jniSetAddresses(interfaze, builder.toString()) < 1) {
507                throw new IllegalArgumentException("At least one address must be specified");
508            }
509            Connection connection = new Connection();
510            if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
511                        new UserHandle(mUserHandle))) {
512                throw new IllegalStateException("Cannot bind " + config.user);
513            }
514
515            mConnection = connection;
516            mInterface = interfaze;
517
518            // Fill more values.
519            config.user = mPackage;
520            config.interfaze = mInterface;
521            config.startTime = SystemClock.elapsedRealtime();
522            mConfig = config;
523
524            // Set up forwarding and DNS rules.
525            mVpnUsers = new ArrayList<UidRange>();
526            mAllowIPv4 = mConfig.allowIPv4;
527            mAllowIPv6 = mConfig.allowIPv6;
528
529            agentConnect();
530
531            if (oldConnection != null) {
532                mContext.unbindService(oldConnection);
533            }
534            // Remove the old tun's user forwarding rules
535            // The new tun's user rules have already been added so they will take over
536            // as rules are deleted. This prevents data leakage as the rules are moved over.
537            agentDisconnect(oldNetworkAgent);
538            if (oldInterface != null && !oldInterface.equals(interfaze)) {
539                jniReset(oldInterface);
540            }
541
542            try {
543                IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
544            } catch (IOException e) {
545                throw new IllegalStateException(
546                        "Cannot set tunnel's fd as blocking=" + config.blocking, e);
547            }
548        } catch (RuntimeException e) {
549            IoUtils.closeQuietly(tun);
550            agentDisconnect();
551            // restore old state
552            mConfig = oldConfig;
553            mConnection = oldConnection;
554            mVpnUsers = oldUsers;
555            mNetworkAgent = oldNetworkAgent;
556            mInterface = oldInterface;
557            mAllowIPv4 = oldAllowIPv4;
558            mAllowIPv6 = oldAllowIPv6;
559            throw e;
560        }
561        Log.i(TAG, "Established by " + config.user + " on " + mInterface);
562        return tun;
563    }
564
565    private boolean isRunningLocked() {
566        return mVpnUsers != null;
567    }
568
569    // Note: Return type guarantees results are deduped and sorted, which callers require.
570    private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
571        SortedSet<Integer> uids = new TreeSet<Integer>();
572        for (String app : packageNames) {
573            int uid = getAppUid(app, userHandle);
574            if (uid != -1) uids.add(uid);
575        }
576        return uids;
577    }
578
579    // Note: This function adds to mVpnUsers but does not publish list to NetworkAgent.
580    private void addVpnUserLocked(int userHandle) {
581        if (!isRunningLocked()) {
582            throw new IllegalStateException("VPN is not active");
583        }
584
585        if (mConfig.allowedApplications != null) {
586            // Add ranges covering all UIDs for allowedApplications.
587            int start = -1, stop = -1;
588            for (int uid : getAppsUids(mConfig.allowedApplications, userHandle)) {
589                if (start == -1) {
590                    start = uid;
591                } else if (uid != stop + 1) {
592                    mVpnUsers.add(new UidRange(start, stop));
593                    start = uid;
594                }
595                stop = uid;
596            }
597            if (start != -1) mVpnUsers.add(new UidRange(start, stop));
598        } else if (mConfig.disallowedApplications != null) {
599            // Add all ranges for user skipping UIDs for disallowedApplications.
600            final UidRange userRange = UidRange.createForUser(userHandle);
601            int start = userRange.start;
602            for (int uid : getAppsUids(mConfig.disallowedApplications, userHandle)) {
603                if (uid == start) {
604                    start++;
605                } else {
606                    mVpnUsers.add(new UidRange(start, uid - 1));
607                    start = uid + 1;
608                }
609            }
610            if (start <= userRange.stop) mVpnUsers.add(new UidRange(start, userRange.stop));
611        } else {
612            // Add all UIDs for the user.
613            mVpnUsers.add(UidRange.createForUser(userHandle));
614        }
615
616        prepareStatusIntent();
617    }
618
619    // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
620    // apply to userHandle.
621    private List<UidRange> uidRangesForUser(int userHandle) {
622        final UidRange userRange = UidRange.createForUser(userHandle);
623        final List<UidRange> ranges = new ArrayList<UidRange>();
624        for (UidRange range : mVpnUsers) {
625            if (range.start >= userRange.start && range.stop <= userRange.stop) {
626                ranges.add(range);
627            }
628        }
629        return ranges;
630    }
631
632    private void removeVpnUserLocked(int userHandle) {
633        if (!isRunningLocked()) {
634            throw new IllegalStateException("VPN is not active");
635        }
636        final List<UidRange> ranges = uidRangesForUser(userHandle);
637        if (mNetworkAgent != null) {
638            mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()]));
639        }
640        mVpnUsers.removeAll(ranges);
641        mStatusIntent = null;
642    }
643
644    private void onUserAdded(int userHandle) {
645        // If the user is restricted tie them to the owner's VPN
646        synchronized(Vpn.this) {
647            UserManager mgr = UserManager.get(mContext);
648            UserInfo user = mgr.getUserInfo(userHandle);
649            if (user.isRestricted()) {
650                try {
651                    addVpnUserLocked(userHandle);
652                    if (mNetworkAgent != null) {
653                        final List<UidRange> ranges = uidRangesForUser(userHandle);
654                        mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()]));
655                    }
656                } catch (Exception e) {
657                    Log.wtf(TAG, "Failed to add restricted user to owner", e);
658                }
659            }
660        }
661    }
662
663    private void onUserRemoved(int userHandle) {
664        // clean up if restricted
665        synchronized(Vpn.this) {
666            UserManager mgr = UserManager.get(mContext);
667            UserInfo user = mgr.getUserInfo(userHandle);
668            if (user.isRestricted()) {
669                try {
670                    removeVpnUserLocked(userHandle);
671                } catch (Exception e) {
672                    Log.wtf(TAG, "Failed to remove restricted user to owner", e);
673                }
674            }
675        }
676    }
677
678    /**
679     * Return the configuration of the currently running VPN.
680     */
681    public VpnConfig getVpnConfig() {
682        enforceControlPermission();
683        return mConfig;
684    }
685
686    @Deprecated
687    public synchronized void interfaceStatusChanged(String iface, boolean up) {
688        try {
689            mObserver.interfaceStatusChanged(iface, up);
690        } catch (RemoteException e) {
691            // ignored; target is local
692        }
693    }
694
695    private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
696        @Override
697        public void interfaceStatusChanged(String interfaze, boolean up) {
698            synchronized (Vpn.this) {
699                if (!up && mLegacyVpnRunner != null) {
700                    mLegacyVpnRunner.check(interfaze);
701                }
702            }
703        }
704
705        @Override
706        public void interfaceRemoved(String interfaze) {
707            synchronized (Vpn.this) {
708                if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
709                    mStatusIntent = null;
710                    mVpnUsers = null;
711                    mInterface = null;
712                    if (mConnection != null) {
713                        mContext.unbindService(mConnection);
714                        mConnection = null;
715                        agentDisconnect();
716                    } else if (mLegacyVpnRunner != null) {
717                        mLegacyVpnRunner.exit();
718                        mLegacyVpnRunner = null;
719                    }
720                }
721            }
722        }
723    };
724
725    private void enforceControlPermission() {
726        // System user is allowed to control VPN.
727        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
728            return;
729        }
730        int appId = UserHandle.getAppId(Binder.getCallingUid());
731        final long token = Binder.clearCallingIdentity();
732        try {
733            // System VPN dialogs are also allowed to control VPN.
734            PackageManager pm = mContext.getPackageManager();
735            ApplicationInfo app = pm.getApplicationInfo(VpnConfig.DIALOGS_PACKAGE, 0);
736            if (((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == app.uid)) {
737                return;
738            }
739            // SystemUI dialogs are also allowed to control VPN.
740            ApplicationInfo sysUiApp = pm.getApplicationInfo("com.android.systemui", 0);
741            if (((sysUiApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == sysUiApp.uid)) {
742                return;
743            }
744        } catch (Exception e) {
745            // ignore
746        } finally {
747            Binder.restoreCallingIdentity(token);
748        }
749
750        throw new SecurityException("Unauthorized Caller");
751    }
752
753    private class Connection implements ServiceConnection {
754        private IBinder mService;
755
756        @Override
757        public void onServiceConnected(ComponentName name, IBinder service) {
758            mService = service;
759        }
760
761        @Override
762        public void onServiceDisconnected(ComponentName name) {
763            mService = null;
764        }
765    }
766
767    private void prepareStatusIntent() {
768        final long token = Binder.clearCallingIdentity();
769        try {
770            mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
771        } finally {
772            Binder.restoreCallingIdentity(token);
773        }
774    }
775
776    public synchronized boolean addAddress(String address, int prefixLength) {
777        if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
778            return false;
779        }
780        boolean success = jniAddAddress(mInterface, address, prefixLength);
781        if (success && (!mAllowIPv4 || !mAllowIPv6)) {
782            try {
783                InetAddress inetAddress = InetAddress.parseNumericAddress(address);
784                if ((inetAddress instanceof Inet4Address) && !mAllowIPv4) {
785                    mAllowIPv4 = true;
786                    mNetworkAgent.unblockAddressFamily(AF_INET);
787                } else if ((inetAddress instanceof Inet6Address) && !mAllowIPv6) {
788                    mAllowIPv6 = true;
789                    mNetworkAgent.unblockAddressFamily(AF_INET6);
790                }
791            } catch (IllegalArgumentException e) {
792                // ignore
793            }
794        }
795        // Ideally, we'd call mNetworkAgent.sendLinkProperties() here to notify ConnectivityService
796        // that the LinkAddress has changed. But we don't do so for two reasons: (1) We don't set
797        // LinkAddresses on the LinkProperties we establish in the first place (see agentConnect())
798        // and (2) CS doesn't do anything with LinkAddresses anyway (see updateLinkProperties()).
799        // TODO: Maybe fix this.
800        return success;
801    }
802
803    public synchronized boolean removeAddress(String address, int prefixLength) {
804        if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
805            return false;
806        }
807        boolean success = jniDelAddress(mInterface, address, prefixLength);
808        // Ideally, we'd call mNetworkAgent.sendLinkProperties() here to notify ConnectivityService
809        // that the LinkAddress has changed. But we don't do so for two reasons: (1) We don't set
810        // LinkAddresses on the LinkProperties we establish in the first place (see agentConnect())
811        // and (2) CS doesn't do anything with LinkAddresses anyway (see updateLinkProperties()).
812        // TODO: Maybe fix this.
813        return success;
814    }
815
816    private native int jniCreate(int mtu);
817    private native String jniGetName(int tun);
818    private native int jniSetAddresses(String interfaze, String addresses);
819    private native void jniReset(String interfaze);
820    private native int jniCheck(String interfaze);
821    private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
822    private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
823
824    private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
825        for (RouteInfo route : prop.getAllRoutes()) {
826            // Currently legacy VPN only works on IPv4.
827            if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
828                return route;
829            }
830        }
831
832        throw new IllegalStateException("Unable to find IPv4 default gateway");
833    }
834
835    /**
836     * Start legacy VPN, controlling native daemons as needed. Creates a
837     * secondary thread to perform connection work, returning quickly.
838     */
839    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
840        enforceControlPermission();
841        if (!keyStore.isUnlocked()) {
842            throw new IllegalStateException("KeyStore isn't unlocked");
843        }
844        UserManager mgr = UserManager.get(mContext);
845        UserInfo user = mgr.getUserInfo(mUserHandle);
846        if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
847            throw new SecurityException("Restricted users cannot establish VPNs");
848        }
849
850        final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
851        final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
852        final String iface = ipv4DefaultRoute.getInterface();
853
854        // Load certificates.
855        String privateKey = "";
856        String userCert = "";
857        String caCert = "";
858        String serverCert = "";
859        if (!profile.ipsecUserCert.isEmpty()) {
860            privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
861            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
862            userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
863        }
864        if (!profile.ipsecCaCert.isEmpty()) {
865            byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
866            caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
867        }
868        if (!profile.ipsecServerCert.isEmpty()) {
869            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
870            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
871        }
872        if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
873            throw new IllegalStateException("Cannot load credentials");
874        }
875
876        // Prepare arguments for racoon.
877        String[] racoon = null;
878        switch (profile.type) {
879            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
880                racoon = new String[] {
881                    iface, profile.server, "udppsk", profile.ipsecIdentifier,
882                    profile.ipsecSecret, "1701",
883                };
884                break;
885            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
886                racoon = new String[] {
887                    iface, profile.server, "udprsa", privateKey, userCert,
888                    caCert, serverCert, "1701",
889                };
890                break;
891            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
892                racoon = new String[] {
893                    iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
894                    profile.ipsecSecret, profile.username, profile.password, "", gateway,
895                };
896                break;
897            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
898                racoon = new String[] {
899                    iface, profile.server, "xauthrsa", privateKey, userCert,
900                    caCert, serverCert, profile.username, profile.password, "", gateway,
901                };
902                break;
903            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
904                racoon = new String[] {
905                    iface, profile.server, "hybridrsa",
906                    caCert, serverCert, profile.username, profile.password, "", gateway,
907                };
908                break;
909        }
910
911        // Prepare arguments for mtpd.
912        String[] mtpd = null;
913        switch (profile.type) {
914            case VpnProfile.TYPE_PPTP:
915                mtpd = new String[] {
916                    iface, "pptp", profile.server, "1723",
917                    "name", profile.username, "password", profile.password,
918                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
919                    "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
920                    (profile.mppe ? "+mppe" : "nomppe"),
921                };
922                break;
923            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
924            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
925                mtpd = new String[] {
926                    iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
927                    "name", profile.username, "password", profile.password,
928                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
929                    "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
930                };
931                break;
932        }
933
934        VpnConfig config = new VpnConfig();
935        config.legacy = true;
936        config.user = profile.key;
937        config.interfaze = iface;
938        config.session = profile.name;
939
940        config.addLegacyRoutes(profile.routes);
941        if (!profile.dnsServers.isEmpty()) {
942            config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
943        }
944        if (!profile.searchDomains.isEmpty()) {
945            config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
946        }
947        startLegacyVpn(config, racoon, mtpd);
948    }
949
950    private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
951        stopLegacyVpn();
952
953        // Prepare for the new request. This also checks the caller.
954        prepare(null, VpnConfig.LEGACY_VPN);
955        updateState(DetailedState.CONNECTING, "startLegacyVpn");
956
957        // Start a new LegacyVpnRunner and we are done!
958        mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
959        mLegacyVpnRunner.start();
960    }
961
962    public synchronized void stopLegacyVpn() {
963        if (mLegacyVpnRunner != null) {
964            mLegacyVpnRunner.exit();
965            mLegacyVpnRunner = null;
966
967            synchronized (LegacyVpnRunner.TAG) {
968                // wait for old thread to completely finish before spinning up
969                // new instance, otherwise state updates can be out of order.
970            }
971        }
972    }
973
974    /**
975     * Return the information of the current ongoing legacy VPN.
976     */
977    public synchronized LegacyVpnInfo getLegacyVpnInfo() {
978        // Check if the caller is authorized.
979        enforceControlPermission();
980        if (mLegacyVpnRunner == null) return null;
981
982        final LegacyVpnInfo info = new LegacyVpnInfo();
983        info.key = mConfig.user;
984        info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
985        if (mNetworkInfo.isConnected()) {
986            info.intent = mStatusIntent;
987        }
988        return info;
989    }
990
991    public VpnConfig getLegacyVpnConfig() {
992        if (mLegacyVpnRunner != null) {
993            return mConfig;
994        } else {
995            return null;
996        }
997    }
998
999    /**
1000     * Bringing up a VPN connection takes time, and that is all this thread
1001     * does. Here we have plenty of time. The only thing we need to take
1002     * care of is responding to interruptions as soon as possible. Otherwise
1003     * requests will be piled up. This can be done in a Handler as a state
1004     * machine, but it is much easier to read in the current form.
1005     */
1006    private class LegacyVpnRunner extends Thread {
1007        private static final String TAG = "LegacyVpnRunner";
1008
1009        private final String[] mDaemons;
1010        private final String[][] mArguments;
1011        private final LocalSocket[] mSockets;
1012        private final String mOuterInterface;
1013        private final AtomicInteger mOuterConnection =
1014                new AtomicInteger(ConnectivityManager.TYPE_NONE);
1015
1016        private long mTimer = -1;
1017
1018        /**
1019         * Watch for the outer connection (passing in the constructor) going away.
1020         */
1021        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1022            @Override
1023            public void onReceive(Context context, Intent intent) {
1024                if (!mEnableTeardown) return;
1025
1026                if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1027                    if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
1028                            ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
1029                        NetworkInfo info = (NetworkInfo)intent.getExtra(
1030                                ConnectivityManager.EXTRA_NETWORK_INFO);
1031                        if (info != null && !info.isConnectedOrConnecting()) {
1032                            try {
1033                                mObserver.interfaceStatusChanged(mOuterInterface, false);
1034                            } catch (RemoteException e) {}
1035                        }
1036                    }
1037                }
1038            }
1039        };
1040
1041        public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
1042            super(TAG);
1043            mConfig = config;
1044            mDaemons = new String[] {"racoon", "mtpd"};
1045            // TODO: clear arguments from memory once launched
1046            mArguments = new String[][] {racoon, mtpd};
1047            mSockets = new LocalSocket[mDaemons.length];
1048
1049            // This is the interface which VPN is running on,
1050            // mConfig.interfaze will change to point to OUR
1051            // internal interface soon. TODO - add inner/outer to mconfig
1052            // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
1053            // we will leave the VPN up.  We should check that it's still there/connected after
1054            // registering
1055            mOuterInterface = mConfig.interfaze;
1056
1057            try {
1058                mOuterConnection.set(
1059                        mConnService.findConnectionTypeForIface(mOuterInterface));
1060            } catch (Exception e) {
1061                mOuterConnection.set(ConnectivityManager.TYPE_NONE);
1062            }
1063
1064            IntentFilter filter = new IntentFilter();
1065            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
1066            mContext.registerReceiver(mBroadcastReceiver, filter);
1067        }
1068
1069        public void check(String interfaze) {
1070            if (interfaze.equals(mOuterInterface)) {
1071                Log.i(TAG, "Legacy VPN is going down with " + interfaze);
1072                exit();
1073            }
1074        }
1075
1076        public void exit() {
1077            // We assume that everything is reset after stopping the daemons.
1078            interrupt();
1079            for (LocalSocket socket : mSockets) {
1080                IoUtils.closeQuietly(socket);
1081            }
1082            agentDisconnect();
1083            try {
1084                mContext.unregisterReceiver(mBroadcastReceiver);
1085            } catch (IllegalArgumentException e) {}
1086        }
1087
1088        @Override
1089        public void run() {
1090            // Wait for the previous thread since it has been interrupted.
1091            Log.v(TAG, "Waiting");
1092            synchronized (TAG) {
1093                Log.v(TAG, "Executing");
1094                execute();
1095                monitorDaemons();
1096            }
1097        }
1098
1099        private void checkpoint(boolean yield) throws InterruptedException {
1100            long now = SystemClock.elapsedRealtime();
1101            if (mTimer == -1) {
1102                mTimer = now;
1103                Thread.sleep(1);
1104            } else if (now - mTimer <= 60000) {
1105                Thread.sleep(yield ? 200 : 1);
1106            } else {
1107                updateState(DetailedState.FAILED, "checkpoint");
1108                throw new IllegalStateException("Time is up");
1109            }
1110        }
1111
1112        private void execute() {
1113            // Catch all exceptions so we can clean up few things.
1114            boolean initFinished = false;
1115            try {
1116                // Initialize the timer.
1117                checkpoint(false);
1118
1119                // Wait for the daemons to stop.
1120                for (String daemon : mDaemons) {
1121                    while (!SystemService.isStopped(daemon)) {
1122                        checkpoint(true);
1123                    }
1124                }
1125
1126                // Clear the previous state.
1127                File state = new File("/data/misc/vpn/state");
1128                state.delete();
1129                if (state.exists()) {
1130                    throw new IllegalStateException("Cannot delete the state");
1131                }
1132                new File("/data/misc/vpn/abort").delete();
1133                initFinished = true;
1134
1135                // Check if we need to restart any of the daemons.
1136                boolean restart = false;
1137                for (String[] arguments : mArguments) {
1138                    restart = restart || (arguments != null);
1139                }
1140                if (!restart) {
1141                    agentDisconnect();
1142                    return;
1143                }
1144                updateState(DetailedState.CONNECTING, "execute");
1145
1146                // Start the daemon with arguments.
1147                for (int i = 0; i < mDaemons.length; ++i) {
1148                    String[] arguments = mArguments[i];
1149                    if (arguments == null) {
1150                        continue;
1151                    }
1152
1153                    // Start the daemon.
1154                    String daemon = mDaemons[i];
1155                    SystemService.start(daemon);
1156
1157                    // Wait for the daemon to start.
1158                    while (!SystemService.isRunning(daemon)) {
1159                        checkpoint(true);
1160                    }
1161
1162                    // Create the control socket.
1163                    mSockets[i] = new LocalSocket();
1164                    LocalSocketAddress address = new LocalSocketAddress(
1165                            daemon, LocalSocketAddress.Namespace.RESERVED);
1166
1167                    // Wait for the socket to connect.
1168                    while (true) {
1169                        try {
1170                            mSockets[i].connect(address);
1171                            break;
1172                        } catch (Exception e) {
1173                            // ignore
1174                        }
1175                        checkpoint(true);
1176                    }
1177                    mSockets[i].setSoTimeout(500);
1178
1179                    // Send over the arguments.
1180                    OutputStream out = mSockets[i].getOutputStream();
1181                    for (String argument : arguments) {
1182                        byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
1183                        if (bytes.length >= 0xFFFF) {
1184                            throw new IllegalArgumentException("Argument is too large");
1185                        }
1186                        out.write(bytes.length >> 8);
1187                        out.write(bytes.length);
1188                        out.write(bytes);
1189                        checkpoint(false);
1190                    }
1191                    out.write(0xFF);
1192                    out.write(0xFF);
1193                    out.flush();
1194
1195                    // Wait for End-of-File.
1196                    InputStream in = mSockets[i].getInputStream();
1197                    while (true) {
1198                        try {
1199                            if (in.read() == -1) {
1200                                break;
1201                            }
1202                        } catch (Exception e) {
1203                            // ignore
1204                        }
1205                        checkpoint(true);
1206                    }
1207                }
1208
1209                // Wait for the daemons to create the new state.
1210                while (!state.exists()) {
1211                    // Check if a running daemon is dead.
1212                    for (int i = 0; i < mDaemons.length; ++i) {
1213                        String daemon = mDaemons[i];
1214                        if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
1215                            throw new IllegalStateException(daemon + " is dead");
1216                        }
1217                    }
1218                    checkpoint(true);
1219                }
1220
1221                // Now we are connected. Read and parse the new state.
1222                String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
1223                if (parameters.length != 6) {
1224                    throw new IllegalStateException("Cannot parse the state");
1225                }
1226
1227                // Set the interface and the addresses in the config.
1228                mConfig.interfaze = parameters[0].trim();
1229
1230                mConfig.addLegacyAddresses(parameters[1]);
1231                // Set the routes if they are not set in the config.
1232                if (mConfig.routes == null || mConfig.routes.isEmpty()) {
1233                    mConfig.addLegacyRoutes(parameters[2]);
1234                }
1235
1236                // Set the DNS servers if they are not set in the config.
1237                if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
1238                    String dnsServers = parameters[3].trim();
1239                    if (!dnsServers.isEmpty()) {
1240                        mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
1241                    }
1242                }
1243
1244                // Set the search domains if they are not set in the config.
1245                if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
1246                    String searchDomains = parameters[4].trim();
1247                    if (!searchDomains.isEmpty()) {
1248                        mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
1249                    }
1250                }
1251
1252                // Here is the last step and it must be done synchronously.
1253                synchronized (Vpn.this) {
1254                    // Set the start time
1255                    mConfig.startTime = SystemClock.elapsedRealtime();
1256
1257                    // Check if the thread is interrupted while we are waiting.
1258                    checkpoint(false);
1259
1260                    // Check if the interface is gone while we are waiting.
1261                    if (jniCheck(mConfig.interfaze) == 0) {
1262                        throw new IllegalStateException(mConfig.interfaze + " is gone");
1263                    }
1264
1265                    // Now INetworkManagementEventObserver is watching our back.
1266                    mInterface = mConfig.interfaze;
1267                    mVpnUsers = new ArrayList<UidRange>();
1268                    mAllowIPv4 = mConfig.allowIPv4;
1269                    mAllowIPv6 = mConfig.allowIPv6;
1270
1271                    agentConnect();
1272
1273                    Log.i(TAG, "Connected!");
1274                }
1275            } catch (Exception e) {
1276                Log.i(TAG, "Aborting", e);
1277                updateState(DetailedState.FAILED, e.getMessage());
1278                exit();
1279            } finally {
1280                // Kill the daemons if they fail to stop.
1281                if (!initFinished) {
1282                    for (String daemon : mDaemons) {
1283                        SystemService.stop(daemon);
1284                    }
1285                }
1286
1287                // Do not leave an unstable state.
1288                if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
1289                    agentDisconnect();
1290                }
1291            }
1292        }
1293
1294        /**
1295         * Monitor the daemons we started, moving to disconnected state if the
1296         * underlying services fail.
1297         */
1298        private void monitorDaemons() {
1299            if (!mNetworkInfo.isConnected()) {
1300                return;
1301            }
1302
1303            try {
1304                while (true) {
1305                    Thread.sleep(2000);
1306                    for (int i = 0; i < mDaemons.length; i++) {
1307                        if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
1308                            return;
1309                        }
1310                    }
1311                }
1312            } catch (InterruptedException e) {
1313                Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
1314            } finally {
1315                for (String daemon : mDaemons) {
1316                    SystemService.stop(daemon);
1317                }
1318
1319                agentDisconnect();
1320            }
1321        }
1322    }
1323}
1324