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