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