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