1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.connectivity; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 20 21 import android.content.Context; 22 import android.net.LinkProperties; 23 import android.net.Network; 24 import android.net.NetworkCapabilities; 25 import android.net.NetworkInfo; 26 import android.net.NetworkMisc; 27 import android.net.NetworkRequest; 28 import android.net.NetworkState; 29 import android.os.Handler; 30 import android.os.INetworkManagementService; 31 import android.os.Messenger; 32 import android.os.RemoteException; 33 import android.os.SystemClock; 34 import android.util.Log; 35 import android.util.SparseArray; 36 37 import com.android.internal.util.AsyncChannel; 38 import com.android.internal.util.WakeupMessage; 39 import com.android.server.ConnectivityService; 40 import com.android.server.connectivity.NetworkMonitor; 41 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 import java.util.Comparator; 45 import java.util.Objects; 46 import java.util.SortedSet; 47 import java.util.TreeSet; 48 49 /** 50 * A bag class used by ConnectivityService for holding a collection of most recent 51 * information published by a particular NetworkAgent as well as the 52 * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests 53 * interested in using it. Default sort order is descending by score. 54 */ 55 // States of a network: 56 // -------------------- 57 // 1. registered, uncreated, disconnected, unvalidated 58 // This state is entered when a NetworkFactory registers a NetworkAgent in any state except 59 // the CONNECTED state. 60 // 2. registered, uncreated, connecting, unvalidated 61 // This state is entered when a registered NetworkAgent for a VPN network transitions to the 62 // CONNECTING state (TODO: go through this state for every network, not just VPNs). 63 // ConnectivityService will tell netd to create the network early in order to add extra UID 64 // routing rules referencing the netID. These rules need to be in place before the network is 65 // connected to avoid racing against client apps trying to connect to a half-setup network. 66 // 3. registered, uncreated, connected, unvalidated 67 // This state is entered when a registered NetworkAgent transitions to the CONNECTED state. 68 // ConnectivityService will tell netd to create the network if it was not already created, and 69 // immediately transition to state #4. 70 // 4. registered, created, connected, unvalidated 71 // If this network can satisfy the default NetworkRequest, then NetworkMonitor will 72 // probe for Internet connectivity. 73 // If this network cannot satisfy the default NetworkRequest, it will immediately be 74 // transitioned to state #5. 75 // A network may remain in this state if NetworkMonitor fails to find Internet connectivity, 76 // for example: 77 // a. a captive portal is present, or 78 // b. a WiFi router whose Internet backhaul is down, or 79 // c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator 80 // or tunnel) but does not disconnect from the AP/cell tower, or 81 // d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes. 82 // 5. registered, created, connected, validated 83 // 84 // The device's default network connection: 85 // ---------------------------------------- 86 // Networks in states #4 and #5 may be used as a device's default network connection if they 87 // satisfy the default NetworkRequest. 88 // A network, that satisfies the default NetworkRequest, in state #5 should always be chosen 89 // in favor of a network, that satisfies the default NetworkRequest, in state #4. 90 // When deciding between two networks, that both satisfy the default NetworkRequest, to select 91 // for the default network connection, the one with the higher score should be chosen. 92 // 93 // When a network disconnects: 94 // --------------------------- 95 // If a network's transport disappears, for example: 96 // a. WiFi turned off, or 97 // b. cellular data turned off, or 98 // c. airplane mode is turned on, or 99 // d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range 100 // of AP for an extended period of time, or switches to another AP without roaming) 101 // then that network can transition from any state (#1-#5) to unregistered. This happens by 102 // the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager. 103 // ConnectivityService also tells netd to destroy the network. 104 // 105 // When ConnectivityService disconnects a network: 106 // ----------------------------------------------- 107 // If a network has no chance of satisfying any requests (even if it were to become validated 108 // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel. 109 // 110 // If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that 111 // satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any 112 // foreground NetworkRequest, then there will be a 30s pause to allow network communication to be 113 // wrapped up rather than abruptly terminated. During this pause the network is said to be 114 // "lingering". During this pause if the network begins satisfying a foreground NetworkRequest, 115 // ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and 116 // the network is no longer considered "lingering". After the linger timer expires, if the network 117 // is satisfying one or more background NetworkRequests it is kept up in the background. If it is 118 // not, ConnectivityService disconnects the NetworkAgent's AsyncChannel. 119 public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 120 121 public NetworkInfo networkInfo; 122 // This Network object should always be used if possible, so as to encourage reuse of the 123 // enclosed socket factory and connection pool. Avoid creating other Network objects. 124 // This Network object is always valid. 125 public final Network network; 126 public LinkProperties linkProperties; 127 // This should only be modified via ConnectivityService.updateCapabilities(). 128 public NetworkCapabilities networkCapabilities; 129 public final NetworkMonitor networkMonitor; 130 public final NetworkMisc networkMisc; 131 // Indicates if netd has been told to create this Network. From this point on the appropriate 132 // routing rules are setup and routes are added so packets can begin flowing over the Network. 133 // This is a sticky bit; once set it is never cleared. 134 public boolean created; 135 // Set to true after the first time this network is marked as CONNECTED. Once set, the network 136 // shows up in API calls, is able to satisfy NetworkRequests and can become the default network. 137 // This is a sticky bit; once set it is never cleared. 138 public boolean everConnected; 139 // Set to true if this Network successfully passed validation or if it did not satisfy the 140 // default NetworkRequest in which case validation will not be attempted. 141 // This is a sticky bit; once set it is never cleared even if future validation attempts fail. 142 public boolean everValidated; 143 144 // The result of the last validation attempt on this network (true if validated, false if not). 145 public boolean lastValidated; 146 147 // If true, becoming unvalidated will lower the network's score. This is only meaningful if the 148 // system is configured not to do this for certain networks, e.g., if the 149 // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via 150 // Settings.Global.NETWORK_AVOID_BAD_WIFI. 151 public boolean avoidUnvalidated; 152 153 // Whether a captive portal was ever detected on this network. 154 // This is a sticky bit; once set it is never cleared. 155 public boolean everCaptivePortalDetected; 156 157 // Whether a captive portal was found during the last network validation attempt. 158 public boolean lastCaptivePortalDetected; 159 160 // Networks are lingered when they become unneeded as a result of their NetworkRequests being 161 // satisfied by a higher-scoring network. so as to allow communication to wrap up before the 162 // network is taken down. This usually only happens to the default network. Lingering ends with 163 // either the linger timeout expiring and the network being taken down, or the network 164 // satisfying a request again. 165 public static class LingerTimer implements Comparable<LingerTimer> { 166 public final NetworkRequest request; 167 public final long expiryMs; 168 LingerTimer(NetworkRequest request, long expiryMs)169 public LingerTimer(NetworkRequest request, long expiryMs) { 170 this.request = request; 171 this.expiryMs = expiryMs; 172 } equals(Object o)173 public boolean equals(Object o) { 174 if (!(o instanceof LingerTimer)) return false; 175 LingerTimer other = (LingerTimer) o; 176 return (request.requestId == other.request.requestId) && (expiryMs == other.expiryMs); 177 } hashCode()178 public int hashCode() { 179 return Objects.hash(request.requestId, expiryMs); 180 } compareTo(LingerTimer other)181 public int compareTo(LingerTimer other) { 182 return (expiryMs != other.expiryMs) ? 183 Long.compare(expiryMs, other.expiryMs) : 184 Integer.compare(request.requestId, other.request.requestId); 185 } toString()186 public String toString() { 187 return String.format("%s, expires %dms", request.toString(), 188 expiryMs - SystemClock.elapsedRealtime()); 189 } 190 } 191 192 /** 193 * Inform ConnectivityService that the network LINGER period has 194 * expired. 195 * obj = this NetworkAgentInfo 196 */ 197 public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001; 198 199 // All linger timers for this network, sorted by expiry time. A linger timer is added whenever 200 // a request is moved to a network with a better score, regardless of whether the network is or 201 // was lingering or not. 202 // TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g., 203 // SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire. 204 private final SortedSet<LingerTimer> mLingerTimers = new TreeSet<>(); 205 206 // For fast lookups. Indexes into mLingerTimers by request ID. 207 private final SparseArray<LingerTimer> mLingerTimerForRequest = new SparseArray<>(); 208 209 // Linger expiry timer. Armed whenever mLingerTimers is non-empty, regardless of whether the 210 // network is lingering or not. Always set to the expiry of the LingerTimer that expires last. 211 // When the timer fires, all linger state is cleared, and if the network has no requests, it is 212 // torn down. 213 private WakeupMessage mLingerMessage; 214 215 // Linger expiry. Holds the expiry time of the linger timer, or 0 if the timer is not armed. 216 private long mLingerExpiryMs; 217 218 // Whether the network is lingering or not. Must be maintained separately from the above because 219 // it depends on the state of other networks and requests, which only ConnectivityService knows. 220 // (Example: we don't linger a network if it would become the best for a NetworkRequest if it 221 // validated). 222 private boolean mLingering; 223 224 // This represents the last score received from the NetworkAgent. 225 private int currentScore; 226 227 // The list of NetworkRequests being satisfied by this Network. 228 private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); 229 230 // How many of the satisfied requests are actual requests and not listens. 231 private int mNumRequestNetworkRequests = 0; 232 233 // How many of the satisfied requests are of type BACKGROUND_REQUEST. 234 private int mNumBackgroundNetworkRequests = 0; 235 236 public final Messenger messenger; 237 public final AsyncChannel asyncChannel; 238 239 // Used by ConnectivityService to keep track of 464xlat. 240 public Nat464Xlat clatd; 241 242 private static final String TAG = ConnectivityService.class.getSimpleName(); 243 private static final boolean VDBG = false; 244 private final ConnectivityService mConnService; 245 private final Context mContext; 246 private final Handler mHandler; 247 NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService)248 public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, 249 LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, 250 NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) { 251 this.messenger = messenger; 252 asyncChannel = ac; 253 network = net; 254 networkInfo = info; 255 linkProperties = lp; 256 networkCapabilities = nc; 257 currentScore = score; 258 mConnService = connService; 259 mContext = context; 260 mHandler = handler; 261 networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest); 262 networkMisc = misc; 263 } 264 connService()265 public ConnectivityService connService() { 266 return mConnService; 267 } 268 handler()269 public Handler handler() { 270 return mHandler; 271 } 272 network()273 public Network network() { 274 return network; 275 } 276 277 // Functions for manipulating the requests satisfied by this network. 278 // 279 // These functions must only called on ConnectivityService's main thread. 280 281 private static final boolean ADD = true; 282 private static final boolean REMOVE = false; 283 updateRequestCounts(boolean add, NetworkRequest request)284 private void updateRequestCounts(boolean add, NetworkRequest request) { 285 int delta = add ? +1 : -1; 286 switch (request.type) { 287 case REQUEST: 288 mNumRequestNetworkRequests += delta; 289 break; 290 291 case BACKGROUND_REQUEST: 292 mNumRequestNetworkRequests += delta; 293 mNumBackgroundNetworkRequests += delta; 294 break; 295 296 case TRACK_DEFAULT: 297 case LISTEN: 298 break; 299 300 case NONE: 301 default: 302 Log.wtf(TAG, "Unhandled request type " + request.type); 303 break; 304 } 305 } 306 307 /** 308 * Add {@code networkRequest} to this network as it's satisfied by this network. 309 * @return true if {@code networkRequest} was added or false if {@code networkRequest} was 310 * already present. 311 */ addRequest(NetworkRequest networkRequest)312 public boolean addRequest(NetworkRequest networkRequest) { 313 NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); 314 if (existing == networkRequest) return false; 315 if (existing != null) { 316 // Should only happen if the requestId wraps. If that happens lots of other things will 317 // be broken as well. 318 Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s", 319 networkRequest, existing, name())); 320 updateRequestCounts(REMOVE, existing); 321 } 322 mNetworkRequests.put(networkRequest.requestId, networkRequest); 323 updateRequestCounts(ADD, networkRequest); 324 return true; 325 } 326 327 /** 328 * Remove the specified request from this network. 329 */ removeRequest(int requestId)330 public void removeRequest(int requestId) { 331 NetworkRequest existing = mNetworkRequests.get(requestId); 332 if (existing == null) return; 333 updateRequestCounts(REMOVE, existing); 334 mNetworkRequests.remove(requestId); 335 if (existing.isRequest()) { 336 unlingerRequest(existing); 337 } 338 } 339 340 /** 341 * Returns whether this network is currently satisfying the request with the specified ID. 342 */ isSatisfyingRequest(int id)343 public boolean isSatisfyingRequest(int id) { 344 return mNetworkRequests.get(id) != null; 345 } 346 347 /** 348 * Returns the request at the specified position in the list of requests satisfied by this 349 * network. 350 */ requestAt(int index)351 public NetworkRequest requestAt(int index) { 352 return mNetworkRequests.valueAt(index); 353 } 354 355 /** 356 * Returns the number of requests currently satisfied by this network for which 357 * {@link android.net.NetworkRequest#isRequest} returns {@code true}. 358 */ numRequestNetworkRequests()359 public int numRequestNetworkRequests() { 360 return mNumRequestNetworkRequests; 361 } 362 363 /** 364 * Returns the number of requests currently satisfied by this network of type 365 * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}. 366 */ numBackgroundNetworkRequests()367 public int numBackgroundNetworkRequests() { 368 return mNumBackgroundNetworkRequests; 369 } 370 371 /** 372 * Returns the number of foreground requests currently satisfied by this network. 373 */ numForegroundNetworkRequests()374 public int numForegroundNetworkRequests() { 375 return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests; 376 } 377 378 /** 379 * Returns the number of requests of any type currently satisfied by this network. 380 */ numNetworkRequests()381 public int numNetworkRequests() { 382 return mNetworkRequests.size(); 383 } 384 385 /** 386 * Returns whether the network is a background network. A network is a background network if it 387 * does not have the NET_CAPABILITY_FOREGROUND capability, which implies it is satisfying no 388 * foreground request, is not lingering (i.e. kept for a while after being outscored), and is 389 * not a speculative network (i.e. kept pending validation when validation would have it 390 * outscore another foreground network). That implies it is being kept up by some background 391 * request (otherwise it would be torn down), maybe the mobile always-on request. 392 */ isBackgroundNetwork()393 public boolean isBackgroundNetwork() { 394 return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0 395 && !isLingering(); 396 } 397 398 /** 399 * Returns whether this network is currently suspended. A network is suspended if it is still 400 * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED} 401 * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}. 402 */ isSuspended()403 public boolean isSuspended() { 404 return networkInfo.getState() == NetworkInfo.State.SUSPENDED; 405 } 406 407 // Does this network satisfy request? satisfies(NetworkRequest request)408 public boolean satisfies(NetworkRequest request) { 409 return created && 410 request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities); 411 } 412 satisfiesImmutableCapabilitiesOf(NetworkRequest request)413 public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) { 414 return created && 415 request.networkCapabilities.satisfiedByImmutableNetworkCapabilities( 416 networkCapabilities); 417 } 418 isVPN()419 public boolean isVPN() { 420 return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN); 421 } 422 getCurrentScore(boolean pretendValidated)423 private int getCurrentScore(boolean pretendValidated) { 424 // TODO: We may want to refactor this into a NetworkScore class that takes a base score from 425 // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the 426 // score. The NetworkScore class would provide a nice place to centralize score constants 427 // so they are not scattered about the transports. 428 429 // If this network is explicitly selected and the user has decided to use it even if it's 430 // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly 431 // selected and we're trying to see what its score could be. This ensures that we don't tear 432 // down an explicitly selected network before the user gets a chance to prefer it when 433 // a higher-scoring network (e.g., Ethernet) is available. 434 if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { 435 return ConnectivityConstants.MAXIMUM_NETWORK_SCORE; 436 } 437 438 int score = currentScore; 439 if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) { 440 score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY; 441 } 442 if (score < 0) score = 0; 443 return score; 444 } 445 446 // Return true on devices configured to ignore score penalty for wifi networks 447 // that become unvalidated (b/31075769). ignoreWifiUnvalidationPenalty()448 private boolean ignoreWifiUnvalidationPenalty() { 449 boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && 450 networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 451 boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated; 452 return isWifi && !avoidBadWifi && everValidated; 453 } 454 455 // Get the current score for this Network. This may be modified from what the 456 // NetworkAgent sent, as it has modifiers applied to it. getCurrentScore()457 public int getCurrentScore() { 458 return getCurrentScore(false); 459 } 460 461 // Get the current score for this Network as if it was validated. This may be modified from 462 // what the NetworkAgent sent, as it has modifiers applied to it. getCurrentScoreAsValidated()463 public int getCurrentScoreAsValidated() { 464 return getCurrentScore(true); 465 } 466 setCurrentScore(int newScore)467 public void setCurrentScore(int newScore) { 468 currentScore = newScore; 469 } 470 getNetworkState()471 public NetworkState getNetworkState() { 472 synchronized (this) { 473 // Network objects are outwardly immutable so there is no point in duplicating. 474 // Duplicating also precludes sharing socket factories and connection pools. 475 final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null; 476 return new NetworkState(new NetworkInfo(networkInfo), 477 new LinkProperties(linkProperties), 478 new NetworkCapabilities(networkCapabilities), network, subscriberId, null); 479 } 480 } 481 482 /** 483 * Sets the specified request to linger on this network for the specified time. Called by 484 * ConnectivityService when the request is moved to another network with a higher score. 485 */ lingerRequest(NetworkRequest request, long now, long duration)486 public void lingerRequest(NetworkRequest request, long now, long duration) { 487 if (mLingerTimerForRequest.get(request.requestId) != null) { 488 // Cannot happen. Once a request is lingering on a particular network, we cannot 489 // re-linger it unless that network becomes the best for that request again, in which 490 // case we should have unlingered it. 491 Log.wtf(TAG, this.name() + ": request " + request.requestId + " already lingered"); 492 } 493 final long expiryMs = now + duration; 494 LingerTimer timer = new LingerTimer(request, expiryMs); 495 if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + this.name()); 496 mLingerTimers.add(timer); 497 mLingerTimerForRequest.put(request.requestId, timer); 498 } 499 500 /** 501 * Cancel lingering. Called by ConnectivityService when a request is added to this network. 502 * Returns true if the given request was lingering on this network, false otherwise. 503 */ unlingerRequest(NetworkRequest request)504 public boolean unlingerRequest(NetworkRequest request) { 505 LingerTimer timer = mLingerTimerForRequest.get(request.requestId); 506 if (timer != null) { 507 if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + this.name()); 508 mLingerTimers.remove(timer); 509 mLingerTimerForRequest.remove(request.requestId); 510 return true; 511 } 512 return false; 513 } 514 getLingerExpiry()515 public long getLingerExpiry() { 516 return mLingerExpiryMs; 517 } 518 updateLingerTimer()519 public void updateLingerTimer() { 520 long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs; 521 if (newExpiry == mLingerExpiryMs) return; 522 523 // Even if we're going to reschedule the timer, cancel it first. This is because the 524 // semantics of WakeupMessage guarantee that if cancel is called then the alarm will 525 // never call its callback (handleLingerComplete), even if it has already fired. 526 // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage 527 // has already been dispatched, rescheduling to some time in the future it won't stop it 528 // from calling its callback immediately. 529 if (mLingerMessage != null) { 530 mLingerMessage.cancel(); 531 mLingerMessage = null; 532 } 533 534 if (newExpiry > 0) { 535 mLingerMessage = mConnService.makeWakeupMessage( 536 mContext, mHandler, 537 "NETWORK_LINGER_COMPLETE." + network.netId, 538 EVENT_NETWORK_LINGER_COMPLETE, this); 539 mLingerMessage.schedule(newExpiry); 540 } 541 542 mLingerExpiryMs = newExpiry; 543 } 544 linger()545 public void linger() { 546 mLingering = true; 547 } 548 unlinger()549 public void unlinger() { 550 mLingering = false; 551 } 552 isLingering()553 public boolean isLingering() { 554 return mLingering; 555 } 556 clearLingerState()557 public void clearLingerState() { 558 if (mLingerMessage != null) { 559 mLingerMessage.cancel(); 560 mLingerMessage = null; 561 } 562 mLingerTimers.clear(); 563 mLingerTimerForRequest.clear(); 564 updateLingerTimer(); // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage. 565 mLingering = false; 566 } 567 dumpLingerTimers(PrintWriter pw)568 public void dumpLingerTimers(PrintWriter pw) { 569 for (LingerTimer timer : mLingerTimers) { pw.println(timer); } 570 } 571 updateClat(INetworkManagementService netd)572 public void updateClat(INetworkManagementService netd) { 573 if (Nat464Xlat.requiresClat(this)) { 574 maybeStartClat(netd); 575 } else { 576 maybeStopClat(); 577 } 578 } 579 580 /** Ensure clat has started for this network. */ maybeStartClat(INetworkManagementService netd)581 public void maybeStartClat(INetworkManagementService netd) { 582 if (clatd != null && clatd.isStarted()) { 583 return; 584 } 585 clatd = new Nat464Xlat(netd, this); 586 clatd.start(); 587 } 588 589 /** Ensure clat has stopped for this network. */ maybeStopClat()590 public void maybeStopClat() { 591 if (clatd == null) { 592 return; 593 } 594 clatd.stop(); 595 clatd = null; 596 } 597 toString()598 public String toString() { 599 return "NetworkAgentInfo{ ni{" + networkInfo + "} " + 600 "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " + 601 "lp{" + linkProperties + "} " + 602 "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} " + 603 "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " + 604 "created{" + created + "} lingering{" + isLingering() + "} " + 605 "explicitlySelected{" + networkMisc.explicitlySelected + "} " + 606 "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + 607 "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " + 608 "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " + 609 "clat{" + clatd + "} " + 610 "}"; 611 } 612 name()613 public String name() { 614 return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" + 615 networkInfo.getSubtypeName() + ") - " + Objects.toString(network) + "]"; 616 } 617 618 // Enables sorting in descending order of score. 619 @Override compareTo(NetworkAgentInfo other)620 public int compareTo(NetworkAgentInfo other) { 621 return other.getCurrentScore() - getCurrentScore(); 622 } 623 } 624