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