1 /* 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 17 package com.android.networkstack.tethering; 18 19 import static android.net.ConnectivityManager.TYPE_BLUETOOTH; 20 import static android.net.ConnectivityManager.TYPE_ETHERNET; 21 import static android.net.ConnectivityManager.TYPE_MOBILE; 22 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; 23 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; 24 import static android.net.ConnectivityManager.TYPE_WIFI; 25 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; 26 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 27 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 28 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 29 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 30 31 import android.content.Context; 32 import android.net.ConnectivityManager; 33 import android.net.ConnectivityManager.NetworkCallback; 34 import android.net.IpPrefix; 35 import android.net.LinkProperties; 36 import android.net.Network; 37 import android.net.NetworkCapabilities; 38 import android.net.NetworkRequest; 39 import android.net.util.SharedLog; 40 import android.os.Handler; 41 import android.util.Log; 42 import android.util.SparseIntArray; 43 44 import androidx.annotation.NonNull; 45 import androidx.annotation.Nullable; 46 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.StateMachine; 49 import com.android.networkstack.apishim.ConnectivityManagerShimImpl; 50 import com.android.networkstack.apishim.common.ConnectivityManagerShim; 51 import com.android.networkstack.tethering.util.PrefixUtils; 52 53 import java.util.HashMap; 54 import java.util.HashSet; 55 import java.util.Objects; 56 import java.util.Set; 57 58 59 /** 60 * A class to centralize all the network and link properties information 61 * pertaining to the current and any potential upstream network. 62 * 63 * The owner of UNM gets it to register network callbacks by calling the 64 * following methods : 65 * Calling #startTrackDefaultNetwork() to track the system default network. 66 * Calling #startObserveAllNetworks() to observe all networks. Listening all 67 * networks is necessary while the expression of preferred upstreams remains 68 * a list of legacy connectivity types. In future, this can be revisited. 69 * Calling #setTryCell() to request bringing up mobile DUN or HIPRI. 70 * 71 * The methods and data members of this class are only to be accessed and 72 * modified from the tethering main state machine thread. Any other 73 * access semantics would necessitate the addition of locking. 74 * 75 * TODO: Move upstream selection logic here. 76 * 77 * All callback methods are run on the same thread as the specified target 78 * state machine. This class does not require locking when accessed from this 79 * thread. Access from other threads is not advised. 80 * 81 * @hide 82 */ 83 public class UpstreamNetworkMonitor { 84 private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName(); 85 private static final boolean DBG = false; 86 private static final boolean VDBG = false; 87 88 public static final int EVENT_ON_CAPABILITIES = 1; 89 public static final int EVENT_ON_LINKPROPERTIES = 2; 90 public static final int EVENT_ON_LOST = 3; 91 public static final int EVENT_DEFAULT_SWITCHED = 4; 92 public static final int NOTIFY_LOCAL_PREFIXES = 10; 93 // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default 94 // disabled. 95 @VisibleForTesting 96 public static final int TYPE_NONE = -1; 97 98 private static final int CALLBACK_LISTEN_ALL = 1; 99 private static final int CALLBACK_DEFAULT_INTERNET = 2; 100 private static final int CALLBACK_MOBILE_REQUEST = 3; 101 102 private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); 103 static { sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR)104 sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR)105 sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR)106 sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI)107 sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH)108 sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET)109 sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); 110 } 111 112 private final Context mContext; 113 private final SharedLog mLog; 114 private final StateMachine mTarget; 115 private final Handler mHandler; 116 private final int mWhat; 117 private final HashMap<Network, UpstreamNetworkState> mNetworkMap = new HashMap<>(); 118 private HashSet<IpPrefix> mLocalPrefixes; 119 private ConnectivityManager mCM; 120 private EntitlementManager mEntitlementMgr; 121 private NetworkCallback mListenAllCallback; 122 private NetworkCallback mDefaultNetworkCallback; 123 private NetworkCallback mMobileNetworkCallback; 124 125 /** Whether Tethering has requested a cellular upstream. */ 126 private boolean mTryCell; 127 /** Whether the carrier requires DUN. */ 128 private boolean mDunRequired; 129 /** Whether automatic upstream selection is enabled. */ 130 private boolean mAutoUpstream; 131 132 // Whether the current default upstream is mobile or not. 133 private boolean mIsDefaultCellularUpstream; 134 // The current system default network (not really used yet). 135 private Network mDefaultInternetNetwork; 136 // The current upstream network used for tethering. 137 private Network mTetheringUpstreamNetwork; 138 private boolean mPreferTestNetworks; 139 UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what)140 public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) { 141 mContext = ctx; 142 mTarget = tgt; 143 mHandler = mTarget.getHandler(); 144 mLog = log.forSubComponent(TAG); 145 mWhat = what; 146 mLocalPrefixes = new HashSet<>(); 147 mIsDefaultCellularUpstream = false; 148 mCM = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); 149 } 150 151 /** 152 * Tracking the system default network. This method should be only called once when system is 153 * ready, and the callback is never unregistered. 154 * 155 * @param entitle a EntitlementManager object to communicate between EntitlementManager and 156 * UpstreamNetworkMonitor 157 */ startTrackDefaultNetwork(EntitlementManager entitle)158 public void startTrackDefaultNetwork(EntitlementManager entitle) { 159 if (mDefaultNetworkCallback != null) { 160 Log.wtf(TAG, "default network callback is already registered"); 161 return; 162 } 163 ConnectivityManagerShim mCmShim = ConnectivityManagerShimImpl.newInstance(mContext); 164 mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); 165 mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler); 166 if (mEntitlementMgr == null) { 167 mEntitlementMgr = entitle; 168 } 169 } 170 171 /** Listen all networks. */ startObserveAllNetworks()172 public void startObserveAllNetworks() { 173 stop(); 174 175 final NetworkRequest listenAllRequest = new NetworkRequest.Builder() 176 .clearCapabilities().build(); 177 mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); 178 cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler); 179 } 180 181 /** 182 * Stop tracking candidate tethering upstreams and release mobile network request. 183 * Note: this function is used when tethering is stopped because tethering do not need to 184 * choose upstream anymore. But it would not stop default network tracking because 185 * EntitlementManager may need to know default network to decide whether to request entitlement 186 * check even tethering is not active yet. 187 */ stop()188 public void stop() { 189 setTryCell(false); 190 191 releaseCallback(mListenAllCallback); 192 mListenAllCallback = null; 193 194 mTetheringUpstreamNetwork = null; 195 mNetworkMap.clear(); 196 } 197 reevaluateUpstreamRequirements(boolean tryCell, boolean autoUpstream, boolean dunRequired)198 private void reevaluateUpstreamRequirements(boolean tryCell, boolean autoUpstream, 199 boolean dunRequired) { 200 final boolean mobileRequestRequired = tryCell && (dunRequired || !autoUpstream); 201 final boolean dunRequiredChanged = (mDunRequired != dunRequired); 202 203 mTryCell = tryCell; 204 mDunRequired = dunRequired; 205 mAutoUpstream = autoUpstream; 206 207 if (mobileRequestRequired && !mobileNetworkRequested()) { 208 registerMobileNetworkRequest(); 209 } else if (mobileNetworkRequested() && !mobileRequestRequired) { 210 releaseMobileNetworkRequest(); 211 } else if (mobileNetworkRequested() && dunRequiredChanged) { 212 releaseMobileNetworkRequest(); 213 if (mobileRequestRequired) { 214 registerMobileNetworkRequest(); 215 } 216 } 217 } 218 219 /** 220 * Informs UpstreamNetworkMonitor that a cellular upstream is desired. 221 * 222 * This may result in filing a NetworkRequest for DUN if it is required, or for MOBILE_HIPRI if 223 * automatic upstream selection is disabled and MOBILE_HIPRI is the preferred upstream. 224 */ setTryCell(boolean tryCell)225 public void setTryCell(boolean tryCell) { 226 reevaluateUpstreamRequirements(tryCell, mAutoUpstream, mDunRequired); 227 } 228 229 /** Informs UpstreamNetworkMonitor of upstream configuration parameters. */ setUpstreamConfig(boolean autoUpstream, boolean dunRequired)230 public void setUpstreamConfig(boolean autoUpstream, boolean dunRequired) { 231 reevaluateUpstreamRequirements(mTryCell, autoUpstream, dunRequired); 232 } 233 234 /** Whether mobile network is requested. */ mobileNetworkRequested()235 public boolean mobileNetworkRequested() { 236 return (mMobileNetworkCallback != null); 237 } 238 239 /** Request mobile network if mobile upstream is permitted. */ registerMobileNetworkRequest()240 private void registerMobileNetworkRequest() { 241 if (!isCellularUpstreamPermitted()) { 242 mLog.i("registerMobileNetworkRequest() is not permitted"); 243 releaseMobileNetworkRequest(); 244 return; 245 } 246 if (mMobileNetworkCallback != null) { 247 mLog.e("registerMobileNetworkRequest() already registered"); 248 return; 249 } 250 251 final NetworkRequest mobileUpstreamRequest; 252 if (mDunRequired) { 253 mobileUpstreamRequest = new NetworkRequest.Builder() 254 .addCapability(NET_CAPABILITY_DUN) 255 .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) 256 .addTransportType(TRANSPORT_CELLULAR).build(); 257 } else { 258 mobileUpstreamRequest = new NetworkRequest.Builder() 259 .addCapability(NET_CAPABILITY_INTERNET) 260 .addTransportType(TRANSPORT_CELLULAR).build(); 261 } 262 263 // The existing default network and DUN callbacks will be notified. 264 // Therefore, to avoid duplicate notifications, we only register a no-op. 265 mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST); 266 267 // The following use of the legacy type system cannot be removed until 268 // upstream selection no longer finds networks by legacy type. 269 // See also http://b/34364553 . 270 final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; 271 272 // TODO: Change the timeout from 0 (no onUnavailable callback) to some 273 // moderate callback timeout. This might be useful for updating some UI. 274 // Additionally, we log a message to aid in any subsequent debugging. 275 mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest 276 + " mTryCell=" + mTryCell + " mAutoUpstream=" + mAutoUpstream 277 + " mDunRequired=" + mDunRequired); 278 279 cm().requestNetwork(mobileUpstreamRequest, 0, legacyType, mHandler, 280 mMobileNetworkCallback); 281 } 282 283 /** Release mobile network request. */ releaseMobileNetworkRequest()284 private void releaseMobileNetworkRequest() { 285 if (mMobileNetworkCallback == null) return; 286 287 cm().unregisterNetworkCallback(mMobileNetworkCallback); 288 mMobileNetworkCallback = null; 289 } 290 291 // So many TODOs here, but chief among them is: make this functionality an 292 // integral part of this class such that whenever a higher priority network 293 // becomes available and useful we (a) file a request to keep it up as 294 // necessary and (b) change all upstream tracking state accordingly (by 295 // passing LinkProperties up to Tethering). 296 /** 297 * Select the first available network from |perferredTypes|. 298 */ selectPreferredUpstreamType(Iterable<Integer> preferredTypes)299 public UpstreamNetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) { 300 final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType( 301 mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted()); 302 303 mLog.log("preferred upstream type: " + typeStatePair.type); 304 305 switch (typeStatePair.type) { 306 case TYPE_MOBILE_DUN: 307 case TYPE_MOBILE_HIPRI: 308 // Tethering just selected mobile upstream in spite of the default network being 309 // not mobile. This can happen because of the priority list. 310 // Notify EntitlementManager to check permission for using mobile upstream. 311 if (!mIsDefaultCellularUpstream) { 312 mEntitlementMgr.maybeRunProvisioning(); 313 } 314 break; 315 } 316 317 return typeStatePair.ns; 318 } 319 320 /** 321 * Get current preferred upstream network. If default network is cellular and DUN is required, 322 * preferred upstream would be DUN otherwise preferred upstream is the same as default network. 323 * Returns null if no current upstream is available. 324 */ getCurrentPreferredUpstream()325 public UpstreamNetworkState getCurrentPreferredUpstream() { 326 final UpstreamNetworkState dfltState = (mDefaultInternetNetwork != null) 327 ? mNetworkMap.get(mDefaultInternetNetwork) 328 : null; 329 if (mPreferTestNetworks) { 330 final UpstreamNetworkState testState = findFirstTestNetwork(mNetworkMap.values()); 331 if (testState != null) return testState; 332 } 333 334 if (isNetworkUsableAndNotCellular(dfltState)) return dfltState; 335 336 if (!isCellularUpstreamPermitted()) return null; 337 338 if (!mDunRequired) return dfltState; 339 340 // Find a DUN network. Note that code in Tethering causes a DUN request 341 // to be filed, but this might be moved into this class in future. 342 return findFirstDunNetwork(mNetworkMap.values()); 343 } 344 345 /** Tell UpstreamNetworkMonitor which network is the current upstream of tethering. */ setCurrentUpstream(Network upstream)346 public void setCurrentUpstream(Network upstream) { 347 mTetheringUpstreamNetwork = upstream; 348 } 349 350 /** Return local prefixes. */ getLocalPrefixes()351 public Set<IpPrefix> getLocalPrefixes() { 352 return (Set<IpPrefix>) mLocalPrefixes.clone(); 353 } 354 isCellularUpstreamPermitted()355 private boolean isCellularUpstreamPermitted() { 356 if (mEntitlementMgr != null) { 357 return mEntitlementMgr.isCellularUpstreamPermitted(); 358 } else { 359 // This flow should only happens in testing. 360 return true; 361 } 362 } 363 handleAvailable(Network network)364 private void handleAvailable(Network network) { 365 if (mNetworkMap.containsKey(network)) return; 366 367 if (VDBG) Log.d(TAG, "onAvailable for " + network); 368 mNetworkMap.put(network, new UpstreamNetworkState(null, null, network)); 369 } 370 handleNetCap(Network network, NetworkCapabilities newNc)371 private void handleNetCap(Network network, NetworkCapabilities newNc) { 372 final UpstreamNetworkState prev = mNetworkMap.get(network); 373 if (prev == null || newNc.equals(prev.networkCapabilities)) { 374 // Ignore notifications about networks for which we have not yet 375 // received onAvailable() (should never happen) and any duplicate 376 // notifications (e.g. matching more than one of our callbacks). 377 return; 378 } 379 380 if (VDBG) { 381 Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s", 382 network, newNc)); 383 } 384 385 mNetworkMap.put(network, new UpstreamNetworkState( 386 prev.linkProperties, newNc, network)); 387 // TODO: If sufficient information is available to select a more 388 // preferable upstream, do so now and notify the target. 389 notifyTarget(EVENT_ON_CAPABILITIES, network); 390 } 391 updateLinkProperties(@onNull Network network, LinkProperties newLp)392 private @Nullable UpstreamNetworkState updateLinkProperties(@NonNull Network network, 393 LinkProperties newLp) { 394 final UpstreamNetworkState prev = mNetworkMap.get(network); 395 if (prev == null || newLp.equals(prev.linkProperties)) { 396 // Ignore notifications about networks for which we have not yet 397 // received onAvailable() (should never happen) and any duplicate 398 // notifications (e.g. matching more than one of our callbacks). 399 // 400 // Also, it can happen that onLinkPropertiesChanged is called after 401 // onLost removed the state from mNetworkMap. This is due to a bug 402 // in disconnectAndDestroyNetwork, which calls nai.clatd.update() 403 // after the onLost callbacks. This was fixed in S. 404 // TODO: make this method void when R is no longer supported. 405 return null; 406 } 407 408 if (VDBG) { 409 Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s", 410 network, newLp)); 411 } 412 413 final UpstreamNetworkState ns = new UpstreamNetworkState(newLp, prev.networkCapabilities, 414 network); 415 mNetworkMap.put(network, ns); 416 return ns; 417 } 418 handleLinkProp(Network network, LinkProperties newLp)419 private void handleLinkProp(Network network, LinkProperties newLp) { 420 final UpstreamNetworkState ns = updateLinkProperties(network, newLp); 421 if (ns != null) { 422 notifyTarget(EVENT_ON_LINKPROPERTIES, ns); 423 } 424 } 425 handleLost(Network network)426 private void handleLost(Network network) { 427 // There are few TODOs within ConnectivityService's rematching code 428 // pertaining to spurious onLost() notifications. 429 // 430 // TODO: simplify this, probably if favor of code that: 431 // - selects a new upstream if mTetheringUpstreamNetwork has 432 // been lost (by any callback) 433 // - deletes the entry from the map only when the LISTEN_ALL 434 // callback gets notified. 435 436 if (!mNetworkMap.containsKey(network)) { 437 // Ignore loss of networks about which we had not previously 438 // learned any information or for which we have already processed 439 // an onLost() notification. 440 return; 441 } 442 443 if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network); 444 445 // TODO: If sufficient information is available to select a more 446 // preferable upstream, do so now and notify the target. Likewise, 447 // if the current upstream network is gone, notify the target of the 448 // fact that we now have no upstream at all. 449 notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network)); 450 } 451 maybeHandleNetworkSwitch(@onNull Network network)452 private void maybeHandleNetworkSwitch(@NonNull Network network) { 453 if (Objects.equals(mDefaultInternetNetwork, network)) return; 454 455 final UpstreamNetworkState ns = mNetworkMap.get(network); 456 if (ns == null) { 457 // Can never happen unless there is a bug in ConnectivityService. Entries are only 458 // removed from mNetworkMap when receiving onLost, and onLost for a given network can 459 // never be followed by any other callback on that network. 460 Log.wtf(TAG, "maybeHandleNetworkSwitch: no UpstreamNetworkState for " + network); 461 return; 462 } 463 464 // Default network changed. Update local data and notify tethering. 465 Log.d(TAG, "New default Internet network: " + network); 466 mDefaultInternetNetwork = network; 467 notifyTarget(EVENT_DEFAULT_SWITCHED, ns); 468 } 469 recomputeLocalPrefixes()470 private void recomputeLocalPrefixes() { 471 final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values()); 472 if (!mLocalPrefixes.equals(localPrefixes)) { 473 mLocalPrefixes = localPrefixes; 474 notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone()); 475 } 476 } 477 478 // Fetch (and cache) a ConnectivityManager only if and when we need one. cm()479 private ConnectivityManager cm() { 480 if (mCM == null) { 481 // MUST call the String variant to be able to write unittests. 482 mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 483 } 484 return mCM; 485 } 486 487 /** 488 * A NetworkCallback class that handles information of interest directly 489 * in the thread on which it is invoked. To avoid locking, this MUST be 490 * run on the same thread as the target state machine's handler. 491 */ 492 private class UpstreamNetworkCallback extends NetworkCallback { 493 private final int mCallbackType; 494 UpstreamNetworkCallback(int callbackType)495 UpstreamNetworkCallback(int callbackType) { 496 mCallbackType = callbackType; 497 } 498 499 @Override onAvailable(Network network)500 public void onAvailable(Network network) { 501 handleAvailable(network); 502 } 503 504 @Override onCapabilitiesChanged(Network network, NetworkCapabilities newNc)505 public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { 506 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { 507 // mDefaultInternetNetwork is not updated here because upstream selection must only 508 // run when the LinkProperties have been updated as well as the capabilities. If 509 // this callback is due to a default network switch, then the system will invoke 510 // onLinkPropertiesChanged right after this method and mDefaultInternetNetwork will 511 // be updated then. 512 // 513 // Technically, not updating here isn't necessary, because the notifications to 514 // Tethering sent by notifyTarget are messages sent to a state machine running on 515 // the same thread as this method, and so cannot arrive until after this method has 516 // returned. However, it is not a good idea to rely on that because fact that 517 // Tethering uses multiple state machines running on the same thread is a major 518 // source of race conditions and something that should be fixed. 519 // 520 // TODO: is it correct that this code always updates EntitlementManager? 521 // This code runs when the default network connects or changes capabilities, but the 522 // default network might not be the tethering upstream. 523 final boolean newIsCellular = isCellular(newNc); 524 if (mIsDefaultCellularUpstream != newIsCellular) { 525 mIsDefaultCellularUpstream = newIsCellular; 526 mEntitlementMgr.notifyUpstream(newIsCellular); 527 } 528 return; 529 } 530 531 handleNetCap(network, newNc); 532 } 533 534 @Override onLinkPropertiesChanged(Network network, LinkProperties newLp)535 public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { 536 handleLinkProp(network, newLp); 537 538 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { 539 // When the default network callback calls onLinkPropertiesChanged, it means that 540 // all the network information for the default network is known (because 541 // onLinkPropertiesChanged is called after onAvailable and onCapabilitiesChanged). 542 // Inform tethering that the default network might have changed. 543 maybeHandleNetworkSwitch(network); 544 return; 545 } 546 547 // Any non-LISTEN_ALL callback will necessarily concern a network that will 548 // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. 549 // So it's not useful to do this work for non-LISTEN_ALL callbacks. 550 if (mCallbackType == CALLBACK_LISTEN_ALL) { 551 recomputeLocalPrefixes(); 552 } 553 } 554 555 @Override onLost(Network network)556 public void onLost(Network network) { 557 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { 558 mDefaultInternetNetwork = null; 559 mIsDefaultCellularUpstream = false; 560 mEntitlementMgr.notifyUpstream(false); 561 Log.d(TAG, "Lost default Internet network: " + network); 562 notifyTarget(EVENT_DEFAULT_SWITCHED, null); 563 return; 564 } 565 566 handleLost(network); 567 // Any non-LISTEN_ALL callback will necessarily concern a network that will 568 // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. 569 // So it's not useful to do this work for non-LISTEN_ALL callbacks. 570 if (mCallbackType == CALLBACK_LISTEN_ALL) { 571 recomputeLocalPrefixes(); 572 } 573 } 574 } 575 releaseCallback(NetworkCallback cb)576 private void releaseCallback(NetworkCallback cb) { 577 if (cb != null) cm().unregisterNetworkCallback(cb); 578 } 579 notifyTarget(int which, Network network)580 private void notifyTarget(int which, Network network) { 581 notifyTarget(which, mNetworkMap.get(network)); 582 } 583 notifyTarget(int which, Object obj)584 private void notifyTarget(int which, Object obj) { 585 mTarget.sendMessage(mWhat, which, 0, obj); 586 } 587 588 private static class TypeStatePair { 589 public int type = TYPE_NONE; 590 public UpstreamNetworkState ns = null; 591 } 592 findFirstAvailableUpstreamByType( Iterable<UpstreamNetworkState> netStates, Iterable<Integer> preferredTypes, boolean isCellularUpstreamPermitted)593 private static TypeStatePair findFirstAvailableUpstreamByType( 594 Iterable<UpstreamNetworkState> netStates, Iterable<Integer> preferredTypes, 595 boolean isCellularUpstreamPermitted) { 596 final TypeStatePair result = new TypeStatePair(); 597 598 for (int type : preferredTypes) { 599 NetworkCapabilities nc; 600 try { 601 nc = networkCapabilitiesForType(type); 602 } catch (IllegalArgumentException iae) { 603 Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type); 604 continue; 605 } 606 if (!isCellularUpstreamPermitted && isCellular(nc)) { 607 continue; 608 } 609 610 for (UpstreamNetworkState value : netStates) { 611 if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) { 612 continue; 613 } 614 615 result.type = type; 616 result.ns = value; 617 return result; 618 } 619 } 620 621 return result; 622 } 623 allLocalPrefixes(Iterable<UpstreamNetworkState> netStates)624 private static HashSet<IpPrefix> allLocalPrefixes(Iterable<UpstreamNetworkState> netStates) { 625 final HashSet<IpPrefix> prefixSet = new HashSet<>(); 626 627 for (UpstreamNetworkState ns : netStates) { 628 final LinkProperties lp = ns.linkProperties; 629 if (lp == null) continue; 630 prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp)); 631 } 632 633 return prefixSet; 634 } 635 636 /** Check whether upstream is cellular. */ isCellular(UpstreamNetworkState ns)637 static boolean isCellular(UpstreamNetworkState ns) { 638 return (ns != null) && isCellular(ns.networkCapabilities); 639 } 640 isCellular(NetworkCapabilities nc)641 private static boolean isCellular(NetworkCapabilities nc) { 642 return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) 643 && nc.hasCapability(NET_CAPABILITY_NOT_VPN); 644 } 645 hasCapability(UpstreamNetworkState ns, int netCap)646 private static boolean hasCapability(UpstreamNetworkState ns, int netCap) { 647 return (ns != null) && (ns.networkCapabilities != null) 648 && ns.networkCapabilities.hasCapability(netCap); 649 } 650 isNetworkUsableAndNotCellular(UpstreamNetworkState ns)651 private static boolean isNetworkUsableAndNotCellular(UpstreamNetworkState ns) { 652 return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) 653 && !isCellular(ns.networkCapabilities); 654 } 655 findFirstDunNetwork( Iterable<UpstreamNetworkState> netStates)656 private static UpstreamNetworkState findFirstDunNetwork( 657 Iterable<UpstreamNetworkState> netStates) { 658 for (UpstreamNetworkState ns : netStates) { 659 if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns; 660 } 661 662 return null; 663 } 664 isTestNetwork(UpstreamNetworkState ns)665 static boolean isTestNetwork(UpstreamNetworkState ns) { 666 return ((ns != null) && (ns.networkCapabilities != null) 667 && ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_TEST)); 668 } 669 findFirstTestNetwork( Iterable<UpstreamNetworkState> netStates)670 private UpstreamNetworkState findFirstTestNetwork( 671 Iterable<UpstreamNetworkState> netStates) { 672 for (UpstreamNetworkState ns : netStates) { 673 if (isTestNetwork(ns)) return ns; 674 } 675 676 return null; 677 } 678 679 /** 680 * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance. 681 * This function is used for deprecated legacy type and be disabled by default. 682 */ 683 @VisibleForTesting networkCapabilitiesForType(int type)684 public static NetworkCapabilities networkCapabilitiesForType(int type) { 685 final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); 686 687 // Map from type to transports. 688 final int notFound = -1; 689 final int transport = sLegacyTypeToTransport.get(type, notFound); 690 if (transport == notFound) { 691 throw new IllegalArgumentException("unknown legacy type: " + type); 692 } 693 builder.addTransportType(transport); 694 695 if (type == TYPE_MOBILE_DUN) { 696 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); 697 // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES. 698 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 699 } else { 700 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 701 } 702 return builder.build(); 703 } 704 705 /** Set test network as preferred upstream. */ setPreferTestNetworks(boolean prefer)706 public void setPreferTestNetworks(boolean prefer) { 707 mPreferTestNetworks = prefer; 708 } 709 } 710