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 // Penalty applied to scores of Networks that have not been validated. 227 private static final int UNVALIDATED_SCORE_PENALTY = 40; 228 229 // Score for explicitly connected network. 230 // 231 // This ensures that a) the explicitly selected network is never trumped by anything else, and 232 // b) the explicitly selected network is never torn down. 233 private static final int MAXIMUM_NETWORK_SCORE = 100; 234 235 // The list of NetworkRequests being satisfied by this Network. 236 private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); 237 238 // How many of the satisfied requests are actual requests and not listens. 239 private int mNumRequestNetworkRequests = 0; 240 241 // How many of the satisfied requests are of type BACKGROUND_REQUEST. 242 private int mNumBackgroundNetworkRequests = 0; 243 244 public final Messenger messenger; 245 public final AsyncChannel asyncChannel; 246 247 // Used by ConnectivityService to keep track of 464xlat. 248 public Nat464Xlat clatd; 249 250 private static final String TAG = ConnectivityService.class.getSimpleName(); 251 private static final boolean VDBG = false; 252 private final ConnectivityService mConnService; 253 private final Context mContext; 254 private final Handler mHandler; 255 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)256 public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, 257 LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, 258 NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) { 259 this.messenger = messenger; 260 asyncChannel = ac; 261 network = net; 262 networkInfo = info; 263 linkProperties = lp; 264 networkCapabilities = nc; 265 currentScore = score; 266 mConnService = connService; 267 mContext = context; 268 mHandler = handler; 269 networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest); 270 networkMisc = misc; 271 } 272 connService()273 public ConnectivityService connService() { 274 return mConnService; 275 } 276 handler()277 public Handler handler() { 278 return mHandler; 279 } 280 281 // Functions for manipulating the requests satisfied by this network. 282 // 283 // These functions must only called on ConnectivityService's main thread. 284 285 private static final boolean ADD = true; 286 private static final boolean REMOVE = false; 287 updateRequestCounts(boolean add, NetworkRequest request)288 private void updateRequestCounts(boolean add, NetworkRequest request) { 289 int delta = add ? +1 : -1; 290 switch (request.type) { 291 case REQUEST: 292 case TRACK_DEFAULT: 293 mNumRequestNetworkRequests += delta; 294 break; 295 296 case BACKGROUND_REQUEST: 297 mNumRequestNetworkRequests += delta; 298 mNumBackgroundNetworkRequests += delta; 299 break; 300 301 case LISTEN: 302 break; 303 304 case NONE: 305 default: 306 Log.wtf(TAG, "Unhandled request type " + request.type); 307 break; 308 } 309 } 310 311 /** 312 * Add {@code networkRequest} to this network as it's satisfied by this network. 313 * @return true if {@code networkRequest} was added or false if {@code networkRequest} was 314 * already present. 315 */ addRequest(NetworkRequest networkRequest)316 public boolean addRequest(NetworkRequest networkRequest) { 317 NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); 318 if (existing == networkRequest) return false; 319 if (existing != null) { 320 // Should only happen if the requestId wraps. If that happens lots of other things will 321 // be broken as well. 322 Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s", 323 networkRequest, existing, name())); 324 updateRequestCounts(REMOVE, existing); 325 } 326 mNetworkRequests.put(networkRequest.requestId, networkRequest); 327 updateRequestCounts(ADD, networkRequest); 328 return true; 329 } 330 331 /** 332 * Remove the specified request from this network. 333 */ removeRequest(int requestId)334 public void removeRequest(int requestId) { 335 NetworkRequest existing = mNetworkRequests.get(requestId); 336 if (existing == null) return; 337 updateRequestCounts(REMOVE, existing); 338 mNetworkRequests.remove(requestId); 339 if (existing.isRequest()) { 340 unlingerRequest(existing); 341 } 342 } 343 344 /** 345 * Returns whether this network is currently satisfying the request with the specified ID. 346 */ isSatisfyingRequest(int id)347 public boolean isSatisfyingRequest(int id) { 348 return mNetworkRequests.get(id) != null; 349 } 350 351 /** 352 * Returns the request at the specified position in the list of requests satisfied by this 353 * network. 354 */ requestAt(int index)355 public NetworkRequest requestAt(int index) { 356 return mNetworkRequests.valueAt(index); 357 } 358 359 /** 360 * Returns the number of requests currently satisfied by this network for which 361 * {@link android.net.NetworkRequest#isRequest} returns {@code true}. 362 */ numRequestNetworkRequests()363 public int numRequestNetworkRequests() { 364 return mNumRequestNetworkRequests; 365 } 366 367 /** 368 * Returns the number of requests currently satisfied by this network of type 369 * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}. 370 */ numBackgroundNetworkRequests()371 public int numBackgroundNetworkRequests() { 372 return mNumBackgroundNetworkRequests; 373 } 374 375 /** 376 * Returns the number of foreground requests currently satisfied by this network. 377 */ numForegroundNetworkRequests()378 public int numForegroundNetworkRequests() { 379 return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests; 380 } 381 382 /** 383 * Returns the number of requests of any type currently satisfied by this network. 384 */ numNetworkRequests()385 public int numNetworkRequests() { 386 return mNetworkRequests.size(); 387 } 388 389 /** 390 * Returns whether the network is a background network. A network is a background network if it 391 * is satisfying no foreground requests and at least one background request. (If it did not have 392 * a background request, it would be a speculative network that is only being kept up because 393 * it might satisfy a request if it validated). 394 */ isBackgroundNetwork()395 public boolean isBackgroundNetwork() { 396 return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0; 397 } 398 399 // Does this network satisfy request? satisfies(NetworkRequest request)400 public boolean satisfies(NetworkRequest request) { 401 return created && 402 request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities); 403 } 404 satisfiesImmutableCapabilitiesOf(NetworkRequest request)405 public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) { 406 return created && 407 request.networkCapabilities.satisfiedByImmutableNetworkCapabilities( 408 networkCapabilities); 409 } 410 isVPN()411 public boolean isVPN() { 412 return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN); 413 } 414 getCurrentScore(boolean pretendValidated)415 private int getCurrentScore(boolean pretendValidated) { 416 // TODO: We may want to refactor this into a NetworkScore class that takes a base score from 417 // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the 418 // score. The NetworkScore class would provide a nice place to centralize score constants 419 // so they are not scattered about the transports. 420 421 // If this network is explicitly selected and the user has decided to use it even if it's 422 // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly 423 // selected and we're trying to see what its score could be. This ensures that we don't tear 424 // down an explicitly selected network before the user gets a chance to prefer it when 425 // a higher-scoring network (e.g., Ethernet) is available. 426 if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { 427 return MAXIMUM_NETWORK_SCORE; 428 } 429 430 int score = currentScore; 431 if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) { 432 score -= UNVALIDATED_SCORE_PENALTY; 433 } 434 if (score < 0) score = 0; 435 return score; 436 } 437 438 // Return true on devices configured to ignore score penalty for wifi networks 439 // that become unvalidated (b/31075769). ignoreWifiUnvalidationPenalty()440 private boolean ignoreWifiUnvalidationPenalty() { 441 boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && 442 networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 443 boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated; 444 return isWifi && !avoidBadWifi && everValidated; 445 } 446 447 // Get the current score for this Network. This may be modified from what the 448 // NetworkAgent sent, as it has modifiers applied to it. getCurrentScore()449 public int getCurrentScore() { 450 return getCurrentScore(false); 451 } 452 453 // Get the current score for this Network as if it was validated. This may be modified from 454 // what the NetworkAgent sent, as it has modifiers applied to it. getCurrentScoreAsValidated()455 public int getCurrentScoreAsValidated() { 456 return getCurrentScore(true); 457 } 458 setCurrentScore(int newScore)459 public void setCurrentScore(int newScore) { 460 currentScore = newScore; 461 } 462 getNetworkState()463 public NetworkState getNetworkState() { 464 synchronized (this) { 465 // Network objects are outwardly immutable so there is no point to duplicating. 466 // Duplicating also precludes sharing socket factories and connection pools. 467 final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null; 468 return new NetworkState(new NetworkInfo(networkInfo), 469 new LinkProperties(linkProperties), 470 new NetworkCapabilities(networkCapabilities), network, subscriberId, null); 471 } 472 } 473 474 /** 475 * Sets the specified request to linger on this network for the specified time. Called by 476 * ConnectivityService when the request is moved to another network with a higher score. 477 */ lingerRequest(NetworkRequest request, long now, long duration)478 public void lingerRequest(NetworkRequest request, long now, long duration) { 479 if (mLingerTimerForRequest.get(request.requestId) != null) { 480 // Cannot happen. Once a request is lingering on a particular network, we cannot 481 // re-linger it unless that network becomes the best for that request again, in which 482 // case we should have unlingered it. 483 Log.wtf(TAG, this.name() + ": request " + request.requestId + " already lingered"); 484 } 485 final long expiryMs = now + duration; 486 LingerTimer timer = new LingerTimer(request, expiryMs); 487 if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + this.name()); 488 mLingerTimers.add(timer); 489 mLingerTimerForRequest.put(request.requestId, timer); 490 } 491 492 /** 493 * Cancel lingering. Called by ConnectivityService when a request is added to this network. 494 * Returns true if the given request was lingering on this network, false otherwise. 495 */ unlingerRequest(NetworkRequest request)496 public boolean unlingerRequest(NetworkRequest request) { 497 LingerTimer timer = mLingerTimerForRequest.get(request.requestId); 498 if (timer != null) { 499 if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + this.name()); 500 mLingerTimers.remove(timer); 501 mLingerTimerForRequest.remove(request.requestId); 502 return true; 503 } 504 return false; 505 } 506 getLingerExpiry()507 public long getLingerExpiry() { 508 return mLingerExpiryMs; 509 } 510 updateLingerTimer()511 public void updateLingerTimer() { 512 long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs; 513 if (newExpiry == mLingerExpiryMs) return; 514 515 // Even if we're going to reschedule the timer, cancel it first. This is because the 516 // semantics of WakeupMessage guarantee that if cancel is called then the alarm will 517 // never call its callback (handleLingerComplete), even if it has already fired. 518 // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage 519 // has already been dispatched, rescheduling to some time in the future it won't stop it 520 // from calling its callback immediately. 521 if (mLingerMessage != null) { 522 mLingerMessage.cancel(); 523 mLingerMessage = null; 524 } 525 526 if (newExpiry > 0) { 527 mLingerMessage = mConnService.makeWakeupMessage( 528 mContext, mHandler, 529 "NETWORK_LINGER_COMPLETE." + network.netId, 530 EVENT_NETWORK_LINGER_COMPLETE, this); 531 mLingerMessage.schedule(newExpiry); 532 } 533 534 mLingerExpiryMs = newExpiry; 535 } 536 linger()537 public void linger() { 538 mLingering = true; 539 } 540 unlinger()541 public void unlinger() { 542 mLingering = false; 543 } 544 isLingering()545 public boolean isLingering() { 546 return mLingering; 547 } 548 clearLingerState()549 public void clearLingerState() { 550 if (mLingerMessage != null) { 551 mLingerMessage.cancel(); 552 mLingerMessage = null; 553 } 554 mLingerTimers.clear(); 555 mLingerTimerForRequest.clear(); 556 updateLingerTimer(); // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage. 557 mLingering = false; 558 } 559 dumpLingerTimers(PrintWriter pw)560 public void dumpLingerTimers(PrintWriter pw) { 561 for (LingerTimer timer : mLingerTimers) { pw.println(timer); } 562 } 563 updateClat(INetworkManagementService netd)564 public void updateClat(INetworkManagementService netd) { 565 if (Nat464Xlat.requiresClat(this)) { 566 maybeStartClat(netd); 567 } else { 568 maybeStopClat(); 569 } 570 } 571 572 /** Ensure clat has started for this network. */ maybeStartClat(INetworkManagementService netd)573 public void maybeStartClat(INetworkManagementService netd) { 574 if (clatd != null && clatd.isStarted()) { 575 return; 576 } 577 clatd = new Nat464Xlat(netd, this); 578 clatd.start(); 579 } 580 581 /** Ensure clat has stopped for this network. */ maybeStopClat()582 public void maybeStopClat() { 583 if (clatd == null) { 584 return; 585 } 586 clatd.stop(); 587 clatd = null; 588 } 589 toString()590 public String toString() { 591 return "NetworkAgentInfo{ ni{" + networkInfo + "} " + 592 "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " + 593 "lp{" + linkProperties + "} " + 594 "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} " + 595 "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " + 596 "created{" + created + "} lingering{" + isLingering() + "} " + 597 "explicitlySelected{" + networkMisc.explicitlySelected + "} " + 598 "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + 599 "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " + 600 "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " + 601 "clat{" + clatd + "} " + 602 "}"; 603 } 604 name()605 public String name() { 606 return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" + 607 networkInfo.getSubtypeName() + ") - " + Objects.toString(network) + "]"; 608 } 609 610 // Enables sorting in descending order of score. 611 @Override compareTo(NetworkAgentInfo other)612 public int compareTo(NetworkAgentInfo other) { 613 return other.getCurrentScore() - getCurrentScore(); 614 } 615 } 616