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