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