• 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.Messenger;
31 import android.os.SystemClock;
32 import android.util.Log;
33 import android.util.SparseArray;
34 
35 import com.android.internal.util.AsyncChannel;
36 import com.android.internal.util.WakeupMessage;
37 import com.android.server.ConnectivityService;
38 import com.android.server.connectivity.NetworkMonitor;
39 
40 import java.io.PrintWriter;
41 import java.util.ArrayList;
42 import java.util.Comparator;
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 // If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
108 // the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
109 // highest scoring network for any NetworkRequest, then there will be a 30s pause before
110 // ConnectivityService disconnects the NetworkAgent's AsyncChannel.  During this pause the
111 // network is considered "lingering".  This pause exists to allow network communication to be
112 // wrapped up rather than abruptly terminated.  During this pause if the network begins satisfying
113 // a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
114 // AsyncChannel, and the network is no longer considered "lingering".
115 public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
116 
117     public NetworkInfo networkInfo;
118     // This Network object should always be used if possible, so as to encourage reuse of the
119     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
120     // This Network object is always valid.
121     public final Network network;
122     public LinkProperties linkProperties;
123     // This should only be modified via ConnectivityService.updateCapabilities().
124     public NetworkCapabilities networkCapabilities;
125     public final NetworkMonitor networkMonitor;
126     public final NetworkMisc networkMisc;
127     // Indicates if netd has been told to create this Network. From this point on the appropriate
128     // routing rules are setup and routes are added so packets can begin flowing over the Network.
129     // This is a sticky bit; once set it is never cleared.
130     public boolean created;
131     // Set to true after the first time this network is marked as CONNECTED. Once set, the network
132     // shows up in API calls, is able to satisfy NetworkRequests and can become the default network.
133     // This is a sticky bit; once set it is never cleared.
134     public boolean everConnected;
135     // Set to true if this Network successfully passed validation or if it did not satisfy the
136     // default NetworkRequest in which case validation will not be attempted.
137     // This is a sticky bit; once set it is never cleared even if future validation attempts fail.
138     public boolean everValidated;
139 
140     // The result of the last validation attempt on this network (true if validated, false if not).
141     public boolean lastValidated;
142 
143     // If true, becoming unvalidated will lower the network's score. This is only meaningful if the
144     // system is configured not to do this for certain networks, e.g., if the
145     // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via
146     // Settings.Global.NETWORK_AVOID_BAD_WIFI.
147     public boolean avoidUnvalidated;
148 
149     // Whether a captive portal was ever detected on this network.
150     // This is a sticky bit; once set it is never cleared.
151     public boolean everCaptivePortalDetected;
152 
153     // Whether a captive portal was found during the last network validation attempt.
154     public boolean lastCaptivePortalDetected;
155 
156     // Networks are lingered when they become unneeded as a result of their NetworkRequests being
157     // satisfied by a higher-scoring network. so as to allow communication to wrap up before the
158     // network is taken down.  This usually only happens to the default network. Lingering ends with
159     // either the linger timeout expiring and the network being taken down, or the network
160     // satisfying a request again.
161     public static class LingerTimer implements Comparable<LingerTimer> {
162         public final NetworkRequest request;
163         public final long expiryMs;
164 
LingerTimer(NetworkRequest request, long expiryMs)165         public LingerTimer(NetworkRequest request, long expiryMs) {
166             this.request = request;
167             this.expiryMs = expiryMs;
168         }
equals(Object o)169         public boolean equals(Object o) {
170             if (!(o instanceof LingerTimer)) return false;
171             LingerTimer other = (LingerTimer) o;
172             return (request.requestId == other.request.requestId) && (expiryMs == other.expiryMs);
173         }
hashCode()174         public int hashCode() {
175             return Objects.hash(request.requestId, expiryMs);
176         }
compareTo(LingerTimer other)177         public int compareTo(LingerTimer other) {
178             return (expiryMs != other.expiryMs) ?
179                     Long.compare(expiryMs, other.expiryMs) :
180                     Integer.compare(request.requestId, other.request.requestId);
181         }
toString()182         public String toString() {
183             return String.format("%s, expires %dms", request.toString(),
184                     expiryMs - SystemClock.elapsedRealtime());
185         }
186     }
187 
188     /**
189      * Inform ConnectivityService that the network LINGER period has
190      * expired.
191      * obj = this NetworkAgentInfo
192      */
193     public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001;
194 
195     // All linger timers for this network, sorted by expiry time. A linger timer is added whenever
196     // a request is moved to a network with a better score, regardless of whether the network is or
197     // was lingering or not.
198     // TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g.,
199     // SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire.
200     private final SortedSet<LingerTimer> mLingerTimers = new TreeSet<>();
201 
202     // For fast lookups. Indexes into mLingerTimers by request ID.
203     private final SparseArray<LingerTimer> mLingerTimerForRequest = new SparseArray<>();
204 
205     // Linger expiry timer. Armed whenever mLingerTimers is non-empty, regardless of whether the
206     // network is lingering or not. Always set to the expiry of the LingerTimer that expires last.
207     // When the timer fires, all linger state is cleared, and if the network has no requests, it is
208     // torn down.
209     private WakeupMessage mLingerMessage;
210 
211     // Linger expiry. Holds the expiry time of the linger timer, or 0 if the timer is not armed.
212     private long mLingerExpiryMs;
213 
214     // Whether the network is lingering or not. Must be maintained separately from the above because
215     // it depends on the state of other networks and requests, which only ConnectivityService knows.
216     // (Example: we don't linger a network if it would become the best for a NetworkRequest if it
217     // validated).
218     private boolean mLingering;
219 
220     // This represents the last score received from the NetworkAgent.
221     private int currentScore;
222     // Penalty applied to scores of Networks that have not been validated.
223     private static final int UNVALIDATED_SCORE_PENALTY = 40;
224 
225     // Score for explicitly connected network.
226     //
227     // This ensures that a) the explicitly selected network is never trumped by anything else, and
228     // b) the explicitly selected network is never torn down.
229     private static final int MAXIMUM_NETWORK_SCORE = 100;
230 
231     // The list of NetworkRequests being satisfied by this Network.
232     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
233     // The list of NetworkRequests that this Network previously satisfied with the highest
234     // score.  A non-empty list indicates that if this Network was validated it is lingered.
235     // How many of the satisfied requests are actual requests and not listens.
236     private int mNumRequestNetworkRequests = 0;
237 
238     public final Messenger messenger;
239     public final AsyncChannel asyncChannel;
240 
241     // Used by ConnectivityService to keep track of 464xlat.
242     public Nat464Xlat clatd;
243 
244     private static final String TAG = ConnectivityService.class.getSimpleName();
245     private static final boolean VDBG = false;
246     private final ConnectivityService mConnService;
247     private final Context mContext;
248     private final Handler mHandler;
249 
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)250     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
251             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
252             NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
253         this.messenger = messenger;
254         asyncChannel = ac;
255         network = net;
256         networkInfo = info;
257         linkProperties = lp;
258         networkCapabilities = nc;
259         currentScore = score;
260         mConnService = connService;
261         mContext = context;
262         mHandler = handler;
263         networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
264         networkMisc = misc;
265     }
266 
267     // Functions for manipulating the requests satisfied by this network.
268     //
269     // These functions must only called on ConnectivityService's main thread.
270 
271     /**
272      * Add {@code networkRequest} to this network as it's satisfied by this network.
273      * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
274      *         already present.
275      */
addRequest(NetworkRequest networkRequest)276     public boolean addRequest(NetworkRequest networkRequest) {
277         NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
278         if (existing == networkRequest) return false;
279         if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--;
280         mNetworkRequests.put(networkRequest.requestId, networkRequest);
281         if (networkRequest.isRequest()) mNumRequestNetworkRequests++;
282         return true;
283     }
284 
285     /**
286      * Remove the specified request from this network.
287      */
removeRequest(int requestId)288     public void removeRequest(int requestId) {
289         NetworkRequest existing = mNetworkRequests.get(requestId);
290         if (existing == null) return;
291         mNetworkRequests.remove(requestId);
292         if (existing.isRequest()) {
293             mNumRequestNetworkRequests--;
294             unlingerRequest(existing);
295         }
296     }
297 
298     /**
299      * Returns whether this network is currently satisfying the request with the specified ID.
300      */
isSatisfyingRequest(int id)301     public boolean isSatisfyingRequest(int id) {
302         return mNetworkRequests.get(id) != null;
303     }
304 
305     /**
306      * Returns the request at the specified position in the list of requests satisfied by this
307      * network.
308      */
requestAt(int index)309     public NetworkRequest requestAt(int index) {
310         return mNetworkRequests.valueAt(index);
311     }
312 
313     /**
314      * Returns the number of requests currently satisfied by this network for which
315      * {@link android.net.NetworkRequest#isRequest} returns {@code true}.
316      */
numRequestNetworkRequests()317     public int numRequestNetworkRequests() {
318         return mNumRequestNetworkRequests;
319     }
320 
321     /**
322      * Returns the number of requests of any type currently satisfied by this network.
323      */
numNetworkRequests()324     public int numNetworkRequests() {
325         return mNetworkRequests.size();
326     }
327 
328     // Does this network satisfy request?
satisfies(NetworkRequest request)329     public boolean satisfies(NetworkRequest request) {
330         return created &&
331                 request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities);
332     }
333 
satisfiesImmutableCapabilitiesOf(NetworkRequest request)334     public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) {
335         return created &&
336                 request.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
337                         networkCapabilities);
338     }
339 
isVPN()340     public boolean isVPN() {
341         return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
342     }
343 
getCurrentScore(boolean pretendValidated)344     private int getCurrentScore(boolean pretendValidated) {
345         // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
346         // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
347         // score.  The NetworkScore class would provide a nice place to centralize score constants
348         // so they are not scattered about the transports.
349 
350         // If this network is explicitly selected and the user has decided to use it even if it's
351         // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
352         // selected and we're trying to see what its score could be. This ensures that we don't tear
353         // down an explicitly selected network before the user gets a chance to prefer it when
354         // a higher-scoring network (e.g., Ethernet) is available.
355         if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
356             return MAXIMUM_NETWORK_SCORE;
357         }
358 
359         int score = currentScore;
360         if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
361             score -= UNVALIDATED_SCORE_PENALTY;
362         }
363         if (score < 0) score = 0;
364         return score;
365     }
366 
367     // Return true on devices configured to ignore score penalty for wifi networks
368     // that become unvalidated (b/31075769).
ignoreWifiUnvalidationPenalty()369     private boolean ignoreWifiUnvalidationPenalty() {
370         boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
371                 networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
372         boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
373         return isWifi && !avoidBadWifi && everValidated;
374     }
375 
376     // Get the current score for this Network.  This may be modified from what the
377     // NetworkAgent sent, as it has modifiers applied to it.
getCurrentScore()378     public int getCurrentScore() {
379         return getCurrentScore(false);
380     }
381 
382     // Get the current score for this Network as if it was validated.  This may be modified from
383     // what the NetworkAgent sent, as it has modifiers applied to it.
getCurrentScoreAsValidated()384     public int getCurrentScoreAsValidated() {
385         return getCurrentScore(true);
386     }
387 
setCurrentScore(int newScore)388     public void setCurrentScore(int newScore) {
389         currentScore = newScore;
390     }
391 
getNetworkState()392     public NetworkState getNetworkState() {
393         synchronized (this) {
394             // Network objects are outwardly immutable so there is no point to duplicating.
395             // Duplicating also precludes sharing socket factories and connection pools.
396             final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null;
397             return new NetworkState(new NetworkInfo(networkInfo),
398                     new LinkProperties(linkProperties),
399                     new NetworkCapabilities(networkCapabilities), network, subscriberId, null);
400         }
401     }
402 
403     /**
404      * Sets the specified request to linger on this network for the specified time. Called by
405      * ConnectivityService when the request is moved to another network with a higher score.
406      */
lingerRequest(NetworkRequest request, long now, long duration)407     public void lingerRequest(NetworkRequest request, long now, long duration) {
408         if (mLingerTimerForRequest.get(request.requestId) != null) {
409             // Cannot happen. Once a request is lingering on a particular network, we cannot
410             // re-linger it unless that network becomes the best for that request again, in which
411             // case we should have unlingered it.
412             Log.wtf(TAG, this.name() + ": request " + request.requestId + " already lingered");
413         }
414         final long expiryMs = now + duration;
415         LingerTimer timer = new LingerTimer(request, expiryMs);
416         if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + this.name());
417         mLingerTimers.add(timer);
418         mLingerTimerForRequest.put(request.requestId, timer);
419     }
420 
421     /**
422      * Cancel lingering. Called by ConnectivityService when a request is added to this network.
423      * Returns true if the given request was lingering on this network, false otherwise.
424      */
unlingerRequest(NetworkRequest request)425     public boolean unlingerRequest(NetworkRequest request) {
426         LingerTimer timer = mLingerTimerForRequest.get(request.requestId);
427         if (timer != null) {
428             if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + this.name());
429             mLingerTimers.remove(timer);
430             mLingerTimerForRequest.remove(request.requestId);
431             return true;
432         }
433         return false;
434     }
435 
getLingerExpiry()436     public long getLingerExpiry() {
437         return mLingerExpiryMs;
438     }
439 
updateLingerTimer()440     public void updateLingerTimer() {
441         long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs;
442         if (newExpiry == mLingerExpiryMs) return;
443 
444         // Even if we're going to reschedule the timer, cancel it first. This is because the
445         // semantics of WakeupMessage guarantee that if cancel is called then the alarm will
446         // never call its callback (handleLingerComplete), even if it has already fired.
447         // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
448         // has already been dispatched, rescheduling to some time in the future it won't stop it
449         // from calling its callback immediately.
450         if (mLingerMessage != null) {
451             mLingerMessage.cancel();
452             mLingerMessage = null;
453         }
454 
455         if (newExpiry > 0) {
456             mLingerMessage = mConnService.makeWakeupMessage(
457                     mContext, mHandler,
458                     "NETWORK_LINGER_COMPLETE." + network.netId,
459                     EVENT_NETWORK_LINGER_COMPLETE, this);
460             mLingerMessage.schedule(newExpiry);
461         }
462 
463         mLingerExpiryMs = newExpiry;
464     }
465 
linger()466     public void linger() {
467         mLingering = true;
468     }
469 
unlinger()470     public void unlinger() {
471         mLingering = false;
472     }
473 
isLingering()474     public boolean isLingering() {
475         return mLingering;
476     }
477 
clearLingerState()478     public void clearLingerState() {
479         if (mLingerMessage != null) {
480             mLingerMessage.cancel();
481             mLingerMessage = null;
482         }
483         mLingerTimers.clear();
484         mLingerTimerForRequest.clear();
485         updateLingerTimer();  // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage.
486         mLingering = false;
487     }
488 
dumpLingerTimers(PrintWriter pw)489     public void dumpLingerTimers(PrintWriter pw) {
490         for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
491     }
492 
toString()493     public String toString() {
494         return "NetworkAgentInfo{ ni{" + networkInfo + "}  " +
495                 "network{" + network + "}  nethandle{" + network.getNetworkHandle() + "}  " +
496                 "lp{" + linkProperties + "}  " +
497                 "nc{" + networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
498                 "everValidated{" + everValidated + "}  lastValidated{" + lastValidated + "}  " +
499                 "created{" + created + "} lingering{" + isLingering() + "} " +
500                 "explicitlySelected{" + networkMisc.explicitlySelected + "} " +
501                 "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
502                 "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " +
503                 "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " +
504                 "}";
505     }
506 
name()507     public String name() {
508         return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" +
509                 networkInfo.getSubtypeName() + ") - " +
510                 (network == null ? "null" : network.toString()) + "]";
511     }
512 
513     // Enables sorting in descending order of score.
514     @Override
compareTo(NetworkAgentInfo other)515     public int compareTo(NetworkAgentInfo other) {
516         return other.getCurrentScore() - getCurrentScore();
517     }
518 }
519