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.NET_CAPABILITY_INTERNET; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 23 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 24 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 25 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 26 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 27 import static android.net.NetworkCapabilities.transportNamesOf; 28 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.content.Context; 32 import android.content.pm.PackageManager; 33 import android.net.CaptivePortalData; 34 import android.net.DscpPolicy; 35 import android.net.IDnsResolver; 36 import android.net.INetd; 37 import android.net.INetworkAgent; 38 import android.net.INetworkAgentRegistry; 39 import android.net.INetworkMonitor; 40 import android.net.LinkProperties; 41 import android.net.LocalNetworkConfig; 42 import android.net.NattKeepalivePacketData; 43 import android.net.Network; 44 import android.net.NetworkAgent; 45 import android.net.NetworkAgentConfig; 46 import android.net.NetworkCapabilities; 47 import android.net.NetworkInfo; 48 import android.net.NetworkMonitorManager; 49 import android.net.NetworkRequest; 50 import android.net.NetworkScore; 51 import android.net.NetworkStateSnapshot; 52 import android.net.QosCallbackException; 53 import android.net.QosFilter; 54 import android.net.QosFilterParcelable; 55 import android.net.QosSession; 56 import android.net.TcpKeepalivePacketData; 57 import android.os.Handler; 58 import android.os.IBinder; 59 import android.os.RemoteException; 60 import android.os.SystemClock; 61 import android.telephony.data.EpsBearerQosSessionAttributes; 62 import android.telephony.data.NrQosSessionAttributes; 63 import android.util.ArraySet; 64 import android.util.Log; 65 import android.util.Pair; 66 import android.util.SparseArray; 67 68 import com.android.internal.annotations.VisibleForTesting; 69 import com.android.internal.util.IndentingPrintWriter; 70 import com.android.internal.util.WakeupMessage; 71 import com.android.server.ConnectivityService; 72 73 import java.io.PrintWriter; 74 import java.net.Inet4Address; 75 import java.net.Inet6Address; 76 import java.time.Instant; 77 import java.util.ArrayList; 78 import java.util.Arrays; 79 import java.util.List; 80 import java.util.NoSuchElementException; 81 import java.util.Objects; 82 import java.util.SortedSet; 83 import java.util.TreeSet; 84 85 /** 86 * A bag class used by ConnectivityService for holding a collection of most recent 87 * information published by a particular NetworkAgent as well as the 88 * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests 89 * interested in using it. Default sort order is descending by score. 90 */ 91 // States of a network: 92 // -------------------- 93 // 1. registered, uncreated, disconnected, unvalidated 94 // This state is entered when a NetworkFactory registers a NetworkAgent in any state except 95 // the CONNECTED state. 96 // 2. registered, uncreated, connecting, unvalidated 97 // This state is entered when a registered NetworkAgent for a VPN network transitions to the 98 // CONNECTING state (TODO: go through this state for every network, not just VPNs). 99 // ConnectivityService will tell netd to create the network early in order to add extra UID 100 // routing rules referencing the netID. These rules need to be in place before the network is 101 // connected to avoid racing against client apps trying to connect to a half-setup network. 102 // 3. registered, uncreated, connected, unvalidated 103 // This state is entered when a registered NetworkAgent transitions to the CONNECTED state. 104 // ConnectivityService will tell netd to create the network if it was not already created, and 105 // immediately transition to state #4. 106 // 4. registered, created, connected, unvalidated 107 // If this network can satisfy the default NetworkRequest, then NetworkMonitor will 108 // probe for Internet connectivity. 109 // If this network cannot satisfy the default NetworkRequest, it will immediately be 110 // transitioned to state #5. 111 // A network may remain in this state if NetworkMonitor fails to find Internet connectivity, 112 // for example: 113 // a. a captive portal is present, or 114 // b. a WiFi router whose Internet backhaul is down, or 115 // c. a wireless connection stops transferring packets temporarily (e.g. device is in elevator 116 // or tunnel) but does not disconnect from the AP/cell tower, or 117 // d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes. 118 // 5. registered, created, connected, validated 119 // 6. registered, created, connected, (validated or unvalidated), destroyed 120 // This is an optional state where the underlying native network is destroyed but the network is 121 // still connected for scoring purposes, so can satisfy requests, including the default request. 122 // It is used when the transport layer wants to replace a network with another network (e.g., 123 // when Wi-Fi has roamed to a different BSSID that is part of a different L3 network) and does 124 // not want the device to switch to another network until the replacement connects and validates. 125 // 126 // The device's default network connection: 127 // ---------------------------------------- 128 // Networks in states #4 and #5 may be used as a device's default network connection if they 129 // satisfy the default NetworkRequest. 130 // A network, that satisfies the default NetworkRequest, in state #5 should always be chosen 131 // in favor of a network, that satisfies the default NetworkRequest, in state #4. 132 // When deciding between two networks, that both satisfy the default NetworkRequest, to select 133 // for the default network connection, the one with the higher score should be chosen. 134 // 135 // When a network disconnects: 136 // --------------------------- 137 // If a network's transport disappears, for example: 138 // a. WiFi turned off, or 139 // b. cellular data turned off, or 140 // c. airplane mode is turned on, or 141 // d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range 142 // of AP for an extended period of time, or switches to another AP without roaming) 143 // then that network can transition from any state (#1-#5) to unregistered. This happens by 144 // the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager. 145 // ConnectivityService also tells netd to destroy the network. 146 // 147 // When ConnectivityService disconnects a network: 148 // ----------------------------------------------- 149 // If a network is just connected, ConnectivityService will think it will be used soon, but might 150 // not be used. Thus, a 5s timer will be held to prevent the network being torn down immediately. 151 // This "nascent" state is implemented by the "lingering" logic below without relating to any 152 // request, and is used in some cases where network requests race with network establishment. The 153 // nascent state ends when the 5-second timer fires, or as soon as the network satisfies a 154 // request, whichever is earlier. In this state, the network is considered in the background. 155 // 156 // If a network has no chance of satisfying any requests (even if it were to become validated 157 // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel. 158 // 159 // If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that 160 // satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any 161 // foreground NetworkRequest, then there will be a 30s pause to allow network communication to be 162 // wrapped up rather than abruptly terminated. During this pause the network is said to be 163 // "lingering". During this pause if the network begins satisfying a foreground NetworkRequest, 164 // ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and 165 // the network is no longer considered "lingering". After the linger timer expires, if the network 166 // is satisfying one or more background NetworkRequests it is kept up in the background. If it is 167 // not, ConnectivityService disconnects the NetworkAgent's AsyncChannel. 168 public class NetworkAgentInfo implements NetworkRanker.Scoreable { 169 170 @NonNull public NetworkInfo networkInfo; 171 // This Network object should always be used if possible, so as to encourage reuse of the 172 // enclosed socket factory and connection pool. Avoid creating other Network objects. 173 // This Network object is always valid. 174 @NonNull public final Network network; 175 @NonNull public LinkProperties linkProperties; 176 // This should only be modified by ConnectivityService, via setNetworkCapabilities(). 177 // TODO: make this private with a getter. 178 @NonNull public NetworkCapabilities networkCapabilities; 179 @NonNull public final NetworkAgentConfig networkAgentConfig; 180 @Nullable public LocalNetworkConfig localNetworkConfig; 181 182 // Underlying networks declared by the agent. 183 // The networks in this list might be declared by a VPN using setUnderlyingNetworks and are 184 // not guaranteed to be current or correct, or even to exist. 185 // 186 // This array is read and iterated on multiple threads with no locking so its contents must 187 // never be modified. When the list of networks changes, replace with a new array, on the 188 // handler thread. 189 public @Nullable volatile Network[] declaredUnderlyingNetworks; 190 191 // The capabilities originally announced by the NetworkAgent, regardless of any capabilities 192 // that were added or removed due to this network's underlying networks. 193 // 194 // As the name implies, these capabilities are not sanitized and are not to 195 // be trusted. Most callers should simply use the {@link networkCapabilities} 196 // field instead. 197 private @Nullable NetworkCapabilities mDeclaredCapabilitiesUnsanitized; 198 199 // Timestamp (SystemClock.elapsedRealtime()) when netd has been told to create this Network, or 200 // 0 if it hasn't been done yet. 201 // From this point on, the appropriate routing rules are setup and routes are added so packets 202 // can begin flowing over the Network. 203 // This is a sticky value; once set != 0 it is never changed. 204 private long mCreatedTime; 205 206 /** Notify this NAI that netd was just told to create this network */ setCreated()207 public void setCreated() { 208 if (0L != mCreatedTime) throw new IllegalStateException("Already created"); 209 mCreatedTime = SystemClock.elapsedRealtime(); 210 } 211 212 /** Returns whether netd was told to create this network */ isCreated()213 public boolean isCreated() { 214 return mCreatedTime != 0L; 215 } 216 217 // Get the time (SystemClock.elapsedRealTime) when this network was created (or 0 if never). getCreatedTime()218 public long getCreatedTime() { 219 return mCreatedTime; 220 } 221 222 // Timestamp of the first time (SystemClock.elapsedRealtime()) this network is marked as 223 // connected, or 0 if this network has never been marked connected. Once set to non-zero, the 224 // network shows up in API calls, is able to satisfy NetworkRequests and can become the default 225 // network. 226 // This is a sticky value; once set != 0 it is never changed. 227 private long mConnectedTime; 228 229 /** Notify this NAI that this network just connected */ setConnected()230 public void setConnected() { 231 if (0L != mConnectedTime) throw new IllegalStateException("Already connected"); 232 mConnectedTime = SystemClock.elapsedRealtime(); 233 } 234 235 /** Return whether this network ever connected */ everConnected()236 public boolean everConnected() { 237 return mConnectedTime != 0L; 238 } 239 240 // Get the time (SystemClock.elapsedRealTime()) when this network was first connected, or 0 if 241 // never. getConnectedTime()242 public long getConnectedTime() { 243 return mConnectedTime; 244 } 245 246 // When this network has been destroyed and is being kept temporarily until it is replaced, 247 // this is set to that timestamp (SystemClock.elapsedRealtime()). Zero otherwise. 248 private long mDestroyedTime; 249 250 /** Notify this NAI that this network was destroyed */ setDestroyed()251 public void setDestroyed() { 252 if (0L != mDestroyedTime) throw new IllegalStateException("Already destroyed"); 253 mDestroyedTime = SystemClock.elapsedRealtime(); 254 } 255 256 /** Return whether this network was destroyed */ isDestroyed()257 public boolean isDestroyed() { 258 return 0L != mDestroyedTime; 259 } 260 261 // Timestamp of the last roaming (SystemClock.elapsedRealtime()) or 0 if never roamed. 262 public long lastRoamTime; 263 264 // Timestamp (SystemClock.elapsedRealtime()) of the first time this network successfully 265 // passed validation or was deemed exempt of validation (see 266 // {@link NetworkMonitorUtils#isValidationRequired}). Zero if the network requires 267 // validation but never passed it successfully. 268 // This is a sticky value; once set it is never changed even if further validation attempts are 269 // made (whether they succeed or fail). 270 private long mFirstValidationTime; 271 272 // Timestamp (SystemClock.elapsedRealtime()) at which the latest validation attempt succeeded, 273 // or 0 if the latest validation attempt failed. 274 private long mCurrentValidationTime; 275 276 /** Notify this NAI that this network just finished a validation check */ setValidated(final boolean validated)277 public void setValidated(final boolean validated) { 278 final long nowOrZero = validated ? SystemClock.elapsedRealtime() : 0L; 279 if (validated && 0L == mFirstValidationTime) { 280 mFirstValidationTime = nowOrZero; 281 } 282 mCurrentValidationTime = nowOrZero; 283 } 284 285 /** 286 * Returns whether this network is currently validated. 287 * 288 * This is the result of the latest validation check. {@see #getCurrentValidationTime} for 289 * when that check was performed. 290 */ isValidated()291 public boolean isValidated() { 292 return 0L != mCurrentValidationTime; 293 } 294 295 /** 296 * Returns whether this network ever passed the validation checks successfully. 297 * 298 * Note that the network may no longer be validated at this time ever if this is true. 299 * @see #isValidated 300 */ everValidated()301 public boolean everValidated() { 302 return 0L != mFirstValidationTime; 303 } 304 305 // Get the time (SystemClock.elapsedRealTime()) when this network was most recently validated, 306 // or 0 if this network was found not to validate on the last attempt. getCurrentValidationTime()307 public long getCurrentValidationTime() { 308 return mCurrentValidationTime; 309 } 310 311 // Get the time (SystemClock.elapsedRealTime()) when this network was validated for the first 312 // time (or 0 if never). getFirstValidationTime()313 public long getFirstValidationTime() { 314 return mFirstValidationTime; 315 } 316 317 // Timestamp (SystemClock.elapsedRealtime()) at which the user requested this network be 318 // avoided when unvalidated. Zero if this never happened for this network. 319 // This is only meaningful if the system is configured to have some cell networks yield 320 // to bad wifi, e.g., if the config_networkAvoidBadWifi option is set to 0 and the user has 321 // not overridden that via Settings.Global.NETWORK_AVOID_BAD_WIFI. 322 // 323 // Normally the system always prefers a validated network to a non-validated one, even if 324 // the non-validated one is cheaper. However, some cell networks may be configured by the 325 // setting above to yield to WiFi even if that WiFi network goes bad. When this configuration 326 // is active, specific networks can be marked to override this configuration so that the 327 // system will revert to preferring such a cell to this network when this network goes bad. This 328 // is achieved by calling {@link ConnectivityManager#setAvoidUnvalidated()}, and this field 329 // is set to non-zero when this happened to this network. 330 private long mAvoidUnvalidated; 331 332 /** Set this network as being avoided when unvalidated. {@see mAvoidUnvalidated} */ setAvoidUnvalidated()333 public void setAvoidUnvalidated() { 334 if (0L != mAvoidUnvalidated) throw new IllegalStateException("Already avoided unvalidated"); 335 mAvoidUnvalidated = SystemClock.elapsedRealtime(); 336 } 337 338 // Get the time (SystemClock.elapsedRealTime()) when this network was set to being avoided 339 // when unvalidated, or 0 if this never happened. getAvoidUnvalidated()340 public long getAvoidUnvalidated() { 341 return mAvoidUnvalidated; 342 } 343 344 // Timestamp (SystemClock.elapsedRealtime()) at which a captive portal was first detected 345 // on this network, or zero if this never happened. 346 // This is a sticky value; once set != 0 it is never changed. 347 private long mFirstCaptivePortalDetectedTime; 348 349 // Timestamp (SystemClock.elapsedRealtime()) at which the latest validation attempt found a 350 // captive portal, or zero if the latest attempt didn't find a captive portal. 351 private long mCurrentCaptivePortalDetectedTime; 352 353 /** Notify this NAI that a captive portal has just been detected on this network */ setCaptivePortalDetected(final boolean hasCaptivePortal)354 public void setCaptivePortalDetected(final boolean hasCaptivePortal) { 355 if (!hasCaptivePortal) { 356 mCurrentCaptivePortalDetectedTime = 0L; 357 return; 358 } 359 final long now = SystemClock.elapsedRealtime(); 360 if (0L == mFirstCaptivePortalDetectedTime) mFirstCaptivePortalDetectedTime = now; 361 mCurrentCaptivePortalDetectedTime = now; 362 } 363 364 /** Return whether a captive portal has ever been detected on this network */ everCaptivePortalDetected()365 public boolean everCaptivePortalDetected() { 366 return 0L != mFirstCaptivePortalDetectedTime; 367 } 368 369 /** Return whether this network has been detected to be behind a captive portal at the moment */ captivePortalDetected()370 public boolean captivePortalDetected() { 371 return 0L != mCurrentCaptivePortalDetectedTime; 372 } 373 374 // Timestamp (SystemClock.elapsedRealtime()) at which the latest validation attempt found 375 // partial connectivity, or zero if the latest attempt didn't find partial connectivity. 376 private long mPartialConnectivityTime; 377 setPartialConnectivity(final boolean value)378 public void setPartialConnectivity(final boolean value) { 379 mPartialConnectivityTime = value ? SystemClock.elapsedRealtime() : 0L; 380 } 381 382 /** Return whether this NAI has partial connectivity */ partialConnectivity()383 public boolean partialConnectivity() { 384 return 0L != mPartialConnectivityTime; 385 } 386 387 // Timestamp (SystemClock.elapsedRealTime()) at which the first validation attempt concluded, 388 // or timed out after {@link ConnectivityService#PROMPT_UNVALIDATED_DELAY_MS}. 0 if not yet. 389 private long mFirstEvaluationConcludedTime; 390 391 /** 392 * Notify this NAI that this network has been evaluated. 393 * 394 * The stack considers that any result finding some working connectivity (valid, partial, 395 * captive portal) is an initial validation. Negative result (not valid), however, is not 396 * considered initial validation until {@link ConnectivityService#PROMPT_UNVALIDATED_DELAY_MS} 397 * have elapsed. This is because some networks may spuriously fail for a short time immediately 398 * after associating. If no positive result is found after the timeout has elapsed, then 399 * the network has been evaluated once. 400 * 401 * @return true the first time this is called on this object, then always returns false. 402 */ setEvaluated()403 public boolean setEvaluated() { 404 if (0L != mFirstEvaluationConcludedTime) return false; 405 mFirstEvaluationConcludedTime = SystemClock.elapsedRealtime(); 406 return true; 407 } 408 409 /** When this network ever concluded its first evaluation, or 0 if this never happened. */ 410 @VisibleForTesting getFirstEvaluationConcludedTime()411 public long getFirstEvaluationConcludedTime() { 412 return mFirstEvaluationConcludedTime; 413 } 414 415 // Delay between when the network is disconnected and when the native network is destroyed. 416 public int teardownDelayMs; 417 418 // Captive portal info of the network from RFC8908, if any. 419 // Obtained by ConnectivityService and merged into NetworkAgent-provided information. 420 public CaptivePortalData capportApiData; 421 422 // The UID of the remote entity that created this Network. 423 public final int creatorUid; 424 425 // Network agent portal info of the network, if any. This information is provided from 426 // non-RFC8908 sources, such as Wi-Fi Passpoint, which can provide information such as Venue 427 // URL, Terms & Conditions URL, and network friendly name. 428 public CaptivePortalData networkAgentPortalData; 429 430 // Indicate whether this device has the automotive feature. 431 private final boolean mHasAutomotiveFeature; 432 433 /** 434 * Checks that a proposed update to the NCs of this NAI satisfies structural constraints. 435 * 436 * Some changes to NetworkCapabilities are structurally not supported by the stack, and 437 * NetworkAgents are absolutely never allowed to try and do them. When one of these is 438 * violated, this method returns false, which has ConnectivityService disconnect the network ; 439 * this is meant to guarantee that no implementor ever tries to do this. 440 */ respectsNcStructuralConstraints(@onNull final NetworkCapabilities proposedNc)441 public boolean respectsNcStructuralConstraints(@NonNull final NetworkCapabilities proposedNc) { 442 if (networkCapabilities.hasCapability(NET_CAPABILITY_LOCAL_NETWORK) 443 != proposedNc.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)) { 444 return false; 445 } 446 return true; 447 } 448 449 /** 450 * Sets the capabilities sent by the agent for later retrieval. 451 * <p> 452 * This method does not sanitize the capabilities before storing them ; instead, use 453 * {@link #getDeclaredCapabilitiesSanitized} to retrieve a sanitized copy of the capabilities 454 * as they were passed here. 455 * <p> 456 * This method makes a defensive copy to avoid issues where the passed object is later mutated. 457 * 458 * @param caps the caps sent by the agent 459 */ setDeclaredCapabilities(@onNull final NetworkCapabilities caps)460 public void setDeclaredCapabilities(@NonNull final NetworkCapabilities caps) { 461 mDeclaredCapabilitiesUnsanitized = new NetworkCapabilities(caps); 462 } 463 464 /** 465 * Get the latest capabilities sent by the network agent, after sanitizing them. 466 * 467 * These are the capabilities as they were sent by the agent (but sanitized to conform to 468 * their restrictions). They are NOT the capabilities currently applying to this agent ; 469 * for that, use {@link #networkCapabilities}. 470 * 471 * Agents have restrictions on what capabilities they can send to Connectivity. For example, 472 * they can't change the owner UID from what they declared before, and complex restrictions 473 * apply to the allowedUids field. 474 * They also should not mutate immutable capabilities, although for backward-compatibility 475 * this is not enforced and limited to just a log. 476 * Forbidden capabilities also make no sense for networks, so they are disallowed and 477 * will be ignored with a warning. 478 * 479 * @param carrierPrivilegeAuthenticator the authenticator, to check access UIDs. 480 */ getDeclaredCapabilitiesSanitized( final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator)481 public NetworkCapabilities getDeclaredCapabilitiesSanitized( 482 final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) { 483 final NetworkCapabilities nc = new NetworkCapabilities(mDeclaredCapabilitiesUnsanitized); 484 if (nc.hasConnectivityManagedCapability()) { 485 Log.wtf(TAG, "BUG: " + this + " has CS-managed capability."); 486 nc.removeAllForbiddenCapabilities(); 487 } 488 if (networkCapabilities.getOwnerUid() != nc.getOwnerUid()) { 489 Log.e(TAG, toShortString() + ": ignoring attempt to change owner from " 490 + networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid()); 491 nc.setOwnerUid(networkCapabilities.getOwnerUid()); 492 } 493 restrictCapabilitiesFromNetworkAgent(nc, creatorUid, mHasAutomotiveFeature, 494 mConnServiceDeps, carrierPrivilegeAuthenticator); 495 return nc; 496 } 497 498 // Networks are lingered when they become unneeded as a result of their NetworkRequests being 499 // satisfied by a higher-scoring network. so as to allow communication to wrap up before the 500 // network is taken down. This usually only happens to the default network. Lingering ends with 501 // either the linger timeout expiring and the network being taken down, or the network 502 // satisfying a request again. 503 public static class InactivityTimer implements Comparable<InactivityTimer> { 504 public final int requestId; 505 public final long expiryMs; 506 InactivityTimer(int requestId, long expiryMs)507 public InactivityTimer(int requestId, long expiryMs) { 508 this.requestId = requestId; 509 this.expiryMs = expiryMs; 510 } equals(Object o)511 public boolean equals(Object o) { 512 if (!(o instanceof InactivityTimer)) return false; 513 InactivityTimer other = (InactivityTimer) o; 514 return (requestId == other.requestId) && (expiryMs == other.expiryMs); 515 } hashCode()516 public int hashCode() { 517 return Objects.hash(requestId, expiryMs); 518 } compareTo(InactivityTimer other)519 public int compareTo(InactivityTimer other) { 520 return (expiryMs != other.expiryMs) ? 521 Long.compare(expiryMs, other.expiryMs) : 522 Integer.compare(requestId, other.requestId); 523 } toString()524 public String toString() { 525 return String.format("%s, expires %dms", requestId, 526 expiryMs - SystemClock.elapsedRealtime()); 527 } 528 } 529 530 /** 531 * Inform ConnectivityService that the network LINGER period has 532 * expired. 533 * obj = this NetworkAgentInfo 534 */ 535 public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001; 536 537 /** 538 * Inform ConnectivityService that the agent is half-connected. 539 * arg1 = ARG_AGENT_SUCCESS or ARG_AGENT_FAILURE 540 * obj = NetworkAgentInfo 541 * @hide 542 */ 543 public static final int EVENT_AGENT_REGISTERED = 1002; 544 545 /** 546 * Inform ConnectivityService that the agent was disconnected. 547 * obj = NetworkAgentInfo 548 * @hide 549 */ 550 public static final int EVENT_AGENT_DISCONNECTED = 1003; 551 552 /** 553 * Argument for EVENT_AGENT_HALF_CONNECTED indicating failure. 554 */ 555 public static final int ARG_AGENT_FAILURE = 0; 556 557 /** 558 * Argument for EVENT_AGENT_HALF_CONNECTED indicating success. 559 */ 560 public static final int ARG_AGENT_SUCCESS = 1; 561 562 // How long this network should linger for. 563 private int mLingerDurationMs; 564 565 // All inactivity timers for this network, sorted by expiry time. A timer is added whenever 566 // a request is moved to a network with a better score, regardless of whether the network is or 567 // was lingering or not. An inactivity timer is also added when a network connects 568 // without immediately satisfying any requests. 569 // TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g., 570 // SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire. 571 private final SortedSet<InactivityTimer> mInactivityTimers = new TreeSet<>(); 572 573 // For fast lookups. Indexes into mInactivityTimers by request ID. 574 private final SparseArray<InactivityTimer> mInactivityTimerForRequest = new SparseArray<>(); 575 576 // Inactivity expiry timer. Armed whenever mInactivityTimers is non-empty, regardless of 577 // whether the network is inactive or not. Always set to the expiry of the mInactivityTimers 578 // that expires last. When the timer fires, all inactivity state is cleared, and if the network 579 // has no requests, it is torn down. 580 private WakeupMessage mInactivityMessage; 581 582 // Inactivity expiry. Holds the expiry time of the inactivity timer, or 0 if the timer is not 583 // armed. 584 private long mInactivityExpiryMs; 585 586 // Whether the network is inactive or not. Must be maintained separately from the above because 587 // it depends on the state of other networks and requests, which only ConnectivityService knows. 588 // (Example: we don't linger a network if it would become the best for a NetworkRequest if it 589 // validated). 590 private boolean mInactive; 591 592 // This represents the quality of the network. As opposed to NetworkScore, FullScore includes 593 // the ConnectivityService-managed bits. 594 private FullScore mScore; 595 596 // The list of NetworkRequests being satisfied by this Network. 597 private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); 598 599 // How many of the satisfied requests are actual requests and not listens. 600 private int mNumRequestNetworkRequests = 0; 601 602 // How many of the satisfied requests are of type BACKGROUND_REQUEST. 603 private int mNumBackgroundNetworkRequests = 0; 604 605 // The last ConnectivityReport made available for this network. This value is only null before a 606 // report is generated. Once non-null, it will never be null again. 607 @Nullable private ConnectivityReport mConnectivityReport; 608 609 public final INetworkAgent networkAgent; 610 // Only accessed from ConnectivityService handler thread 611 private final AgentDeathMonitor mDeathMonitor = new AgentDeathMonitor(); 612 613 public final int factorySerialNumber; 614 615 // Used by ConnectivityService to keep track of 464xlat. 616 public final Nat464Xlat clatd; 617 618 // Set after asynchronous creation of the NetworkMonitor. 619 private volatile NetworkMonitorManager mNetworkMonitor; 620 621 private static final String TAG = ConnectivityService.class.getSimpleName(); 622 private static final boolean VDBG = false; 623 private final ConnectivityService mConnService; 624 private final ConnectivityService.Dependencies mConnServiceDeps; 625 private final Context mContext; 626 private final Handler mHandler; 627 private final QosCallbackTracker mQosCallbackTracker; 628 629 private final long mCreationTime; 630 NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info, @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score, Context context, Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid, int lingerDurationMs, QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps)631 public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info, 632 @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, 633 @Nullable LocalNetworkConfig localNetworkConfig, 634 @NonNull NetworkScore score, Context context, 635 Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, 636 IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid, 637 int lingerDurationMs, QosCallbackTracker qosCallbackTracker, 638 ConnectivityService.Dependencies deps) { 639 Objects.requireNonNull(net); 640 Objects.requireNonNull(info); 641 Objects.requireNonNull(lp); 642 Objects.requireNonNull(nc); 643 Objects.requireNonNull(context); 644 Objects.requireNonNull(config); 645 Objects.requireNonNull(qosCallbackTracker); 646 networkAgent = na; 647 network = net; 648 networkInfo = info; 649 linkProperties = lp; 650 networkCapabilities = nc; 651 this.localNetworkConfig = localNetworkConfig; 652 networkAgentConfig = config; 653 mConnService = connService; 654 mConnServiceDeps = deps; 655 setScore(score); // uses members connService, networkCapabilities and networkAgentConfig 656 clatd = new Nat464Xlat(this, netd, dnsResolver, deps); 657 mContext = context; 658 mHandler = handler; 659 this.factorySerialNumber = factorySerialNumber; 660 this.creatorUid = creatorUid; 661 mLingerDurationMs = lingerDurationMs; 662 mQosCallbackTracker = qosCallbackTracker; 663 declaredUnderlyingNetworks = (nc.getUnderlyingNetworks() != null) 664 ? nc.getUnderlyingNetworks().toArray(new Network[0]) 665 : null; 666 mCreationTime = System.currentTimeMillis(); 667 mHasAutomotiveFeature = 668 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 669 } 670 671 private class AgentDeathMonitor implements IBinder.DeathRecipient { 672 @Override binderDied()673 public void binderDied() { 674 notifyDisconnected(); 675 } 676 } 677 678 /** 679 * Notify the NetworkAgent that it was registered, and should be unregistered if it dies. 680 * 681 * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be 682 * registered once. 683 */ notifyRegistered()684 public void notifyRegistered() { 685 try { 686 networkAgent.asBinder().linkToDeath(mDeathMonitor, 0); 687 networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler)); 688 } catch (RemoteException e) { 689 Log.e(TAG, "Error registering NetworkAgent", e); 690 maybeUnlinkDeathMonitor(); 691 mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_FAILURE, 0, this) 692 .sendToTarget(); 693 return; 694 } 695 696 mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget(); 697 } 698 699 /** 700 * Disconnect the NetworkAgent. Must be called from the ConnectivityService handler thread. 701 */ disconnect()702 public void disconnect() { 703 try { 704 networkAgent.onDisconnected(); 705 } catch (RemoteException e) { 706 Log.i(TAG, "Error disconnecting NetworkAgent", e); 707 // Fall through: it's fine if the remote has died 708 } 709 710 notifyDisconnected(); 711 maybeUnlinkDeathMonitor(); 712 } 713 maybeUnlinkDeathMonitor()714 private void maybeUnlinkDeathMonitor() { 715 try { 716 networkAgent.asBinder().unlinkToDeath(mDeathMonitor, 0); 717 } catch (NoSuchElementException e) { 718 // Was not linked: ignore 719 } 720 } 721 notifyDisconnected()722 private void notifyDisconnected() { 723 // Note this may be called multiple times if ConnectivityService disconnects while the 724 // NetworkAgent also dies. ConnectivityService ignores disconnects of already disconnected 725 // agents. 726 mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED, this).sendToTarget(); 727 } 728 729 /** 730 * Notify the NetworkAgent that bandwidth update was requested. 731 */ onBandwidthUpdateRequested()732 public void onBandwidthUpdateRequested() { 733 try { 734 networkAgent.onBandwidthUpdateRequested(); 735 } catch (RemoteException e) { 736 Log.e(TAG, "Error sending bandwidth update request event", e); 737 } 738 } 739 740 /** 741 * Notify the NetworkAgent that validation status has changed. 742 */ onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl)743 public void onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl) { 744 try { 745 networkAgent.onValidationStatusChanged(validationStatus, captivePortalUrl); 746 } catch (RemoteException e) { 747 Log.e(TAG, "Error sending validation status change event", e); 748 } 749 } 750 751 /** 752 * Notify the NetworkAgent that the acceptUnvalidated setting should be saved. 753 */ onSaveAcceptUnvalidated(boolean acceptUnvalidated)754 public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { 755 try { 756 networkAgent.onSaveAcceptUnvalidated(acceptUnvalidated); 757 } catch (RemoteException e) { 758 Log.e(TAG, "Error sending accept unvalidated event", e); 759 } 760 } 761 762 /** 763 * Notify the NetworkAgent that NATT socket keepalive should be started. 764 */ onStartNattSocketKeepalive(int slot, int intervalDurationMs, @NonNull NattKeepalivePacketData packetData)765 public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, 766 @NonNull NattKeepalivePacketData packetData) { 767 try { 768 networkAgent.onStartNattSocketKeepalive(slot, intervalDurationMs, packetData); 769 } catch (RemoteException e) { 770 Log.e(TAG, "Error sending NATT socket keepalive start event", e); 771 } 772 } 773 774 /** 775 * Notify the NetworkAgent that TCP socket keepalive should be started. 776 */ onStartTcpSocketKeepalive(int slot, int intervalDurationMs, @NonNull TcpKeepalivePacketData packetData)777 public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, 778 @NonNull TcpKeepalivePacketData packetData) { 779 try { 780 networkAgent.onStartTcpSocketKeepalive(slot, intervalDurationMs, packetData); 781 } catch (RemoteException e) { 782 Log.e(TAG, "Error sending TCP socket keepalive start event", e); 783 } 784 } 785 786 /** 787 * Notify the NetworkAgent that socket keepalive should be stopped. 788 */ onStopSocketKeepalive(int slot)789 public void onStopSocketKeepalive(int slot) { 790 try { 791 networkAgent.onStopSocketKeepalive(slot); 792 } catch (RemoteException e) { 793 Log.e(TAG, "Error sending TCP socket keepalive stop event", e); 794 } 795 } 796 797 /** 798 * Notify the NetworkAgent that signal strength thresholds should be updated. 799 */ onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)800 public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { 801 try { 802 networkAgent.onSignalStrengthThresholdsUpdated(thresholds); 803 } catch (RemoteException e) { 804 Log.e(TAG, "Error sending signal strength thresholds event", e); 805 } 806 } 807 808 /** 809 * Notify the NetworkAgent that automatic reconnect should be prevented. 810 */ onPreventAutomaticReconnect()811 public void onPreventAutomaticReconnect() { 812 try { 813 networkAgent.onPreventAutomaticReconnect(); 814 } catch (RemoteException e) { 815 Log.e(TAG, "Error sending prevent automatic reconnect event", e); 816 } 817 } 818 819 /** 820 * Notify the NetworkAgent that a NATT keepalive packet filter should be added. 821 */ onAddNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketData packetData)822 public void onAddNattKeepalivePacketFilter(int slot, 823 @NonNull NattKeepalivePacketData packetData) { 824 try { 825 networkAgent.onAddNattKeepalivePacketFilter(slot, packetData); 826 } catch (RemoteException e) { 827 Log.e(TAG, "Error sending add NATT keepalive packet filter event", e); 828 } 829 } 830 831 /** 832 * Notify the NetworkAgent that a TCP keepalive packet filter should be added. 833 */ onAddTcpKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketData packetData)834 public void onAddTcpKeepalivePacketFilter(int slot, 835 @NonNull TcpKeepalivePacketData packetData) { 836 try { 837 networkAgent.onAddTcpKeepalivePacketFilter(slot, packetData); 838 } catch (RemoteException e) { 839 Log.e(TAG, "Error sending add TCP keepalive packet filter event", e); 840 } 841 } 842 843 /** 844 * Notify the NetworkAgent that a keepalive packet filter should be removed. 845 */ onRemoveKeepalivePacketFilter(int slot)846 public void onRemoveKeepalivePacketFilter(int slot) { 847 try { 848 networkAgent.onRemoveKeepalivePacketFilter(slot); 849 } catch (RemoteException e) { 850 Log.e(TAG, "Error sending remove keepalive packet filter event", e); 851 } 852 } 853 854 /** 855 * Notify the NetworkAgent that the qos filter should be registered against the given qos 856 * callback id. 857 */ onQosFilterCallbackRegistered(final int qosCallbackId, final QosFilter qosFilter)858 public void onQosFilterCallbackRegistered(final int qosCallbackId, 859 final QosFilter qosFilter) { 860 try { 861 networkAgent.onQosFilterCallbackRegistered(qosCallbackId, 862 new QosFilterParcelable(qosFilter)); 863 } catch (final RemoteException e) { 864 Log.e(TAG, "Error registering a qos callback id against a qos filter", e); 865 } 866 } 867 868 /** 869 * Notify the NetworkAgent that the given qos callback id should be unregistered. 870 */ onQosCallbackUnregistered(final int qosCallbackId)871 public void onQosCallbackUnregistered(final int qosCallbackId) { 872 try { 873 networkAgent.onQosCallbackUnregistered(qosCallbackId); 874 } catch (RemoteException e) { 875 Log.e(TAG, "Error unregistering a qos callback id", e); 876 } 877 } 878 879 /** 880 * Notify the NetworkAgent that the network is successfully connected. 881 */ onNetworkCreated()882 public void onNetworkCreated() { 883 try { 884 networkAgent.onNetworkCreated(); 885 } catch (RemoteException e) { 886 Log.e(TAG, "Error sending network created event", e); 887 } 888 } 889 890 /** 891 * Notify the NetworkAgent that the native network has been destroyed. 892 */ onNetworkDestroyed()893 public void onNetworkDestroyed() { 894 try { 895 networkAgent.onNetworkDestroyed(); 896 } catch (RemoteException e) { 897 Log.e(TAG, "Error sending network destroyed event", e); 898 } 899 } 900 901 // TODO: consider moving out of NetworkAgentInfo into its own class 902 private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub { 903 private final Handler mHandler; 904 NetworkAgentMessageHandler(Handler handler)905 private NetworkAgentMessageHandler(Handler handler) { 906 mHandler = handler; 907 } 908 909 @Override sendNetworkCapabilities(@onNull NetworkCapabilities nc)910 public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) { 911 Objects.requireNonNull(nc); 912 mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, 913 new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget(); 914 } 915 916 @Override sendLinkProperties(@onNull LinkProperties lp)917 public void sendLinkProperties(@NonNull LinkProperties lp) { 918 Objects.requireNonNull(lp); 919 mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, 920 new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget(); 921 } 922 923 @Override sendNetworkInfo(@onNull NetworkInfo info)924 public void sendNetworkInfo(@NonNull NetworkInfo info) { 925 Objects.requireNonNull(info); 926 mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED, 927 new Pair<>(NetworkAgentInfo.this, info)).sendToTarget(); 928 } 929 930 @Override sendLocalNetworkConfig(@onNull final LocalNetworkConfig config)931 public void sendLocalNetworkConfig(@NonNull final LocalNetworkConfig config) { 932 mHandler.obtainMessage(NetworkAgent.EVENT_LOCAL_NETWORK_CONFIG_CHANGED, 933 new Pair<>(NetworkAgentInfo.this, config)).sendToTarget(); 934 } 935 936 @Override sendScore(@onNull final NetworkScore score)937 public void sendScore(@NonNull final NetworkScore score) { 938 mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, 939 new Pair<>(NetworkAgentInfo.this, score)).sendToTarget(); 940 } 941 942 @Override sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial)943 public void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial) { 944 mHandler.obtainMessage(NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED, 945 explicitlySelected ? 1 : 0, acceptPartial ? 1 : 0, 946 new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); 947 } 948 949 @Override sendSocketKeepaliveEvent(int slot, int reason)950 public void sendSocketKeepaliveEvent(int slot, int reason) { 951 mHandler.obtainMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE, 952 slot, reason, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); 953 } 954 955 @Override sendUnderlyingNetworks(@ullable List<Network> networks)956 public void sendUnderlyingNetworks(@Nullable List<Network> networks) { 957 mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED, 958 new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget(); 959 } 960 961 @Override sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session, final EpsBearerQosSessionAttributes attributes)962 public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session, 963 final EpsBearerQosSessionAttributes attributes) { 964 mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes); 965 } 966 967 @Override sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session, final NrQosSessionAttributes attributes)968 public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session, 969 final NrQosSessionAttributes attributes) { 970 mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes); 971 } 972 973 @Override sendQosSessionLost(final int qosCallbackId, final QosSession session)974 public void sendQosSessionLost(final int qosCallbackId, final QosSession session) { 975 mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session); 976 } 977 978 @Override sendQosCallbackError(final int qosCallbackId, @QosCallbackException.ExceptionType final int exceptionType)979 public void sendQosCallbackError(final int qosCallbackId, 980 @QosCallbackException.ExceptionType final int exceptionType) { 981 mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType); 982 } 983 984 @Override sendTeardownDelayMs(int teardownDelayMs)985 public void sendTeardownDelayMs(int teardownDelayMs) { 986 mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED, 987 teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); 988 } 989 990 @Override sendLingerDuration(final int durationMs)991 public void sendLingerDuration(final int durationMs) { 992 mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED, 993 new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget(); 994 } 995 996 @Override sendAddDscpPolicy(final DscpPolicy policy)997 public void sendAddDscpPolicy(final DscpPolicy policy) { 998 mHandler.obtainMessage(NetworkAgent.EVENT_ADD_DSCP_POLICY, 999 new Pair<>(NetworkAgentInfo.this, policy)).sendToTarget(); 1000 } 1001 1002 @Override sendRemoveDscpPolicy(final int policyId)1003 public void sendRemoveDscpPolicy(final int policyId) { 1004 mHandler.obtainMessage(NetworkAgent.EVENT_REMOVE_DSCP_POLICY, 1005 new Pair<>(NetworkAgentInfo.this, policyId)).sendToTarget(); 1006 } 1007 1008 @Override sendRemoveAllDscpPolicies()1009 public void sendRemoveAllDscpPolicies() { 1010 mHandler.obtainMessage(NetworkAgent.EVENT_REMOVE_ALL_DSCP_POLICIES, 1011 new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); 1012 } 1013 1014 @Override sendUnregisterAfterReplacement(final int timeoutMillis)1015 public void sendUnregisterAfterReplacement(final int timeoutMillis) { 1016 mHandler.obtainMessage(NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT, 1017 new Pair<>(NetworkAgentInfo.this, timeoutMillis)).sendToTarget(); 1018 } 1019 } 1020 1021 /** 1022 * Inform NetworkAgentInfo that a new NetworkMonitor was created. 1023 */ onNetworkMonitorCreated(INetworkMonitor networkMonitor)1024 public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) { 1025 mNetworkMonitor = new NetworkMonitorManager(networkMonitor); 1026 } 1027 1028 /** 1029 * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor 1030 * of the new capabilities, if NetworkMonitor has been created. 1031 * 1032 * <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails, 1033 * the exception is logged but not reported to callers. 1034 * 1035 * @return the old capabilities of this network. 1036 */ getAndSetNetworkCapabilities( @onNull final NetworkCapabilities nc)1037 @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities( 1038 @NonNull final NetworkCapabilities nc) { 1039 final NetworkCapabilities oldNc = networkCapabilities; 1040 networkCapabilities = nc; 1041 updateScoreForNetworkAgentUpdate(); 1042 final NetworkMonitorManager nm = mNetworkMonitor; 1043 if (nm != null) { 1044 nm.notifyNetworkCapabilitiesChanged(nc); 1045 } 1046 return oldNc; 1047 } 1048 yieldToBadWiFi()1049 private boolean yieldToBadWiFi() { 1050 // Only cellular networks yield to bad wifi 1051 return networkCapabilities.hasTransport(TRANSPORT_CELLULAR) && !mConnService.avoidBadWifi(); 1052 } 1053 connService()1054 public ConnectivityService connService() { 1055 return mConnService; 1056 } 1057 netAgentConfig()1058 public NetworkAgentConfig netAgentConfig() { 1059 return networkAgentConfig; 1060 } 1061 handler()1062 public Handler handler() { 1063 return mHandler; 1064 } 1065 network()1066 public Network network() { 1067 return network; 1068 } 1069 1070 /** 1071 * Get the generated v6 address of clat. 1072 */ 1073 @Nullable getClatv6SrcAddress()1074 public Inet6Address getClatv6SrcAddress() { 1075 return clatd.getClatv6SrcAddress(); 1076 } 1077 1078 /** 1079 * Get the generated v4 address of clat. 1080 */ 1081 @Nullable getClatv4SrcAddress()1082 public Inet4Address getClatv4SrcAddress() { 1083 return clatd.getClatv4SrcAddress(); 1084 } 1085 1086 /** 1087 * Translate the input v4 address to v6 clat address. 1088 */ 1089 @Nullable translateV4toClatV6(@onNull Inet4Address addr)1090 public Inet6Address translateV4toClatV6(@NonNull Inet4Address addr) { 1091 return clatd.translateV4toV6(addr); 1092 } 1093 1094 /** 1095 * Get the NetworkMonitorManager in this NetworkAgentInfo. 1096 * 1097 * <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called. 1098 */ networkMonitor()1099 public NetworkMonitorManager networkMonitor() { 1100 return mNetworkMonitor; 1101 } 1102 1103 // Functions for manipulating the requests satisfied by this network. 1104 // 1105 // These functions must only called on ConnectivityService's main thread. 1106 1107 private static final boolean ADD = true; 1108 private static final boolean REMOVE = false; 1109 updateRequestCounts(boolean add, NetworkRequest request)1110 private void updateRequestCounts(boolean add, NetworkRequest request) { 1111 int delta = add ? +1 : -1; 1112 switch (request.type) { 1113 case REQUEST: 1114 mNumRequestNetworkRequests += delta; 1115 break; 1116 1117 case BACKGROUND_REQUEST: 1118 mNumRequestNetworkRequests += delta; 1119 mNumBackgroundNetworkRequests += delta; 1120 break; 1121 1122 case LISTEN: 1123 case LISTEN_FOR_BEST: 1124 case TRACK_DEFAULT: 1125 case TRACK_SYSTEM_DEFAULT: 1126 break; 1127 1128 case NONE: 1129 default: 1130 Log.wtf(TAG, "Unhandled request type " + request.type); 1131 break; 1132 } 1133 } 1134 1135 /** 1136 * Add {@code networkRequest} to this network as it's satisfied by this network. 1137 * @return true if {@code networkRequest} was added or false if {@code networkRequest} was 1138 * already present. 1139 */ addRequest(NetworkRequest networkRequest)1140 public boolean addRequest(NetworkRequest networkRequest) { 1141 if (mHandler.getLooper().getThread() != Thread.currentThread()) { 1142 throw new IllegalStateException( 1143 "Not running on ConnectivityService thread: " 1144 + Thread.currentThread().getName()); 1145 } 1146 NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); 1147 if (existing == networkRequest) return false; 1148 if (existing != null) { 1149 // Should only happen if the requestId wraps. If that happens lots of other things will 1150 // be broken as well. 1151 Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s", 1152 networkRequest, existing, toShortString())); 1153 updateRequestCounts(REMOVE, existing); 1154 } 1155 mNetworkRequests.put(networkRequest.requestId, networkRequest); 1156 updateRequestCounts(ADD, networkRequest); 1157 return true; 1158 } 1159 1160 /** 1161 * Remove the specified request from this network. 1162 */ removeRequest(int requestId)1163 public void removeRequest(int requestId) { 1164 if (mHandler.getLooper().getThread() != Thread.currentThread()) { 1165 throw new IllegalStateException( 1166 "Not running on ConnectivityService thread: " 1167 + Thread.currentThread().getName()); 1168 } 1169 NetworkRequest existing = mNetworkRequests.get(requestId); 1170 if (existing == null) return; 1171 updateRequestCounts(REMOVE, existing); 1172 mNetworkRequests.remove(requestId); 1173 if (existing.isRequest()) { 1174 unlingerRequest(existing.requestId); 1175 } 1176 } 1177 1178 /** 1179 * Returns whether this network is currently satisfying the request with the specified ID. 1180 */ isSatisfyingRequest(int id)1181 public boolean isSatisfyingRequest(int id) { 1182 return mNetworkRequests.get(id) != null; 1183 } 1184 1185 /** 1186 * Returns the request at the specified position in the list of requests satisfied by this 1187 * network. 1188 */ requestAt(int index)1189 public NetworkRequest requestAt(int index) { 1190 if (mHandler.getLooper().getThread() != Thread.currentThread()) { 1191 throw new IllegalStateException( 1192 "Not running on ConnectivityService thread: " 1193 + Thread.currentThread().getName()); 1194 } 1195 return mNetworkRequests.valueAt(index); 1196 } 1197 1198 /** 1199 * Returns the number of requests currently satisfied by this network for which 1200 * {@link android.net.NetworkRequest#isRequest} returns {@code true}. 1201 */ numRequestNetworkRequests()1202 public int numRequestNetworkRequests() { 1203 return mNumRequestNetworkRequests; 1204 } 1205 1206 /** 1207 * Returns the number of requests currently satisfied by this network of type 1208 * {@link android.net.NetworkRequest.Type#BACKGROUND_REQUEST}. 1209 */ numBackgroundNetworkRequests()1210 public int numBackgroundNetworkRequests() { 1211 return mNumBackgroundNetworkRequests; 1212 } 1213 1214 /** 1215 * Returns the number of foreground requests currently satisfied by this network. 1216 */ numForegroundNetworkRequests()1217 public int numForegroundNetworkRequests() { 1218 return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests; 1219 } 1220 1221 /** 1222 * Returns the number of requests of any type currently satisfied by this network. 1223 */ numNetworkRequests()1224 public int numNetworkRequests() { 1225 if (mHandler.getLooper().getThread() != Thread.currentThread()) { 1226 throw new IllegalStateException( 1227 "Not running on ConnectivityService thread: " 1228 + Thread.currentThread().getName()); 1229 } 1230 return mNetworkRequests.size(); 1231 } 1232 1233 /** 1234 * Returns whether the network is a background network. A network is a background network if it 1235 * does not have the NET_CAPABILITY_FOREGROUND capability, which implies it is satisfying no 1236 * foreground request, is not lingering (i.e. kept for a while after being outscored), and is 1237 * not a speculative network (i.e. kept pending validation when validation would have it 1238 * outscore another foreground network). That implies it is being kept up by some background 1239 * request (otherwise it would be torn down), maybe the mobile always-on request. 1240 */ isBackgroundNetwork()1241 public boolean isBackgroundNetwork() { 1242 return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0 1243 && !isLingering(); 1244 } 1245 1246 // Does this network satisfy request? satisfies(NetworkRequest request)1247 public boolean satisfies(NetworkRequest request) { 1248 return everConnected() 1249 && request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities); 1250 } 1251 satisfiesImmutableCapabilitiesOf(NetworkRequest request)1252 public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) { 1253 return everConnected() 1254 && request.networkCapabilities.satisfiedByImmutableNetworkCapabilities( 1255 networkCapabilities); 1256 } 1257 1258 /** Whether this network is a VPN. */ isVPN()1259 public boolean isVPN() { 1260 return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN); 1261 } 1262 1263 /** Whether this network is a local network */ isLocalNetwork()1264 public boolean isLocalNetwork() { 1265 return networkCapabilities.hasCapability(NET_CAPABILITY_LOCAL_NETWORK); 1266 } 1267 1268 /** 1269 * Whether this network should propagate the capabilities from its underlying networks. 1270 * Currently only true for VPNs. 1271 */ propagateUnderlyingCapabilities()1272 public boolean propagateUnderlyingCapabilities() { 1273 return isVPN(); 1274 } 1275 1276 // Caller must not mutate. This method is called frequently and making a defensive copy 1277 // would be too expensive. This is used by NetworkRanker.Scoreable, so it can be compared 1278 // against other scoreables. getCapsNoCopy()1279 @Override public NetworkCapabilities getCapsNoCopy() { 1280 return networkCapabilities; 1281 } 1282 1283 // NetworkRanker.Scoreable getScore()1284 @Override public FullScore getScore() { 1285 return mScore; 1286 } 1287 1288 /** 1289 * Mix-in the ConnectivityService-managed bits in the score. 1290 */ setScore(final NetworkScore score)1291 public void setScore(final NetworkScore score) { 1292 final FullScore oldScore = mScore; 1293 mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig, 1294 everValidated(), 0L != getAvoidUnvalidated(), yieldToBadWiFi(), 1295 0L != mFirstEvaluationConcludedTime, isDestroyed()); 1296 maybeLogDifferences(oldScore); 1297 } 1298 1299 /** 1300 * Update the ConnectivityService-managed bits in the score. 1301 * 1302 * Call this after changing any data that might affect the score (e.g., agent config). 1303 */ updateScoreForNetworkAgentUpdate()1304 public void updateScoreForNetworkAgentUpdate() { 1305 final FullScore oldScore = mScore; 1306 mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, 1307 everValidated(), 0L != getAvoidUnvalidated(), yieldToBadWiFi(), 1308 0L != mFirstEvaluationConcludedTime, isDestroyed()); 1309 maybeLogDifferences(oldScore); 1310 } 1311 1312 /** 1313 * Prints score differences to logcat, if any. 1314 * @param oldScore the old score. Differences from |oldScore| to |this| are logged, if any. 1315 */ maybeLogDifferences(final FullScore oldScore)1316 public void maybeLogDifferences(final FullScore oldScore) { 1317 final String differences = mScore.describeDifferencesFrom(oldScore); 1318 if (null != differences) { 1319 Log.i(TAG, "Update score for net " + network + " : " + differences); 1320 } 1321 } 1322 1323 /** 1324 * Returns a Scoreable identical to this NAI, but validated. 1325 * 1326 * This is useful to probe what scoring would be if this network validated, to know 1327 * whether to provisionally keep a network that may or may not validate. 1328 * 1329 * @return a Scoreable identical to this NAI, but validated. 1330 */ getValidatedScoreable()1331 public NetworkRanker.Scoreable getValidatedScoreable() { 1332 return new NetworkRanker.Scoreable() { 1333 @Override public FullScore getScore() { 1334 return mScore.asValidated(); 1335 } 1336 1337 @Override public NetworkCapabilities getCapsNoCopy() { 1338 return networkCapabilities; 1339 } 1340 }; 1341 } 1342 1343 /** 1344 * Return a {@link NetworkStateSnapshot} for this network. 1345 */ 1346 @NonNull 1347 public NetworkStateSnapshot getNetworkStateSnapshot() { 1348 synchronized (this) { 1349 // Network objects are outwardly immutable so there is no point in duplicating. 1350 // Duplicating also precludes sharing socket factories and connection pools. 1351 final String subscriberId = (networkAgentConfig != null) 1352 ? networkAgentConfig.subscriberId : null; 1353 return new NetworkStateSnapshot(network, new NetworkCapabilities(networkCapabilities), 1354 new LinkProperties(linkProperties), subscriberId, networkInfo.getType()); 1355 } 1356 } 1357 1358 /** 1359 * Sets the specified requestId to linger on this network for the specified time. Called by 1360 * ConnectivityService when any request is moved to another network with a higher score, or 1361 * when a network is newly created. 1362 * 1363 * @param requestId The requestId of the request that no longer need to be served by this 1364 * network. Or {@link NetworkRequest#REQUEST_ID_NONE} if this is the 1365 * {@code InactivityTimer} for a newly created network. 1366 */ 1367 // TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent. 1368 public void lingerRequest(int requestId, long now, long duration) { 1369 if (mInactivityTimerForRequest.get(requestId) != null) { 1370 // Cannot happen. Once a request is lingering on a particular network, we cannot 1371 // re-linger it unless that network becomes the best for that request again, in which 1372 // case we should have unlingered it. 1373 Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered"); 1374 } 1375 final long expiryMs = now + duration; 1376 InactivityTimer timer = new InactivityTimer(requestId, expiryMs); 1377 if (VDBG) Log.d(TAG, "Adding InactivityTimer " + timer + " to " + toShortString()); 1378 mInactivityTimers.add(timer); 1379 mInactivityTimerForRequest.put(requestId, timer); 1380 } 1381 1382 /** 1383 * Sets the specified requestId to linger on this network for the timeout set when 1384 * initializing or modified by {@link #setLingerDuration(int)}. Called by 1385 * ConnectivityService when any request is moved to another network with a higher score. 1386 * 1387 * @param requestId The requestId of the request that no longer need to be served by this 1388 * network. 1389 * @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}. 1390 */ 1391 public void lingerRequest(int requestId, long now) { 1392 lingerRequest(requestId, now, mLingerDurationMs); 1393 } 1394 1395 /** 1396 * Cancel lingering. Called by ConnectivityService when a request is added to this network. 1397 * Returns true if the given requestId was lingering on this network, false otherwise. 1398 */ 1399 public boolean unlingerRequest(int requestId) { 1400 InactivityTimer timer = mInactivityTimerForRequest.get(requestId); 1401 if (timer != null) { 1402 if (VDBG) { 1403 Log.d(TAG, "Removing InactivityTimer " + timer + " from " + toShortString()); 1404 } 1405 mInactivityTimers.remove(timer); 1406 mInactivityTimerForRequest.remove(requestId); 1407 return true; 1408 } 1409 return false; 1410 } 1411 1412 public long getInactivityExpiry() { 1413 return mInactivityExpiryMs; 1414 } 1415 1416 public void updateInactivityTimer() { 1417 long newExpiry = mInactivityTimers.isEmpty() ? 0 : mInactivityTimers.last().expiryMs; 1418 if (newExpiry == mInactivityExpiryMs) return; 1419 1420 // Even if we're going to reschedule the timer, cancel it first. This is because the 1421 // semantics of WakeupMessage guarantee that if cancel is called then the alarm will 1422 // never call its callback (handleLingerComplete), even if it has already fired. 1423 // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage 1424 // has already been dispatched, rescheduling to some time in the future won't stop it 1425 // from calling its callback immediately. 1426 if (mInactivityMessage != null) { 1427 mInactivityMessage.cancel(); 1428 mInactivityMessage = null; 1429 } 1430 1431 if (newExpiry > 0) { 1432 // If the newExpiry timestamp is in the past, the wakeup message will fire immediately. 1433 mInactivityMessage = new WakeupMessage( 1434 mContext, mHandler, 1435 "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */, 1436 EVENT_NETWORK_LINGER_COMPLETE /* cmd */, 1437 0 /* arg1 (unused) */, 0 /* arg2 (unused) */, 1438 this /* obj (NetworkAgentInfo) */); 1439 mInactivityMessage.schedule(newExpiry); 1440 } 1441 1442 mInactivityExpiryMs = newExpiry; 1443 } 1444 1445 public void setInactive() { 1446 mInactive = true; 1447 } 1448 1449 public void unsetInactive() { 1450 mInactive = false; 1451 } 1452 1453 public boolean isInactive() { 1454 return mInactive; 1455 } 1456 1457 public boolean isLingering() { 1458 return mInactive && !isNascent(); 1459 } 1460 1461 /** 1462 * Set the linger duration for this NAI. 1463 * @param durationMs The new linger duration, in milliseconds. 1464 */ 1465 public void setLingerDuration(final int durationMs) { 1466 final long diff = durationMs - mLingerDurationMs; 1467 final ArrayList<InactivityTimer> newTimers = new ArrayList<>(); 1468 for (final InactivityTimer timer : mInactivityTimers) { 1469 if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) { 1470 // Don't touch nascent timer, re-add as is. 1471 newTimers.add(timer); 1472 } else { 1473 newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff)); 1474 } 1475 } 1476 mInactivityTimers.clear(); 1477 mInactivityTimers.addAll(newTimers); 1478 updateInactivityTimer(); 1479 mLingerDurationMs = durationMs; 1480 } 1481 1482 /** 1483 * Return whether the network satisfies no request, but is still being kept up 1484 * because it has just connected less than 1485 * {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered 1486 * nascent. Note that nascent mechanism uses inactivity timer which isn't 1487 * associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it. 1488 * 1489 */ 1490 public boolean isNascent() { 1491 return mInactive && mInactivityTimers.size() == 1 1492 && mInactivityTimers.first().requestId == NetworkRequest.REQUEST_ID_NONE; 1493 } 1494 1495 public void clearInactivityState() { 1496 if (mInactivityMessage != null) { 1497 mInactivityMessage.cancel(); 1498 mInactivityMessage = null; 1499 } 1500 mInactivityTimers.clear(); 1501 mInactivityTimerForRequest.clear(); 1502 // Sets mInactivityExpiryMs, cancels and nulls out mInactivityMessage. 1503 updateInactivityTimer(); 1504 mInactive = false; 1505 } 1506 1507 public void dumpInactivityTimers(PrintWriter pw) { 1508 for (InactivityTimer timer : mInactivityTimers) { 1509 pw.println(timer); 1510 } 1511 } 1512 1513 /** 1514 * Dump the NAT64 xlat information. 1515 * 1516 * @param pw print writer. 1517 */ 1518 public void dumpNat464Xlat(IndentingPrintWriter pw) { 1519 clatd.dump(pw); 1520 } 1521 1522 /** 1523 * Sets the most recent ConnectivityReport for this network. 1524 * 1525 * <p>This should only be called from the ConnectivityService thread. 1526 * 1527 * @hide 1528 */ 1529 public void setConnectivityReport(@NonNull ConnectivityReport connectivityReport) { 1530 mConnectivityReport = connectivityReport; 1531 } 1532 1533 /** 1534 * Returns the most recent ConnectivityReport for this network, or null if none have been 1535 * reported yet. 1536 * 1537 * <p>This should only be called from the ConnectivityService thread. 1538 * 1539 * @hide 1540 */ 1541 @Nullable 1542 public ConnectivityReport getConnectivityReport() { 1543 return mConnectivityReport; 1544 } 1545 1546 /** 1547 * Make sure the NC from network agents don't contain stuff they shouldn't. 1548 * 1549 * @param nc the capabilities to sanitize 1550 * @param creatorUid the UID of the process creating this network agent 1551 * @param hasAutomotiveFeature true if this device has the automotive feature, false otherwise 1552 * @param authenticator the carrier privilege authenticator to check for telephony constraints 1553 */ 1554 public static void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc, 1555 final int creatorUid, final boolean hasAutomotiveFeature, 1556 @NonNull final ConnectivityService.Dependencies deps, 1557 @Nullable final CarrierPrivilegeAuthenticator authenticator) { 1558 if (nc.hasTransport(TRANSPORT_TEST)) { 1559 nc.restrictCapabilitiesForTestNetwork(creatorUid); 1560 } 1561 if (!areAllowedUidsAcceptableFromNetworkAgent( 1562 nc, hasAutomotiveFeature, deps, authenticator)) { 1563 nc.setAllowedUids(new ArraySet<>()); 1564 } 1565 } 1566 1567 private static boolean areAllowedUidsAcceptableFromNetworkAgent( 1568 @NonNull final NetworkCapabilities nc, final boolean hasAutomotiveFeature, 1569 @NonNull final ConnectivityService.Dependencies deps, 1570 @Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) { 1571 // NCs without access UIDs are fine. 1572 if (!nc.hasAllowedUids()) return true; 1573 // S and below must never accept access UIDs, even if an agent sends them, because netd 1574 // didn't support the required feature in S. 1575 if (!deps.isAtLeastT()) return false; 1576 1577 // On a non-restricted network, access UIDs make no sense 1578 if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) return false; 1579 1580 // If this network has TRANSPORT_TEST and nothing else, then the caller can do whatever 1581 // they want to access UIDs 1582 if (nc.hasSingleTransport(TRANSPORT_TEST)) return true; 1583 1584 if (nc.hasTransport(TRANSPORT_ETHERNET)) { 1585 // Factories that make ethernet networks can allow UIDs for automotive devices. 1586 if (hasAutomotiveFeature) return true; 1587 // It's also admissible if the ethernet network has TRANSPORT_TEST, as long as it 1588 // doesn't have NET_CAPABILITY_INTERNET so it can't become the default network. 1589 if (nc.hasTransport(TRANSPORT_TEST) && !nc.hasCapability(NET_CAPABILITY_INTERNET)) { 1590 return true; 1591 } 1592 return false; 1593 } 1594 1595 // Factories that make cell/wifi networks can allow the UID for the carrier service package. 1596 // This can only work in T where there is support for CarrierPrivilegeAuthenticator 1597 if (null != carrierPrivilegeAuthenticator 1598 && (nc.hasSingleTransportBesidesTest(TRANSPORT_CELLULAR) 1599 || nc.hasSingleTransportBesidesTest(TRANSPORT_WIFI)) 1600 && (1 == nc.getAllowedUidsNoCopy().size()) 1601 && (carrierPrivilegeAuthenticator.isCarrierServiceUidForNetworkCapabilities( 1602 nc.getAllowedUidsNoCopy().valueAt(0), nc))) { 1603 return true; 1604 } 1605 1606 return false; 1607 } 1608 1609 // TODO: Print shorter members first and only print the boolean variable which value is true 1610 // to improve readability. 1611 public String toString() { 1612 return "NetworkAgentInfo{" 1613 + "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{" 1614 + networkInfo.toShortString() + "} " 1615 + "created=" + Instant.ofEpochMilli(mCreationTime) + " " 1616 + mScore + " " 1617 + (isCreated() ? " created " + getCreatedTime() : "") 1618 + (isDestroyed() ? " destroyed " + mDestroyedTime : "") 1619 + (isNascent() ? " nascent" : (isLingering() ? " lingering" : "")) 1620 + (everValidated() ? " firstValidated " + getFirstValidationTime() : "") 1621 + (isValidated() ? " lastValidated " + getCurrentValidationTime() : "") 1622 + (partialConnectivity() 1623 ? " partialConnectivity " + mPartialConnectivityTime : "") 1624 + (everCaptivePortalDetected() 1625 ? " firstCaptivePortalDetected " + mFirstCaptivePortalDetectedTime : "") 1626 + (captivePortalDetected() 1627 ? " currentCaptivePortalDetected " + mCurrentCaptivePortalDetectedTime : "") 1628 + (networkAgentConfig.explicitlySelected ? " explicitlySelected" : "") 1629 + (networkAgentConfig.acceptUnvalidated ? " acceptUnvalidated" : "") 1630 + (networkAgentConfig.acceptPartialConnectivity ? " acceptPartialConnectivity" : "") 1631 + (clatd.isStarted() ? " clat{" + clatd + "} " : "") 1632 + (declaredUnderlyingNetworks != null 1633 ? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "") 1634 + " lp{" + linkProperties + "}" 1635 + " nc{" + networkCapabilities + "}" 1636 + " factorySerialNumber=" + factorySerialNumber 1637 + "}"; 1638 } 1639 1640 /** 1641 * Show a short string representing a Network. 1642 * 1643 * This is often not enough for debugging purposes for anything complex, but the full form 1644 * is very long and hard to read, so this is useful when there isn't a lot of ambiguity. 1645 * This represents the network with something like "[100 WIFI|VPN]" or "[108 CELLULAR]". 1646 */ 1647 public String toShortString() { 1648 return "[" + network.getNetId() + " " 1649 + transportNamesOf(networkCapabilities.getTransportTypes()) + "]"; 1650 } 1651 1652 /** 1653 * Null-guarding version of NetworkAgentInfo#toShortString() 1654 */ 1655 @NonNull 1656 public static String toShortString(@Nullable final NetworkAgentInfo nai) { 1657 return null != nai ? nai.toShortString() : "[null]"; 1658 } 1659 } 1660