blob: 34132910ca862bb0d763a67730b94cf9b3b7c050 [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;
23
Erik Kline9bba3402017-01-13 16:46:52 +090024import android.content.Context;
Erik Klineb583b032017-02-22 12:58:24 +090025import android.os.Handler;
26import android.os.Looper;
Erik Kline89c63622018-01-26 19:23:14 +090027import android.os.Process;
Erik Kline9bba3402017-01-13 16:46:52 +090028import android.net.ConnectivityManager;
29import android.net.ConnectivityManager.NetworkCallback;
Erik Klinebe8ee082017-06-24 19:29:10 +090030import android.net.IpPrefix;
31import android.net.LinkAddress;
Erik Kline9bba3402017-01-13 16:46:52 +090032import android.net.LinkProperties;
33import android.net.Network;
34import android.net.NetworkCapabilities;
35import android.net.NetworkRequest;
36import android.net.NetworkState;
Erik Klinebe8ee082017-06-24 19:29:10 +090037import android.net.util.NetworkConstants;
Erik Kline5acb4e32017-07-04 18:28:11 +090038import android.net.util.PrefixUtils;
Erik Kline7747fd42017-05-12 16:52:48 +090039import android.net.util.SharedLog;
Erik Kline9bba3402017-01-13 16:46:52 +090040import android.util.Log;
41
Erik Kline885a9092017-01-16 16:27:22 +090042import com.android.internal.annotations.VisibleForTesting;
Erik Kline9bba3402017-01-13 16:46:52 +090043import com.android.internal.util.StateMachine;
44
Erik Klinebe8ee082017-06-24 19:29:10 +090045import java.util.Collections;
Erik Kline9bba3402017-01-13 16:46:52 +090046import java.util.HashMap;
Erik Klinebe8ee082017-06-24 19:29:10 +090047import java.util.HashSet;
48import java.util.Set;
Erik Kline9bba3402017-01-13 16:46:52 +090049
50
51/**
52 * A class to centralize all the network and link properties information
53 * pertaining to the current and any potential upstream network.
54 *
55 * Calling #start() registers two callbacks: one to track the system default
Erik Klined2ec3912017-01-25 00:53:04 +090056 * network and a second to observe all networks. The latter is necessary
57 * while the expression of preferred upstreams remains a list of legacy
58 * connectivity types. In future, this can be revisited.
Erik Kline9bba3402017-01-13 16:46:52 +090059 *
60 * The methods and data members of this class are only to be accessed and
61 * modified from the tethering master state machine thread. Any other
62 * access semantics would necessitate the addition of locking.
63 *
64 * TODO: Move upstream selection logic here.
65 *
Erik Klined2ec3912017-01-25 00:53:04 +090066 * All callback methods are run on the same thread as the specified target
67 * state machine. This class does not require locking when accessed from this
68 * thread. Access from other threads is not advised.
69 *
Erik Kline9bba3402017-01-13 16:46:52 +090070 * @hide
71 */
72public class UpstreamNetworkMonitor {
73 private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName();
74 private static final boolean DBG = false;
75 private static final boolean VDBG = false;
76
77 public static final int EVENT_ON_AVAILABLE = 1;
78 public static final int EVENT_ON_CAPABILITIES = 2;
79 public static final int EVENT_ON_LINKPROPERTIES = 3;
80 public static final int EVENT_ON_LOST = 4;
Erik Kline5acb4e32017-07-04 18:28:11 +090081 public static final int NOTIFY_LOCAL_PREFIXES = 10;
Erik Kline9bba3402017-01-13 16:46:52 +090082
Erik Kline35bf06c2017-01-26 18:08:28 +090083 private static final int CALLBACK_LISTEN_ALL = 1;
84 private static final int CALLBACK_TRACK_DEFAULT = 2;
85 private static final int CALLBACK_MOBILE_REQUEST = 3;
Erik Klined2ec3912017-01-25 00:53:04 +090086
Erik Kline9bba3402017-01-13 16:46:52 +090087 private final Context mContext;
Erik Kline7747fd42017-05-12 16:52:48 +090088 private final SharedLog mLog;
Erik Kline9bba3402017-01-13 16:46:52 +090089 private final StateMachine mTarget;
Erik Klineb583b032017-02-22 12:58:24 +090090 private final Handler mHandler;
Erik Kline9bba3402017-01-13 16:46:52 +090091 private final int mWhat;
92 private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
Erik Kline5acb4e32017-07-04 18:28:11 +090093 private HashSet<IpPrefix> mLocalPrefixes;
Erik Kline9bba3402017-01-13 16:46:52 +090094 private ConnectivityManager mCM;
Erik Klined2ec3912017-01-25 00:53:04 +090095 private NetworkCallback mListenAllCallback;
Erik Kline9bba3402017-01-13 16:46:52 +090096 private NetworkCallback mDefaultNetworkCallback;
Erik Kline9bba3402017-01-13 16:46:52 +090097 private NetworkCallback mMobileNetworkCallback;
98 private boolean mDunRequired;
Erik Kline126171b2017-10-10 11:54:08 +090099 // The current system default network (not really used yet).
100 private Network mDefaultInternetNetwork;
101 // The current upstream network used for tethering.
102 private Network mTetheringUpstreamNetwork;
Erik Kline9bba3402017-01-13 16:46:52 +0900103
Erik Klinebe8ee082017-06-24 19:29:10 +0900104 public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
Erik Kline9bba3402017-01-13 16:46:52 +0900105 mContext = ctx;
106 mTarget = tgt;
Erik Klineb583b032017-02-22 12:58:24 +0900107 mHandler = mTarget.getHandler();
Erik Kline7747fd42017-05-12 16:52:48 +0900108 mLog = log.forSubComponent(TAG);
Erik Klinebe8ee082017-06-24 19:29:10 +0900109 mWhat = what;
Erik Kline5acb4e32017-07-04 18:28:11 +0900110 mLocalPrefixes = new HashSet<>();
Erik Kline9bba3402017-01-13 16:46:52 +0900111 }
112
Erik Kline885a9092017-01-16 16:27:22 +0900113 @VisibleForTesting
Erik Kline7747fd42017-05-12 16:52:48 +0900114 public UpstreamNetworkMonitor(
Erik Klinebe8ee082017-06-24 19:29:10 +0900115 ConnectivityManager cm, StateMachine tgt, SharedLog log, int what) {
116 this((Context) null, tgt, log, what);
Erik Kline885a9092017-01-16 16:27:22 +0900117 mCM = cm;
118 }
119
Erik Kline9bba3402017-01-13 16:46:52 +0900120 public void start() {
121 stop();
122
Erik Klined2ec3912017-01-25 00:53:04 +0900123 final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
124 .clearCapabilities().build();
Erik Kline35bf06c2017-01-26 18:08:28 +0900125 mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
Erik Klineb583b032017-02-22 12:58:24 +0900126 cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
Erik Kline9bba3402017-01-13 16:46:52 +0900127
Erik Kline35bf06c2017-01-26 18:08:28 +0900128 mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
Erik Klineb583b032017-02-22 12:58:24 +0900129 cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
Erik Kline9bba3402017-01-13 16:46:52 +0900130 }
131
132 public void stop() {
133 releaseMobileNetworkRequest();
134
135 releaseCallback(mDefaultNetworkCallback);
136 mDefaultNetworkCallback = null;
Erik Kline126171b2017-10-10 11:54:08 +0900137 mDefaultInternetNetwork = null;
Erik Kline9bba3402017-01-13 16:46:52 +0900138
Erik Klined2ec3912017-01-25 00:53:04 +0900139 releaseCallback(mListenAllCallback);
140 mListenAllCallback = null;
Erik Kline9bba3402017-01-13 16:46:52 +0900141
Erik Kline126171b2017-10-10 11:54:08 +0900142 mTetheringUpstreamNetwork = null;
Erik Kline9bba3402017-01-13 16:46:52 +0900143 mNetworkMap.clear();
144 }
145
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900146 public void updateMobileRequiresDun(boolean dunRequired) {
Erik Kline9bba3402017-01-13 16:46:52 +0900147 final boolean valueChanged = (mDunRequired != dunRequired);
148 mDunRequired = dunRequired;
149 if (valueChanged && mobileNetworkRequested()) {
150 releaseMobileNetworkRequest();
151 registerMobileNetworkRequest();
152 }
153 }
154
155 public boolean mobileNetworkRequested() {
156 return (mMobileNetworkCallback != null);
157 }
158
159 public void registerMobileNetworkRequest() {
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900160 if (mMobileNetworkCallback != null) {
Erik Kline7747fd42017-05-12 16:52:48 +0900161 mLog.e("registerMobileNetworkRequest() already registered");
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900162 return;
163 }
Erik Kline9bba3402017-01-13 16:46:52 +0900164
Erik Kline35bf06c2017-01-26 18:08:28 +0900165 // The following use of the legacy type system cannot be removed until
166 // after upstream selection no longer finds networks by legacy type.
167 // See also http://b/34364553 .
168 final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
169
170 final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
171 .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
172 .build();
Erik Kline9bba3402017-01-13 16:46:52 +0900173
174 // The existing default network and DUN callbacks will be notified.
175 // Therefore, to avoid duplicate notifications, we only register a no-op.
Erik Kline35bf06c2017-01-26 18:08:28 +0900176 mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
Erik Kline9bba3402017-01-13 16:46:52 +0900177
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900178 // TODO: Change the timeout from 0 (no onUnavailable callback) to some
179 // moderate callback timeout. This might be useful for updating some UI.
180 // Additionally, we log a message to aid in any subsequent debugging.
Erik Kline7747fd42017-05-12 16:52:48 +0900181 mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
Erik Kline9bba3402017-01-13 16:46:52 +0900182
Erik Klineb583b032017-02-22 12:58:24 +0900183 cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
Erik Kline9bba3402017-01-13 16:46:52 +0900184 }
185
186 public void releaseMobileNetworkRequest() {
187 if (mMobileNetworkCallback == null) return;
188
189 cm().unregisterNetworkCallback(mMobileNetworkCallback);
190 mMobileNetworkCallback = null;
191 }
192
Erik Klinea1d368a2017-06-05 16:02:02 +0900193 // So many TODOs here, but chief among them is: make this functionality an
194 // integral part of this class such that whenever a higher priority network
195 // becomes available and useful we (a) file a request to keep it up as
196 // necessary and (b) change all upstream tracking state accordingly (by
197 // passing LinkProperties up to Tethering).
198 //
199 // Next TODO: return NetworkState instead of just the type.
Erik Kline5bbece72017-06-09 17:08:52 +0900200 public NetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
Erik Klinea1d368a2017-06-05 16:02:02 +0900201 final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
202 mNetworkMap.values(), preferredTypes);
203
204 mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
205
206 switch (typeStatePair.type) {
207 case TYPE_MOBILE_DUN:
208 case TYPE_MOBILE_HIPRI:
209 // If we're on DUN, put our own grab on it.
210 registerMobileNetworkRequest();
211 break;
212 case TYPE_NONE:
213 break;
214 default:
215 /* If we've found an active upstream connection that's not DUN/HIPRI
Erik Kline126171b2017-10-10 11:54:08 +0900216 * we should stop any outstanding DUN/HIPRI requests.
Erik Klinea1d368a2017-06-05 16:02:02 +0900217 *
218 * If we found NONE we don't want to do this as we want any previous
219 * requests to keep trying to bring up something we can use.
220 */
221 releaseMobileNetworkRequest();
222 break;
223 }
224
Erik Kline5bbece72017-06-09 17:08:52 +0900225 return typeStatePair.ns;
Erik Klinea1d368a2017-06-05 16:02:02 +0900226 }
227
Erik Kline126171b2017-10-10 11:54:08 +0900228 public void setCurrentUpstream(Network upstream) {
229 mTetheringUpstreamNetwork = upstream;
230 }
231
Erik Kline5acb4e32017-07-04 18:28:11 +0900232 public Set<IpPrefix> getLocalPrefixes() {
233 return (Set<IpPrefix>) mLocalPrefixes.clone();
Erik Klinebe8ee082017-06-24 19:29:10 +0900234 }
235
Erik Klined2ec3912017-01-25 00:53:04 +0900236 private void handleAvailable(int callbackType, Network network) {
237 if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
238
Erik Kline9bba3402017-01-13 16:46:52 +0900239 if (!mNetworkMap.containsKey(network)) {
240 mNetworkMap.put(network,
241 new NetworkState(null, null, null, network, null, null));
242 }
243
Erik Klined2ec3912017-01-25 00:53:04 +0900244 // Always request whatever extra information we can, in case this
245 // was already up when start() was called, in which case we would
246 // not have been notified of any information that had not changed.
Erik Kline35bf06c2017-01-26 18:08:28 +0900247 switch (callbackType) {
248 case CALLBACK_LISTEN_ALL:
249 break;
Erik Kline465c46d2017-03-07 15:25:32 +0900250
Erik Kline35bf06c2017-01-26 18:08:28 +0900251 case CALLBACK_TRACK_DEFAULT:
Erik Kline32858e12017-02-21 16:21:46 +0900252 if (mDefaultNetworkCallback == null) {
253 // The callback was unregistered in the interval between
Erik Klineb583b032017-02-22 12:58:24 +0900254 // ConnectivityService enqueueing onAvailable() and our
255 // handling of it here on the mHandler thread.
256 //
Erik Kline32858e12017-02-21 16:21:46 +0900257 // Clean-up of this network entry is deferred to the
258 // handling of onLost() by other callbacks.
Erik Klineb583b032017-02-22 12:58:24 +0900259 //
260 // These request*() calls can be deleted post oag/339444.
Erik Kline32858e12017-02-21 16:21:46 +0900261 return;
262 }
Erik Kline126171b2017-10-10 11:54:08 +0900263 mDefaultInternetNetwork = network;
Erik Kline35bf06c2017-01-26 18:08:28 +0900264 break;
Erik Kline465c46d2017-03-07 15:25:32 +0900265
Erik Kline35bf06c2017-01-26 18:08:28 +0900266 case CALLBACK_MOBILE_REQUEST:
Erik Kline32858e12017-02-21 16:21:46 +0900267 if (mMobileNetworkCallback == null) {
268 // The callback was unregistered in the interval between
Erik Klineb583b032017-02-22 12:58:24 +0900269 // ConnectivityService enqueueing onAvailable() and our
270 // handling of it here on the mHandler thread.
271 //
Erik Kline32858e12017-02-21 16:21:46 +0900272 // Clean-up of this network entry is deferred to the
273 // handling of onLost() by other callbacks.
Erik Kline32858e12017-02-21 16:21:46 +0900274 return;
275 }
Erik Kline35bf06c2017-01-26 18:08:28 +0900276 break;
Erik Klined2ec3912017-01-25 00:53:04 +0900277 }
Erik Kline9bba3402017-01-13 16:46:52 +0900278
Erik Klined2ec3912017-01-25 00:53:04 +0900279 // Requesting updates for mListenAllCallback is not currently possible
280 // because it's a "listen". Two possible solutions to getting updates
281 // about networks without waiting for a change (which might never come)
282 // are:
283 //
284 // [1] extend request{NetworkCapabilities,LinkProperties}() to
285 // take a Network argument and have ConnectivityService do
286 // what's required (if the network satisfies the request)
287 //
288 // [2] explicitly file a NetworkRequest for each connectivity type
289 // listed as a preferred upstream and wait for these callbacks
290 // to be notified (requires tracking many more callbacks).
291 //
292 // Until this is addressed, networks that exist prior to the "listen"
293 // registration and which do not subsequently change will not cause
294 // us to learn their NetworkCapabilities nor their LinkProperties.
295
296 // TODO: If sufficient information is available to select a more
297 // preferable upstream, do so now and notify the target.
Erik Kline9bba3402017-01-13 16:46:52 +0900298 notifyTarget(EVENT_ON_AVAILABLE, network);
299 }
300
301 private void handleNetCap(Network network, NetworkCapabilities newNc) {
Erik Klined2ec3912017-01-25 00:53:04 +0900302 final NetworkState prev = mNetworkMap.get(network);
303 if (prev == null || newNc.equals(prev.networkCapabilities)) {
304 // Ignore notifications about networks for which we have not yet
305 // received onAvailable() (should never happen) and any duplicate
306 // notifications (e.g. matching more than one of our callbacks).
Erik Kline9bba3402017-01-13 16:46:52 +0900307 return;
308 }
Erik Klined2ec3912017-01-25 00:53:04 +0900309
Erik Kline9bba3402017-01-13 16:46:52 +0900310 if (VDBG) {
311 Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
312 network, newNc));
313 }
314
Erik Kline126171b2017-10-10 11:54:08 +0900315 // Log changes in upstream network signal strength, if available.
316 if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) {
317 final int newSignal = newNc.getSignalStrength();
318 final String prevSignal = getSignalStrength(prev.networkCapabilities);
319 mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal);
320 }
321
Erik Klined2ec3912017-01-25 00:53:04 +0900322 mNetworkMap.put(network, new NetworkState(
323 null, prev.linkProperties, newNc, network, null, null));
324 // TODO: If sufficient information is available to select a more
325 // preferable upstream, do so now and notify the target.
Erik Kline9bba3402017-01-13 16:46:52 +0900326 notifyTarget(EVENT_ON_CAPABILITIES, network);
327 }
328
329 private void handleLinkProp(Network network, LinkProperties newLp) {
Erik Klined2ec3912017-01-25 00:53:04 +0900330 final NetworkState prev = mNetworkMap.get(network);
331 if (prev == null || newLp.equals(prev.linkProperties)) {
332 // Ignore notifications about networks for which we have not yet
333 // received onAvailable() (should never happen) and any duplicate
334 // notifications (e.g. matching more than one of our callbacks).
Erik Kline9bba3402017-01-13 16:46:52 +0900335 return;
336 }
Erik Klined2ec3912017-01-25 00:53:04 +0900337
Erik Kline9bba3402017-01-13 16:46:52 +0900338 if (VDBG) {
339 Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
340 network, newLp));
341 }
342
Erik Klined2ec3912017-01-25 00:53:04 +0900343 mNetworkMap.put(network, new NetworkState(
344 null, newLp, prev.networkCapabilities, network, null, null));
345 // TODO: If sufficient information is available to select a more
346 // preferable upstream, do so now and notify the target.
Erik Kline9bba3402017-01-13 16:46:52 +0900347 notifyTarget(EVENT_ON_LINKPROPERTIES, network);
348 }
349
Erik Kline126171b2017-10-10 11:54:08 +0900350 private void handleSuspended(int callbackType, Network network) {
351 if (callbackType != CALLBACK_LISTEN_ALL) return;
352 if (!network.equals(mTetheringUpstreamNetwork)) return;
353 mLog.log("SUSPENDED current upstream: " + network);
354 }
355
356 private void handleResumed(int callbackType, Network network) {
357 if (callbackType != CALLBACK_LISTEN_ALL) return;
358 if (!network.equals(mTetheringUpstreamNetwork)) return;
359 mLog.log("RESUMED current upstream: " + network);
360 }
361
Erik Klined2ec3912017-01-25 00:53:04 +0900362 private void handleLost(int callbackType, Network network) {
Erik Kline35bf06c2017-01-26 18:08:28 +0900363 if (callbackType == CALLBACK_TRACK_DEFAULT) {
Erik Kline126171b2017-10-10 11:54:08 +0900364 mDefaultInternetNetwork = null;
Erik Klined2ec3912017-01-25 00:53:04 +0900365 // Receiving onLost() for a default network does not necessarily
366 // mean the network is gone. We wait for a separate notification
367 // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
368 // clearing all state.
Erik Kline9bba3402017-01-13 16:46:52 +0900369 return;
370 }
Erik Klined2ec3912017-01-25 00:53:04 +0900371
372 if (!mNetworkMap.containsKey(network)) {
373 // Ignore loss of networks about which we had not previously
374 // learned any information or for which we have already processed
375 // an onLost() notification.
376 return;
Erik Kline9bba3402017-01-13 16:46:52 +0900377 }
Erik Klined2ec3912017-01-25 00:53:04 +0900378
379 if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
380
381 // TODO: If sufficient information is available to select a more
382 // preferable upstream, do so now and notify the target. Likewise,
383 // if the current upstream network is gone, notify the target of the
384 // fact that we now have no upstream at all.
Erik Kline9bba3402017-01-13 16:46:52 +0900385 notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
386 }
387
Erik Kline5acb4e32017-07-04 18:28:11 +0900388 private void recomputeLocalPrefixes() {
389 final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
390 if (!mLocalPrefixes.equals(localPrefixes)) {
391 mLocalPrefixes = localPrefixes;
392 notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
Erik Klinebe8ee082017-06-24 19:29:10 +0900393 }
394 }
395
Erik Kline9bba3402017-01-13 16:46:52 +0900396 // Fetch (and cache) a ConnectivityManager only if and when we need one.
397 private ConnectivityManager cm() {
398 if (mCM == null) {
Erik Klineea9cc482017-03-10 19:35:34 +0900399 // MUST call the String variant to be able to write unittests.
400 mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Erik Kline9bba3402017-01-13 16:46:52 +0900401 }
402 return mCM;
403 }
404
405 /**
Erik Klineb583b032017-02-22 12:58:24 +0900406 * A NetworkCallback class that handles information of interest directly
407 * in the thread on which it is invoked. To avoid locking, this MUST be
408 * run on the same thread as the target state machine's handler.
Erik Kline9bba3402017-01-13 16:46:52 +0900409 */
410 private class UpstreamNetworkCallback extends NetworkCallback {
Erik Klined2ec3912017-01-25 00:53:04 +0900411 private final int mCallbackType;
412
413 UpstreamNetworkCallback(int callbackType) {
414 mCallbackType = callbackType;
415 }
416
Erik Kline9bba3402017-01-13 16:46:52 +0900417 @Override
418 public void onAvailable(Network network) {
Erik Klineb583b032017-02-22 12:58:24 +0900419 handleAvailable(mCallbackType, network);
Erik Kline9bba3402017-01-13 16:46:52 +0900420 }
421
422 @Override
423 public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
Erik Klineb583b032017-02-22 12:58:24 +0900424 handleNetCap(network, newNc);
Erik Kline9bba3402017-01-13 16:46:52 +0900425 }
426
427 @Override
428 public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
Erik Klineb583b032017-02-22 12:58:24 +0900429 handleLinkProp(network, newLp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900430 recomputeLocalPrefixes();
Erik Kline9bba3402017-01-13 16:46:52 +0900431 }
432
Erik Kline126171b2017-10-10 11:54:08 +0900433 @Override
434 public void onNetworkSuspended(Network network) {
435 handleSuspended(mCallbackType, network);
436 }
437
438 @Override
439 public void onNetworkResumed(Network network) {
440 handleResumed(mCallbackType, network);
441 }
Erik Klineb583b032017-02-22 12:58:24 +0900442
Erik Kline9bba3402017-01-13 16:46:52 +0900443 @Override
444 public void onLost(Network network) {
Erik Klineb583b032017-02-22 12:58:24 +0900445 handleLost(mCallbackType, network);
Erik Kline5acb4e32017-07-04 18:28:11 +0900446 recomputeLocalPrefixes();
Erik Klineb583b032017-02-22 12:58:24 +0900447 }
Erik Kline9bba3402017-01-13 16:46:52 +0900448 }
449
450 private void releaseCallback(NetworkCallback cb) {
451 if (cb != null) cm().unregisterNetworkCallback(cb);
452 }
453
454 private void notifyTarget(int which, Network network) {
455 notifyTarget(which, mNetworkMap.get(network));
456 }
457
Erik Klinebe8ee082017-06-24 19:29:10 +0900458 private void notifyTarget(int which, Object obj) {
459 mTarget.sendMessage(mWhat, which, 0, obj);
Erik Kline9bba3402017-01-13 16:46:52 +0900460 }
Erik Klinea1d368a2017-06-05 16:02:02 +0900461
Erik Klinebe8ee082017-06-24 19:29:10 +0900462 private static class TypeStatePair {
Erik Klinea1d368a2017-06-05 16:02:02 +0900463 public int type = TYPE_NONE;
464 public NetworkState ns = null;
465 }
466
Erik Klinebe8ee082017-06-24 19:29:10 +0900467 private static TypeStatePair findFirstAvailableUpstreamByType(
Erik Klinea1d368a2017-06-05 16:02:02 +0900468 Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
469 final TypeStatePair result = new TypeStatePair();
470
471 for (int type : preferredTypes) {
472 NetworkCapabilities nc;
473 try {
474 nc = ConnectivityManager.networkCapabilitiesForType(type);
475 } catch (IllegalArgumentException iae) {
476 Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
477 ConnectivityManager.getNetworkTypeName(type));
478 continue;
479 }
Erik Kline89c63622018-01-26 19:23:14 +0900480 nc.setSingleUid(Process.myUid());
Erik Klinea1d368a2017-06-05 16:02:02 +0900481
482 for (NetworkState value : netStates) {
483 if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
484 continue;
485 }
486
487 result.type = type;
488 result.ns = value;
489 return result;
490 }
491 }
492
493 return result;
494 }
Erik Klinebe8ee082017-06-24 19:29:10 +0900495
Erik Kline5acb4e32017-07-04 18:28:11 +0900496 private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
Erik Klinebe8ee082017-06-24 19:29:10 +0900497 final HashSet<IpPrefix> prefixSet = new HashSet<>();
498
Erik Klinebe8ee082017-06-24 19:29:10 +0900499 for (NetworkState ns : netStates) {
Erik Kline5acb4e32017-07-04 18:28:11 +0900500 final LinkProperties lp = ns.linkProperties;
501 if (lp == null) continue;
502 prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
Erik Klinebe8ee082017-06-24 19:29:10 +0900503 }
504
505 return prefixSet;
506 }
Erik Kline126171b2017-10-10 11:54:08 +0900507
508 private static String getSignalStrength(NetworkCapabilities nc) {
509 if (nc == null || !nc.hasSignalStrength()) return "unknown";
510 return Integer.toString(nc.getSignalStrength());
511 }
Erik Kline9bba3402017-01-13 16:46:52 +0900512}