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