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