blob: 3ac311b3e13a6c6024f035d0affd35e3db219d75 [file] [log] [blame]
Erik Kline9bba3402017-01-13 16:46:52 +09001/*
2 * Copyright (C) 2017 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
17package com.android.server.connectivity.tethering;
18
Erik Klinea1d368a2017-06-05 16:02:02 +090019import static android.net.ConnectivityManager.getNetworkTypeName;
20import static android.net.ConnectivityManager.TYPE_NONE;
Erik Klinedd8e8912017-01-18 16:08:06 +090021import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
22import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
Erik Kline72302902018-06-14 17:36:40 +090023import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
24import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
25import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
Erik Klinedd8e8912017-01-18 16:08:06 +090026
Erik Kline9bba3402017-01-13 16:46:52 +090027import android.content.Context;
Erik Klineb583b032017-02-22 12:58:24 +090028import android.os.Handler;
29import android.os.Looper;
Erik Kline89c63622018-01-26 19:23:14 +090030import android.os.Process;
Erik Kline9bba3402017-01-13 16:46:52 +090031import android.net.ConnectivityManager;
32import android.net.ConnectivityManager.NetworkCallback;
Erik Klinebe8ee082017-06-24 19:29:10 +090033import android.net.IpPrefix;
34import android.net.LinkAddress;
Erik Kline9bba3402017-01-13 16:46:52 +090035import android.net.LinkProperties;
36import android.net.Network;
37import android.net.NetworkCapabilities;
38import android.net.NetworkRequest;
39import android.net.NetworkState;
Erik Klinebe8ee082017-06-24 19:29:10 +090040import android.net.util.NetworkConstants;
Erik Kline5acb4e32017-07-04 18:28:11 +090041import android.net.util.PrefixUtils;
Erik Kline7747fd42017-05-12 16:52:48 +090042import android.net.util.SharedLog;
Erik Kline9bba3402017-01-13 16:46:52 +090043import android.util.Log;
44
Erik Kline885a9092017-01-16 16:27:22 +090045import com.android.internal.annotations.VisibleForTesting;
Erik Kline9bba3402017-01-13 16:46:52 +090046import com.android.internal.util.StateMachine;
47
Erik Klinebe8ee082017-06-24 19:29:10 +090048import java.util.Collections;
Erik Kline9bba3402017-01-13 16:46:52 +090049import java.util.HashMap;
Erik Klinebe8ee082017-06-24 19:29:10 +090050import java.util.HashSet;
51import java.util.Set;
Erik Kline9bba3402017-01-13 16:46:52 +090052
53
54/**
55 * A class to centralize all the network and link properties information
56 * pertaining to the current and any potential upstream network.
57 *
markchiena6c72872018-11-13 18:34:56 +090058 * The owner of UNM gets it to register network callbacks by calling the
59 * following methods :
60 * Calling #startTrackDefaultNetwork() to track the system default network.
61 * Calling #startObserveAllNetworks() to observe all networks. Listening all
62 * networks is necessary while the expression of preferred upstreams remains
63 * a list of legacy connectivity types. In future, this can be revisited.
64 * Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
Erik Kline9bba3402017-01-13 16:46:52 +090065 *
66 * The methods and data members of this class are only to be accessed and
67 * modified from the tethering master state machine thread. Any other
68 * access semantics would necessitate the addition of locking.
69 *
70 * TODO: Move upstream selection logic here.
71 *
Erik Klined2ec3912017-01-25 00:53:04 +090072 * All callback methods are run on the same thread as the specified target
73 * state machine. This class does not require locking when accessed from this
74 * thread. Access from other threads is not advised.
75 *
Erik Kline9bba3402017-01-13 16:46:52 +090076 * @hide
77 */
78public class UpstreamNetworkMonitor {
79 private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName();
80 private static final boolean DBG = false;
81 private static final boolean VDBG = false;
82
Erik Kline72302902018-06-14 17:36:40 +090083 public static final int EVENT_ON_CAPABILITIES = 1;
84 public static final int EVENT_ON_LINKPROPERTIES = 2;
85 public static final int EVENT_ON_LOST = 3;
Erik Kline5acb4e32017-07-04 18:28:11 +090086 public static final int NOTIFY_LOCAL_PREFIXES = 10;
Erik Kline9bba3402017-01-13 16:46:52 +090087
Erik Kline35bf06c2017-01-26 18:08:28 +090088 private static final int CALLBACK_LISTEN_ALL = 1;
Erik Kline72302902018-06-14 17:36:40 +090089 private static final int CALLBACK_DEFAULT_INTERNET = 2;
Erik Kline35bf06c2017-01-26 18:08:28 +090090 private static final int CALLBACK_MOBILE_REQUEST = 3;
Erik Klined2ec3912017-01-25 00:53:04 +090091
Erik Kline9bba3402017-01-13 16:46:52 +090092 private final Context mContext;
Erik Kline7747fd42017-05-12 16:52:48 +090093 private final SharedLog mLog;
Erik Kline9bba3402017-01-13 16:46:52 +090094 private final StateMachine mTarget;
Erik Klineb583b032017-02-22 12:58:24 +090095 private final Handler mHandler;
Erik Kline9bba3402017-01-13 16:46:52 +090096 private final int mWhat;
97 private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
Erik Kline5acb4e32017-07-04 18:28:11 +090098 private HashSet<IpPrefix> mLocalPrefixes;
Erik Kline9bba3402017-01-13 16:46:52 +090099 private ConnectivityManager mCM;
Erik Klined2ec3912017-01-25 00:53:04 +0900100 private NetworkCallback mListenAllCallback;
Erik Kline9bba3402017-01-13 16:46:52 +0900101 private NetworkCallback mDefaultNetworkCallback;
Erik Kline9bba3402017-01-13 16:46:52 +0900102 private NetworkCallback mMobileNetworkCallback;
103 private boolean mDunRequired;
Erik Kline126171b2017-10-10 11:54:08 +0900104 // The current system default network (not really used yet).
105 private Network mDefaultInternetNetwork;
106 // The current upstream network used for tethering.
107 private Network mTetheringUpstreamNetwork;
Erik Kline9bba3402017-01-13 16:46:52 +0900108
Erik Klinebe8ee082017-06-24 19:29:10 +0900109 public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
Erik Kline9bba3402017-01-13 16:46:52 +0900110 mContext = ctx;
111 mTarget = tgt;
Erik Klineb583b032017-02-22 12:58:24 +0900112 mHandler = mTarget.getHandler();
Erik Kline7747fd42017-05-12 16:52:48 +0900113 mLog = log.forSubComponent(TAG);
Erik Klinebe8ee082017-06-24 19:29:10 +0900114 mWhat = what;
Erik Kline5acb4e32017-07-04 18:28:11 +0900115 mLocalPrefixes = new HashSet<>();
Erik Kline9bba3402017-01-13 16:46:52 +0900116 }
117
Erik Kline885a9092017-01-16 16:27:22 +0900118 @VisibleForTesting
Erik Kline7747fd42017-05-12 16:52:48 +0900119 public UpstreamNetworkMonitor(
Erik Klinebe8ee082017-06-24 19:29:10 +0900120 ConnectivityManager cm, StateMachine tgt, SharedLog log, int what) {
121 this((Context) null, tgt, log, what);
Erik Kline885a9092017-01-16 16:27:22 +0900122 mCM = cm;
123 }
124
markchiena6c72872018-11-13 18:34:56 +0900125 public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest) {
126 // This is not really a "request", just a way of tracking the system default network.
127 // It's guaranteed not to actually bring up any networks because it's the same request
128 // as the ConnectivityService default request, and thus shares fate with it. We can't
129 // use registerDefaultNetworkCallback because it will not track the system default
130 // network if there is a VPN that applies to our UID.
131 if (mDefaultNetworkCallback == null) {
Erik Kline72302902018-06-14 17:36:40 +0900132 final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest);
133 mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
134 cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
135 }
Erik Kline9bba3402017-01-13 16:46:52 +0900136 }
137
markchiena6c72872018-11-13 18:34:56 +0900138 public void startObserveAllNetworks() {
139 stop();
140
141 final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
142 .clearCapabilities().build();
143 mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
144 cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
145 }
146
Erik Kline9bba3402017-01-13 16:46:52 +0900147 public void stop() {
148 releaseMobileNetworkRequest();
149
Erik Klined2ec3912017-01-25 00:53:04 +0900150 releaseCallback(mListenAllCallback);
151 mListenAllCallback = null;
Erik Kline9bba3402017-01-13 16:46:52 +0900152
Erik Kline126171b2017-10-10 11:54:08 +0900153 mTetheringUpstreamNetwork = null;
Erik Kline9bba3402017-01-13 16:46:52 +0900154 mNetworkMap.clear();
155 }
156
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900157 public void updateMobileRequiresDun(boolean dunRequired) {
Erik Kline9bba3402017-01-13 16:46:52 +0900158 final boolean valueChanged = (mDunRequired != dunRequired);
159 mDunRequired = dunRequired;
160 if (valueChanged && mobileNetworkRequested()) {
161 releaseMobileNetworkRequest();
162 registerMobileNetworkRequest();
163 }
164 }
165
166 public boolean mobileNetworkRequested() {
167 return (mMobileNetworkCallback != null);
168 }
169
170 public void registerMobileNetworkRequest() {
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900171 if (mMobileNetworkCallback != null) {
Erik Kline7747fd42017-05-12 16:52:48 +0900172 mLog.e("registerMobileNetworkRequest() already registered");
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900173 return;
174 }
Erik Kline9bba3402017-01-13 16:46:52 +0900175
Erik Kline35bf06c2017-01-26 18:08:28 +0900176 // The following use of the legacy type system cannot be removed until
177 // after upstream selection no longer finds networks by legacy type.
178 // See also http://b/34364553 .
179 final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
180
181 final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
182 .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
183 .build();
Erik Kline9bba3402017-01-13 16:46:52 +0900184
185 // The existing default network and DUN callbacks will be notified.
186 // Therefore, to avoid duplicate notifications, we only register a no-op.
Erik Kline35bf06c2017-01-26 18:08:28 +0900187 mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
Erik Kline9bba3402017-01-13 16:46:52 +0900188
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900189 // TODO: Change the timeout from 0 (no onUnavailable callback) to some
190 // moderate callback timeout. This might be useful for updating some UI.
191 // Additionally, we log a message to aid in any subsequent debugging.
Erik Kline7747fd42017-05-12 16:52:48 +0900192 mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
Erik Kline9bba3402017-01-13 16:46:52 +0900193
Erik Klineb583b032017-02-22 12:58:24 +0900194 cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
Erik Kline9bba3402017-01-13 16:46:52 +0900195 }
196
197 public void releaseMobileNetworkRequest() {
198 if (mMobileNetworkCallback == null) return;
199
200 cm().unregisterNetworkCallback(mMobileNetworkCallback);
201 mMobileNetworkCallback = null;
202 }
203
Erik Klinea1d368a2017-06-05 16:02:02 +0900204 // So many TODOs here, but chief among them is: make this functionality an
205 // integral part of this class such that whenever a higher priority network
206 // becomes available and useful we (a) file a request to keep it up as
207 // necessary and (b) change all upstream tracking state accordingly (by
208 // passing LinkProperties up to Tethering).
209 //
210 // Next TODO: return NetworkState instead of just the type.
Erik Kline5bbece72017-06-09 17:08:52 +0900211 public NetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
Erik Klinea1d368a2017-06-05 16:02:02 +0900212 final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
213 mNetworkMap.values(), preferredTypes);
214
215 mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
216
217 switch (typeStatePair.type) {
218 case TYPE_MOBILE_DUN:
219 case TYPE_MOBILE_HIPRI:
220 // If we're on DUN, put our own grab on it.
221 registerMobileNetworkRequest();
222 break;
223 case TYPE_NONE:
224 break;
225 default:
226 /* If we've found an active upstream connection that's not DUN/HIPRI
Erik Kline126171b2017-10-10 11:54:08 +0900227 * we should stop any outstanding DUN/HIPRI requests.
Erik Klinea1d368a2017-06-05 16:02:02 +0900228 *
229 * If we found NONE we don't want to do this as we want any previous
230 * requests to keep trying to bring up something we can use.
231 */
232 releaseMobileNetworkRequest();
233 break;
234 }
235
Erik Kline5bbece72017-06-09 17:08:52 +0900236 return typeStatePair.ns;
Erik Klinea1d368a2017-06-05 16:02:02 +0900237 }
238
Erik Kline72302902018-06-14 17:36:40 +0900239 // Returns null if no current upstream available.
240 public NetworkState getCurrentPreferredUpstream() {
241 final NetworkState dfltState = (mDefaultInternetNetwork != null)
242 ? mNetworkMap.get(mDefaultInternetNetwork)
243 : null;
244 if (!mDunRequired) return dfltState;
245
246 if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
247
248 // Find a DUN network. Note that code in Tethering causes a DUN request
249 // to be filed, but this might be moved into this class in future.
250 return findFirstDunNetwork(mNetworkMap.values());
251 }
252
Erik Kline126171b2017-10-10 11:54:08 +0900253 public void setCurrentUpstream(Network upstream) {
254 mTetheringUpstreamNetwork = upstream;
255 }
256
Erik Kline5acb4e32017-07-04 18:28:11 +0900257 public Set<IpPrefix> getLocalPrefixes() {
258 return (Set<IpPrefix>) mLocalPrefixes.clone();
Erik Klinebe8ee082017-06-24 19:29:10 +0900259 }
260
Erik Kline72302902018-06-14 17:36:40 +0900261 private void handleAvailable(Network network) {
262 if (mNetworkMap.containsKey(network)) return;
Erik Klined2ec3912017-01-25 00:53:04 +0900263
Erik Kline72302902018-06-14 17:36:40 +0900264 if (VDBG) Log.d(TAG, "onAvailable for " + network);
265 mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null));
Erik Kline9bba3402017-01-13 16:46:52 +0900266 }
267
markchiena6c72872018-11-13 18:34:56 +0900268 private void handleNetCap(Network network, NetworkCapabilities newNc) {
Erik Klined2ec3912017-01-25 00:53:04 +0900269 final NetworkState prev = mNetworkMap.get(network);
270 if (prev == null || newNc.equals(prev.networkCapabilities)) {
271 // Ignore notifications about networks for which we have not yet
272 // received onAvailable() (should never happen) and any duplicate
273 // notifications (e.g. matching more than one of our callbacks).
Erik Kline9bba3402017-01-13 16:46:52 +0900274 return;
275 }
Erik Klined2ec3912017-01-25 00:53:04 +0900276
Erik Kline9bba3402017-01-13 16:46:52 +0900277 if (VDBG) {
278 Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
279 network, newNc));
280 }
281
Erik Kline126171b2017-10-10 11:54:08 +0900282 // Log changes in upstream network signal strength, if available.
283 if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) {
284 final int newSignal = newNc.getSignalStrength();
285 final String prevSignal = getSignalStrength(prev.networkCapabilities);
286 mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal);
287 }
288
Erik Klined2ec3912017-01-25 00:53:04 +0900289 mNetworkMap.put(network, new NetworkState(
290 null, prev.linkProperties, newNc, network, null, null));
291 // TODO: If sufficient information is available to select a more
292 // preferable upstream, do so now and notify the target.
Erik Kline9bba3402017-01-13 16:46:52 +0900293 notifyTarget(EVENT_ON_CAPABILITIES, network);
294 }
295
296 private void handleLinkProp(Network network, LinkProperties newLp) {
Erik Klined2ec3912017-01-25 00:53:04 +0900297 final NetworkState prev = mNetworkMap.get(network);
298 if (prev == null || newLp.equals(prev.linkProperties)) {
299 // Ignore notifications about networks for which we have not yet
300 // received onAvailable() (should never happen) and any duplicate
301 // notifications (e.g. matching more than one of our callbacks).
Erik Kline9bba3402017-01-13 16:46:52 +0900302 return;
303 }
Erik Klined2ec3912017-01-25 00:53:04 +0900304
Erik Kline9bba3402017-01-13 16:46:52 +0900305 if (VDBG) {
306 Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
307 network, newLp));
308 }
309
Erik Klined2ec3912017-01-25 00:53:04 +0900310 mNetworkMap.put(network, new NetworkState(
311 null, newLp, prev.networkCapabilities, network, null, null));
312 // TODO: If sufficient information is available to select a more
313 // preferable upstream, do so now and notify the target.
Erik Kline9bba3402017-01-13 16:46:52 +0900314 notifyTarget(EVENT_ON_LINKPROPERTIES, network);
315 }
316
markchiena6c72872018-11-13 18:34:56 +0900317 private void handleSuspended(Network network) {
Erik Kline126171b2017-10-10 11:54:08 +0900318 if (!network.equals(mTetheringUpstreamNetwork)) return;
319 mLog.log("SUSPENDED current upstream: " + network);
320 }
321
markchiena6c72872018-11-13 18:34:56 +0900322 private void handleResumed(Network network) {
Erik Kline126171b2017-10-10 11:54:08 +0900323 if (!network.equals(mTetheringUpstreamNetwork)) return;
324 mLog.log("RESUMED current upstream: " + network);
325 }
326
markchiena6c72872018-11-13 18:34:56 +0900327 private void handleLost(Network network) {
328 // There are few TODOs within ConnectivityService's rematching code
329 // pertaining to spurious onLost() notifications.
330 //
331 // TODO: simplify this, probably if favor of code that:
332 // - selects a new upstream if mTetheringUpstreamNetwork has
333 // been lost (by any callback)
334 // - deletes the entry from the map only when the LISTEN_ALL
335 // callback gets notified.
Erik Klined2ec3912017-01-25 00:53:04 +0900336
337 if (!mNetworkMap.containsKey(network)) {
338 // Ignore loss of networks about which we had not previously
339 // learned any information or for which we have already processed
340 // an onLost() notification.
341 return;
Erik Kline9bba3402017-01-13 16:46:52 +0900342 }
Erik Klined2ec3912017-01-25 00:53:04 +0900343
344 if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
345
346 // TODO: If sufficient information is available to select a more
347 // preferable upstream, do so now and notify the target. Likewise,
348 // if the current upstream network is gone, notify the target of the
349 // fact that we now have no upstream at all.
Erik Kline9bba3402017-01-13 16:46:52 +0900350 notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
351 }
352
Erik Kline5acb4e32017-07-04 18:28:11 +0900353 private void recomputeLocalPrefixes() {
354 final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
355 if (!mLocalPrefixes.equals(localPrefixes)) {
356 mLocalPrefixes = localPrefixes;
357 notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
Erik Klinebe8ee082017-06-24 19:29:10 +0900358 }
359 }
360
Erik Kline9bba3402017-01-13 16:46:52 +0900361 // Fetch (and cache) a ConnectivityManager only if and when we need one.
362 private ConnectivityManager cm() {
363 if (mCM == null) {
Erik Klineea9cc482017-03-10 19:35:34 +0900364 // MUST call the String variant to be able to write unittests.
365 mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Erik Kline9bba3402017-01-13 16:46:52 +0900366 }
367 return mCM;
368 }
369
370 /**
Erik Klineb583b032017-02-22 12:58:24 +0900371 * A NetworkCallback class that handles information of interest directly
372 * in the thread on which it is invoked. To avoid locking, this MUST be
373 * run on the same thread as the target state machine's handler.
Erik Kline9bba3402017-01-13 16:46:52 +0900374 */
375 private class UpstreamNetworkCallback extends NetworkCallback {
Erik Klined2ec3912017-01-25 00:53:04 +0900376 private final int mCallbackType;
377
378 UpstreamNetworkCallback(int callbackType) {
379 mCallbackType = callbackType;
380 }
381
Erik Kline9bba3402017-01-13 16:46:52 +0900382 @Override
383 public void onAvailable(Network network) {
Erik Kline72302902018-06-14 17:36:40 +0900384 handleAvailable(network);
Erik Kline9bba3402017-01-13 16:46:52 +0900385 }
386
387 @Override
388 public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
markchiena6c72872018-11-13 18:34:56 +0900389 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
390 mDefaultInternetNetwork = network;
391 return;
392 }
393 handleNetCap(network, newNc);
Erik Kline9bba3402017-01-13 16:46:52 +0900394 }
395
396 @Override
397 public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
markchiena6c72872018-11-13 18:34:56 +0900398 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) return;
399
Erik Klineb583b032017-02-22 12:58:24 +0900400 handleLinkProp(network, newLp);
markchien69955492018-10-01 21:18:15 +0800401 // Any non-LISTEN_ALL callback will necessarily concern a network that will
402 // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
403 // So it's not useful to do this work for non-LISTEN_ALL callbacks.
404 if (mCallbackType == CALLBACK_LISTEN_ALL) {
405 recomputeLocalPrefixes();
406 }
Erik Kline9bba3402017-01-13 16:46:52 +0900407 }
408
Erik Kline126171b2017-10-10 11:54:08 +0900409 @Override
410 public void onNetworkSuspended(Network network) {
markchiena6c72872018-11-13 18:34:56 +0900411 if (mCallbackType == CALLBACK_LISTEN_ALL) {
412 handleSuspended(network);
413 }
Erik Kline126171b2017-10-10 11:54:08 +0900414 }
415
416 @Override
417 public void onNetworkResumed(Network network) {
markchiena6c72872018-11-13 18:34:56 +0900418 if (mCallbackType == CALLBACK_LISTEN_ALL) {
419 handleResumed(network);
420 }
Erik Kline126171b2017-10-10 11:54:08 +0900421 }
Erik Klineb583b032017-02-22 12:58:24 +0900422
Erik Kline9bba3402017-01-13 16:46:52 +0900423 @Override
424 public void onLost(Network network) {
markchiena6c72872018-11-13 18:34:56 +0900425 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
426 mDefaultInternetNetwork = null;
427 return;
428 }
429 handleLost(network);
markchien69955492018-10-01 21:18:15 +0800430 // Any non-LISTEN_ALL callback will necessarily concern a network that will
431 // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
432 // So it's not useful to do this work for non-LISTEN_ALL callbacks.
433 if (mCallbackType == CALLBACK_LISTEN_ALL) {
434 recomputeLocalPrefixes();
435 }
Erik Klineb583b032017-02-22 12:58:24 +0900436 }
Erik Kline9bba3402017-01-13 16:46:52 +0900437 }
438
439 private void releaseCallback(NetworkCallback cb) {
440 if (cb != null) cm().unregisterNetworkCallback(cb);
441 }
442
443 private void notifyTarget(int which, Network network) {
444 notifyTarget(which, mNetworkMap.get(network));
445 }
446
Erik Klinebe8ee082017-06-24 19:29:10 +0900447 private void notifyTarget(int which, Object obj) {
448 mTarget.sendMessage(mWhat, which, 0, obj);
Erik Kline9bba3402017-01-13 16:46:52 +0900449 }
Erik Klinea1d368a2017-06-05 16:02:02 +0900450
Erik Klinebe8ee082017-06-24 19:29:10 +0900451 private static class TypeStatePair {
Erik Klinea1d368a2017-06-05 16:02:02 +0900452 public int type = TYPE_NONE;
453 public NetworkState ns = null;
454 }
455
Erik Klinebe8ee082017-06-24 19:29:10 +0900456 private static TypeStatePair findFirstAvailableUpstreamByType(
Erik Klinea1d368a2017-06-05 16:02:02 +0900457 Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
458 final TypeStatePair result = new TypeStatePair();
459
460 for (int type : preferredTypes) {
461 NetworkCapabilities nc;
462 try {
463 nc = ConnectivityManager.networkCapabilitiesForType(type);
464 } catch (IllegalArgumentException iae) {
465 Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
466 ConnectivityManager.getNetworkTypeName(type));
467 continue;
468 }
Erik Kline89c63622018-01-26 19:23:14 +0900469 nc.setSingleUid(Process.myUid());
Erik Klinea1d368a2017-06-05 16:02:02 +0900470
471 for (NetworkState value : netStates) {
472 if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
473 continue;
474 }
475
476 result.type = type;
477 result.ns = value;
478 return result;
479 }
480 }
481
482 return result;
483 }
Erik Klinebe8ee082017-06-24 19:29:10 +0900484
Erik Kline5acb4e32017-07-04 18:28:11 +0900485 private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
Erik Klinebe8ee082017-06-24 19:29:10 +0900486 final HashSet<IpPrefix> prefixSet = new HashSet<>();
487
Erik Klinebe8ee082017-06-24 19:29:10 +0900488 for (NetworkState ns : netStates) {
Erik Kline5acb4e32017-07-04 18:28:11 +0900489 final LinkProperties lp = ns.linkProperties;
490 if (lp == null) continue;
491 prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
Erik Klinebe8ee082017-06-24 19:29:10 +0900492 }
493
494 return prefixSet;
495 }
Erik Kline126171b2017-10-10 11:54:08 +0900496
497 private static String getSignalStrength(NetworkCapabilities nc) {
498 if (nc == null || !nc.hasSignalStrength()) return "unknown";
499 return Integer.toString(nc.getSignalStrength());
500 }
Erik Kline72302902018-06-14 17:36:40 +0900501
502 private static boolean isCellular(NetworkState ns) {
503 return (ns != null) && isCellular(ns.networkCapabilities);
504 }
505
506 private static boolean isCellular(NetworkCapabilities nc) {
507 return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) &&
508 nc.hasCapability(NET_CAPABILITY_NOT_VPN);
509 }
510
511 private static boolean hasCapability(NetworkState ns, int netCap) {
512 return (ns != null) && (ns.networkCapabilities != null) &&
513 ns.networkCapabilities.hasCapability(netCap);
514 }
515
516 private static boolean isNetworkUsableAndNotCellular(NetworkState ns) {
517 return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) &&
518 !isCellular(ns.networkCapabilities);
519 }
520
521 private static NetworkState findFirstDunNetwork(Iterable<NetworkState> netStates) {
522 for (NetworkState ns : netStates) {
523 if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns;
524 }
525
526 return null;
527 }
Erik Kline9bba3402017-01-13 16:46:52 +0900528}