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