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.PrefixUtils; 40 import android.net.util.SharedLog; 41 import android.os.Handler; 42 import android.util.Log; 43 import android.util.SparseIntArray; 44 45 import androidx.annotation.NonNull; 46 import androidx.annotation.Nullable; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.util.StateMachine; 50 import com.android.networkstack.apishim.ConnectivityManagerShimImpl; 51 import com.android.networkstack.apishim.common.ConnectivityManagerShim; 52 import com.android.networkstack.apishim.common.UnsupportedApiLevelException; 53 54 import java.util.HashMap; 55 import java.util.HashSet; 56 import java.util.Objects; 57 import java.util.Set; 58 59 60 /** 61 * A class to centralize all the network and link properties information 62 * pertaining to the current and any potential upstream network. 63 * 64 * The owner of UNM gets it to register network callbacks by calling the 65 * following methods : 66 * Calling #startTrackDefaultNetwork() to track the system default network. 67 * Calling #startObserveAllNetworks() to observe all networks. Listening all 68 * networks is necessary while the expression of preferred upstreams remains 69 * a list of legacy connectivity types. In future, this can be revisited. 70 * Calling #setTryCell() to request bringing up mobile DUN or HIPRI. 71 * 72 * The methods and data members of this class are only to be accessed and 73 * modified from the tethering main state machine thread. Any other 74 * access semantics would necessitate the addition of locking. 75 * 76 * TODO: Move upstream selection logic here. 77 * 78 * All callback methods are run on the same thread as the specified target 79 * state machine. This class does not require locking when accessed from this 80 * thread. Access from other threads is not advised. 81 * 82 * @hide 83 */ 84 public class UpstreamNetworkMonitor { 85 private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName(); 86 private static final boolean DBG = false; 87 private static final boolean VDBG = false; 88 89 public static final int EVENT_ON_CAPABILITIES = 1; 90 public static final int EVENT_ON_LINKPROPERTIES = 2; 91 public static final int EVENT_ON_LOST = 3; 92 public static final int EVENT_DEFAULT_SWITCHED = 4; 93 public static final int NOTIFY_LOCAL_PREFIXES = 10; 94 // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default 95 // disabled. 96 @VisibleForTesting 97 public static final int TYPE_NONE = -1; 98 99 private static final int CALLBACK_LISTEN_ALL = 1; 100 private static final int CALLBACK_DEFAULT_INTERNET = 2; 101 private static final int CALLBACK_MOBILE_REQUEST = 3; 102 103 private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); 104 static { sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR)105 sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR)106 sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR)107 sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI)108 sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH)109 sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET)110 sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); 111 } 112 113 private final Context mContext; 114 private final SharedLog mLog; 115 private final StateMachine mTarget; 116 private final Handler mHandler; 117 private final int mWhat; 118 private final HashMap<Network, UpstreamNetworkState> mNetworkMap = new HashMap<>(); 119 private HashSet<IpPrefix> mLocalPrefixes; 120 private ConnectivityManager mCM; 121 private EntitlementManager mEntitlementMgr; 122 private NetworkCallback mListenAllCallback; 123 private NetworkCallback mDefaultNetworkCallback; 124 private NetworkCallback mMobileNetworkCallback; 125 126 /** Whether Tethering has requested a cellular upstream. */ 127 private boolean mTryCell; 128 /** Whether the carrier requires DUN. */ 129 private boolean mDunRequired; 130 /** Whether automatic upstream selection is enabled. */ 131 private boolean mAutoUpstream; 132 133 // Whether the current default upstream is mobile or not. 134 private boolean mIsDefaultCellularUpstream; 135 // The current system default network (not really used yet). 136 private Network mDefaultInternetNetwork; 137 // The current upstream network used for tethering. 138 private Network mTetheringUpstreamNetwork; 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 try { 166 mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler); 167 } catch (UnsupportedApiLevelException e) { 168 Log.wtf(TAG, "registerSystemDefaultNetworkCallback is not supported"); 169 return; 170 } 171 if (mEntitlementMgr == null) { 172 mEntitlementMgr = entitle; 173 } 174 } 175 176 /** Listen all networks. */ startObserveAllNetworks()177 public void startObserveAllNetworks() { 178 stop(); 179 180 final NetworkRequest listenAllRequest = new NetworkRequest.Builder() 181 .clearCapabilities().build(); 182 mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); 183 cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler); 184 } 185 186 /** 187 * Stop tracking candidate tethering upstreams and release mobile network request. 188 * Note: this function is used when tethering is stopped because tethering do not need to 189 * choose upstream anymore. But it would not stop default network tracking because 190 * EntitlementManager may need to know default network to decide whether to request entitlement 191 * check even tethering is not active yet. 192 */ stop()193 public void stop() { 194 setTryCell(false); 195 196 releaseCallback(mListenAllCallback); 197 mListenAllCallback = null; 198 199 mTetheringUpstreamNetwork = null; 200 mNetworkMap.clear(); 201 } 202 reevaluateUpstreamRequirements(boolean tryCell, boolean autoUpstream, boolean dunRequired)203 private void reevaluateUpstreamRequirements(boolean tryCell, boolean autoUpstream, 204 boolean dunRequired) { 205 final boolean mobileRequestRequired = tryCell && (dunRequired || !autoUpstream); 206 final boolean dunRequiredChanged = (mDunRequired != dunRequired); 207 208 mTryCell = tryCell; 209 mDunRequired = dunRequired; 210 mAutoUpstream = autoUpstream; 211 212 if (mobileRequestRequired && !mobileNetworkRequested()) { 213 registerMobileNetworkRequest(); 214 } else if (mobileNetworkRequested() && !mobileRequestRequired) { 215 releaseMobileNetworkRequest(); 216 } else if (mobileNetworkRequested() && dunRequiredChanged) { 217 releaseMobileNetworkRequest(); 218 if (mobileRequestRequired) { 219 registerMobileNetworkRequest(); 220 } 221 } 222 } 223 224 /** 225 * Informs UpstreamNetworkMonitor that a cellular upstream is desired. 226 * 227 * This may result in filing a NetworkRequest for DUN if it is required, or for MOBILE_HIPRI if 228 * automatic upstream selection is disabled and MOBILE_HIPRI is the preferred upstream. 229 */ setTryCell(boolean tryCell)230 public void setTryCell(boolean tryCell) { 231 reevaluateUpstreamRequirements(tryCell, mAutoUpstream, mDunRequired); 232 } 233 234 /** Informs UpstreamNetworkMonitor of upstream configuration parameters. */ setUpstreamConfig(boolean autoUpstream, boolean dunRequired)235 public void setUpstreamConfig(boolean autoUpstream, boolean dunRequired) { 236 reevaluateUpstreamRequirements(mTryCell, autoUpstream, dunRequired); 237 } 238 239 /** Whether mobile network is requested. */ mobileNetworkRequested()240 public boolean mobileNetworkRequested() { 241 return (mMobileNetworkCallback != null); 242 } 243 244 /** Request mobile network if mobile upstream is permitted. */ registerMobileNetworkRequest()245 private void registerMobileNetworkRequest() { 246 if (!isCellularUpstreamPermitted()) { 247 mLog.i("registerMobileNetworkRequest() is not permitted"); 248 releaseMobileNetworkRequest(); 249 return; 250 } 251 if (mMobileNetworkCallback != null) { 252 mLog.e("registerMobileNetworkRequest() already registered"); 253 return; 254 } 255 256 final NetworkRequest mobileUpstreamRequest; 257 if (mDunRequired) { 258 mobileUpstreamRequest = new NetworkRequest.Builder() 259 .addCapability(NET_CAPABILITY_DUN) 260 .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) 261 .addTransportType(TRANSPORT_CELLULAR).build(); 262 } else { 263 mobileUpstreamRequest = new NetworkRequest.Builder() 264 .addCapability(NET_CAPABILITY_INTERNET) 265 .addTransportType(TRANSPORT_CELLULAR).build(); 266 } 267 268 // The existing default network and DUN callbacks will be notified. 269 // Therefore, to avoid duplicate notifications, we only register a no-op. 270 mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST); 271 272 // The following use of the legacy type system cannot be removed until 273 // upstream selection no longer finds networks by legacy type. 274 // See also http://b/34364553 . 275 final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; 276 277 // TODO: Change the timeout from 0 (no onUnavailable callback) to some 278 // moderate callback timeout. This might be useful for updating some UI. 279 // Additionally, we log a message to aid in any subsequent debugging. 280 mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest 281 + " mTryCell=" + mTryCell + " mAutoUpstream=" + mAutoUpstream 282 + " mDunRequired=" + mDunRequired); 283 284 cm().requestNetwork(mobileUpstreamRequest, 0, legacyType, mHandler, 285 mMobileNetworkCallback); 286 } 287 288 /** Release mobile network request. */ releaseMobileNetworkRequest()289 private void releaseMobileNetworkRequest() { 290 if (mMobileNetworkCallback == null) return; 291 292 cm().unregisterNetworkCallback(mMobileNetworkCallback); 293 mMobileNetworkCallback = null; 294 } 295 296 // So many TODOs here, but chief among them is: make this functionality an 297 // integral part of this class such that whenever a higher priority network 298 // becomes available and useful we (a) file a request to keep it up as 299 // necessary and (b) change all upstream tracking state accordingly (by 300 // passing LinkProperties up to Tethering). 301 /** 302 * Select the first available network from |perferredTypes|. 303 */ selectPreferredUpstreamType(Iterable<Integer> preferredTypes)304 public UpstreamNetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) { 305 final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType( 306 mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted()); 307 308 mLog.log("preferred upstream type: " + typeStatePair.type); 309 310 switch (typeStatePair.type) { 311 case TYPE_MOBILE_DUN: 312 case TYPE_MOBILE_HIPRI: 313 // Tethering just selected mobile upstream in spite of the default network being 314 // not mobile. This can happen because of the priority list. 315 // Notify EntitlementManager to check permission for using mobile upstream. 316 if (!mIsDefaultCellularUpstream) { 317 mEntitlementMgr.maybeRunProvisioning(); 318 } 319 break; 320 } 321 322 return typeStatePair.ns; 323 } 324 325 /** 326 * Get current preferred upstream network. If default network is cellular and DUN is required, 327 * preferred upstream would be DUN otherwise preferred upstream is the same as default network. 328 * Returns null if no current upstream is available. 329 */ getCurrentPreferredUpstream()330 public UpstreamNetworkState getCurrentPreferredUpstream() { 331 final UpstreamNetworkState dfltState = (mDefaultInternetNetwork != null) 332 ? mNetworkMap.get(mDefaultInternetNetwork) 333 : null; 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 if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { 537 updateLinkProperties(network, newLp); 538 // When the default network callback calls onLinkPropertiesChanged, it means that 539 // all the network information for the default network is known (because 540 // onLinkPropertiesChanged is called after onAvailable and onCapabilitiesChanged). 541 // Inform tethering that the default network might have changed. 542 maybeHandleNetworkSwitch(network); 543 return; 544 } 545 546 handleLinkProp(network, newLp); 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 665 /** 666 * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance. 667 * This function is used for deprecated legacy type and be disabled by default. 668 */ 669 @VisibleForTesting networkCapabilitiesForType(int type)670 public static NetworkCapabilities networkCapabilitiesForType(int type) { 671 final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); 672 673 // Map from type to transports. 674 final int notFound = -1; 675 final int transport = sLegacyTypeToTransport.get(type, notFound); 676 if (transport == notFound) { 677 throw new IllegalArgumentException("unknown legacy type: " + type); 678 } 679 builder.addTransportType(transport); 680 681 if (type == TYPE_MOBILE_DUN) { 682 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); 683 // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES. 684 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 685 } else { 686 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 687 } 688 return builder.build(); 689 } 690 } 691