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