Loading services/core/java/com/android/server/connectivity/Tethering.java +180 −46 Original line number Diff line number Diff line Loading @@ -1017,16 +1017,30 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * tethering master state machine thread for subsequent processing. */ class UpstreamNetworkCallback extends NetworkCallback { @Override public void onAvailable(Network network) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_AVAILABLE, 0, network); } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES, 0, new NetworkState(null, null, newNc, network, null, null)); } @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { mTetherMasterSM.sendMessage( TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED, mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0, new NetworkState(null, newLp, null, network, null, null)); } @Override public void onLost(Network network) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network); mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_LOST, 0, network); } } Loading @@ -1045,6 +1059,11 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * could/should be moved here. */ class UpstreamNetworkMonitor { static final int EVENT_ON_AVAILABLE = 1; static final int EVENT_ON_CAPABILITIES = 2; static final int EVENT_ON_LINKPROPERTIES = 3; static final int EVENT_ON_LOST = 4; final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); NetworkCallback mDefaultNetworkCallback; NetworkCallback mDunTetheringCallback; Loading Loading @@ -1079,33 +1098,107 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mNetworkMap.clear(); } // Returns true if these updated LinkProperties pertain to the current // upstream network interface, false otherwise (or if there is not // currently any upstream tethering interface). boolean processLinkPropertiesChanged(NetworkState networkState) { if (networkState == null || networkState.network == null || networkState.linkProperties == null) { return false; NetworkState lookup(Network network) { return (network != null) ? mNetworkMap.get(network) : null; } mNetworkMap.put(networkState.network, networkState); NetworkState processCallback(int arg1, Object obj) { switch (arg1) { case EVENT_ON_AVAILABLE: { final Network network = (Network) obj; if (VDBG) { Log.d(TAG, "EVENT_ON_AVAILABLE for " + network); } if (!mNetworkMap.containsKey(network)) { mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null)); } if (mCurrentUpstreamIface != null) { for (String ifname : networkState.linkProperties.getAllInterfaceNames()) { if (mCurrentUpstreamIface.equals(ifname)) { return true; final ConnectivityManager cm = getConnectivityManager(); if (mDefaultNetworkCallback != null) { cm.requestNetworkCapabilities(mDefaultNetworkCallback); cm.requestLinkProperties(mDefaultNetworkCallback); } // Requesting updates for mDunTetheringCallback is not // necessary. Because it's a listen, it will already have // heard all NetworkCapabilities and LinkProperties updates // since UpstreamNetworkMonitor was started. Because we // start UpstreamNetworkMonitor before chooseUpstreamType() // is ever invoked (it can register a DUN request) this is // mostly safe. However, if a DUN network is already up for // some reason (unlikely, because DUN is restricted and, // unless the DUN network is shared with another APN, only // the system can request it and this is the only part of // the system that requests it) we won't know its // LinkProperties or NetworkCapabilities. return mNetworkMap.get(network); } case EVENT_ON_CAPABILITIES: { final NetworkState ns = (NetworkState) obj; if (!mNetworkMap.containsKey(ns.network)) { // Ignore updates for networks for which we have not yet // received onAvailable() - which should never happen - // or for which we have already received onLost(). return null; } if (VDBG) { Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s", ns.network, ns.networkCapabilities)); } final NetworkState prev = mNetworkMap.get(ns.network); mNetworkMap.put(ns.network, new NetworkState(null, prev.linkProperties, ns.networkCapabilities, ns.network, null, null)); return mNetworkMap.get(ns.network); } case EVENT_ON_LINKPROPERTIES: { final NetworkState ns = (NetworkState) obj; if (!mNetworkMap.containsKey(ns.network)) { // Ignore updates for networks for which we have not yet // received onAvailable() - which should never happen - // or for which we have already received onLost(). return null; } if (VDBG) { Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s", ns.network, ns.linkProperties)); } final NetworkState prev = mNetworkMap.get(ns.network); mNetworkMap.put(ns.network, new NetworkState(null, ns.linkProperties, prev.networkCapabilities, ns.network, null, null)); return mNetworkMap.get(ns.network); } case EVENT_ON_LOST: { final Network network = (Network) obj; if (VDBG) { Log.d(TAG, "EVENT_ON_LOST for " + network); } return mNetworkMap.remove(network); } default: return null; } } return false; } void processNetworkLost(Network network) { if (network != null) { mNetworkMap.remove(network); // Needed because the canonical source of upstream truth is just the // upstream interface name, |mCurrentUpstreamIface|. This is ripe for // future simplification, once the upstream Network is canonical. boolean pertainsToCurrentUpstream(NetworkState ns) { if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) { for (String ifname : ns.linkProperties.getAllInterfaceNames()) { if (mCurrentUpstreamIface.equals(ifname)) { return true; } } } return false; } class TetherMasterSM extends StateMachine { Loading @@ -1120,8 +1213,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering static final int CMD_RETRY_UPSTREAM = BASE_MASTER + 4; // Events from NetworkCallbacks that we process on the master state // machine thread on behalf of the UpstreamNetworkMonitor. static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED = BASE_MASTER + 5; static final int EVENT_UPSTREAM_LOST = BASE_MASTER + 6; static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5; private State mInitialState; private State mTetherModeAliveState; Loading Loading @@ -1278,6 +1370,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } protected void chooseUpstreamType(boolean tryCell) { final ConnectivityManager cm = getConnectivityManager(); int upType = ConnectivityManager.TYPE_NONE; String iface = null; Loading @@ -1292,8 +1385,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } for (Integer netType : mUpstreamIfaceTypes) { NetworkInfo info = getConnectivityManager().getNetworkInfo(netType.intValue()); NetworkInfo info = cm.getNetworkInfo(netType.intValue()); if ((info != null) && info.isConnected()) { upType = netType.intValue(); break; Loading Loading @@ -1334,9 +1426,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering break; } Network network = null; if (upType != ConnectivityManager.TYPE_NONE) { LinkProperties linkProperties = getConnectivityManager().getLinkProperties(upType); LinkProperties linkProperties = cm.getLinkProperties(upType); if (linkProperties != null) { // Find the interface with the default IPv4 route. It may be the // interface described by linkProperties, or one of the interfaces Loading @@ -1353,7 +1445,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } if (iface != null) { Network network = getConnectivityManager().getNetworkForType(upType); network = cm.getNetworkForType(upType); if (network == null) { Log.e(TAG, "No Network for upstream type " + upType + "!"); } Loading @@ -1361,6 +1453,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } notifyTetheredOfNewUpstreamIface(iface); NetworkState ns = mUpstreamNetworkMonitor.lookup(network); if (ns != null && pertainsToCurrentUpstream(ns)) { // If we already have NetworkState for this network examine // it immediately, because there likely will be no second // EVENT_ON_AVAILABLE (it was already received). handleNewUpstreamNetworkState(ns); } } protected void setDnsForwarders(final Network network, final LinkProperties lp) { Loading Loading @@ -1393,6 +1492,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering ifaceName); } } protected void handleNewUpstreamNetworkState(NetworkState ns) { mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns); } } private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0); Loading Loading @@ -1582,11 +1685,18 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(mTryCell); mTryCell = !mTryCell; break; case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED: NetworkState state = (NetworkState) message.obj; if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) { setDnsForwarders(state.network, state.linkProperties); } else if (mCurrentUpstreamIface == null) { case EVENT_UPSTREAM_CALLBACK: { // First: always update local state about every network. final NetworkState ns = mUpstreamNetworkMonitor.processCallback( message.arg1, message.obj); if (ns == null || !pertainsToCurrentUpstream(ns)) { // TODO: In future, this is where upstream evaluation and selection // could be handled for notifications which include sufficient data. // For example, after CONNECTIVITY_ACTION listening is removed, here // is where we could observe a Wi-Fi network becoming available and // passing validation. if (mCurrentUpstreamIface == null) { // If we have no upstream interface, try to run through upstream // selection again. If, for example, IPv4 connectivity has shown up // after IPv6 (e.g., 464xlat became available) we want the chance to Loading @@ -1594,12 +1704,36 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(false); } break; case EVENT_UPSTREAM_LOST: // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation // is triggered via received CONNECTIVITY_ACTION broadcasts that result // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED. mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj); } switch (message.arg1) { case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE: // The default network changed, or DUN connected // before this callback was processed. Updates // for the current NetworkCapabilities and // LinkProperties have been requested (default // request) or are being sent shortly (DUN). Do // nothing until they arrive; if no updates // arrive there's nothing to do. break; case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES: handleNewUpstreamNetworkState(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: setDnsForwarders(ns.network, ns.linkProperties); handleNewUpstreamNetworkState(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LOST: // TODO: Re-evaluate possible upstreams. Currently upstream // reevaluation is triggered via received CONNECTIVITY_ACTION // broadcasts that result in being passed a // TetherMasterSM.CMD_UPSTREAM_CHANGED. break; default: break; } break; } default: retValue = false; break; Loading Loading
services/core/java/com/android/server/connectivity/Tethering.java +180 −46 Original line number Diff line number Diff line Loading @@ -1017,16 +1017,30 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * tethering master state machine thread for subsequent processing. */ class UpstreamNetworkCallback extends NetworkCallback { @Override public void onAvailable(Network network) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_AVAILABLE, 0, network); } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES, 0, new NetworkState(null, null, newNc, network, null, null)); } @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { mTetherMasterSM.sendMessage( TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED, mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0, new NetworkState(null, newLp, null, network, null, null)); } @Override public void onLost(Network network) { mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network); mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK, UpstreamNetworkMonitor.EVENT_ON_LOST, 0, network); } } Loading @@ -1045,6 +1059,11 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * could/should be moved here. */ class UpstreamNetworkMonitor { static final int EVENT_ON_AVAILABLE = 1; static final int EVENT_ON_CAPABILITIES = 2; static final int EVENT_ON_LINKPROPERTIES = 3; static final int EVENT_ON_LOST = 4; final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); NetworkCallback mDefaultNetworkCallback; NetworkCallback mDunTetheringCallback; Loading Loading @@ -1079,33 +1098,107 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mNetworkMap.clear(); } // Returns true if these updated LinkProperties pertain to the current // upstream network interface, false otherwise (or if there is not // currently any upstream tethering interface). boolean processLinkPropertiesChanged(NetworkState networkState) { if (networkState == null || networkState.network == null || networkState.linkProperties == null) { return false; NetworkState lookup(Network network) { return (network != null) ? mNetworkMap.get(network) : null; } mNetworkMap.put(networkState.network, networkState); NetworkState processCallback(int arg1, Object obj) { switch (arg1) { case EVENT_ON_AVAILABLE: { final Network network = (Network) obj; if (VDBG) { Log.d(TAG, "EVENT_ON_AVAILABLE for " + network); } if (!mNetworkMap.containsKey(network)) { mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null)); } if (mCurrentUpstreamIface != null) { for (String ifname : networkState.linkProperties.getAllInterfaceNames()) { if (mCurrentUpstreamIface.equals(ifname)) { return true; final ConnectivityManager cm = getConnectivityManager(); if (mDefaultNetworkCallback != null) { cm.requestNetworkCapabilities(mDefaultNetworkCallback); cm.requestLinkProperties(mDefaultNetworkCallback); } // Requesting updates for mDunTetheringCallback is not // necessary. Because it's a listen, it will already have // heard all NetworkCapabilities and LinkProperties updates // since UpstreamNetworkMonitor was started. Because we // start UpstreamNetworkMonitor before chooseUpstreamType() // is ever invoked (it can register a DUN request) this is // mostly safe. However, if a DUN network is already up for // some reason (unlikely, because DUN is restricted and, // unless the DUN network is shared with another APN, only // the system can request it and this is the only part of // the system that requests it) we won't know its // LinkProperties or NetworkCapabilities. return mNetworkMap.get(network); } case EVENT_ON_CAPABILITIES: { final NetworkState ns = (NetworkState) obj; if (!mNetworkMap.containsKey(ns.network)) { // Ignore updates for networks for which we have not yet // received onAvailable() - which should never happen - // or for which we have already received onLost(). return null; } if (VDBG) { Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s", ns.network, ns.networkCapabilities)); } final NetworkState prev = mNetworkMap.get(ns.network); mNetworkMap.put(ns.network, new NetworkState(null, prev.linkProperties, ns.networkCapabilities, ns.network, null, null)); return mNetworkMap.get(ns.network); } case EVENT_ON_LINKPROPERTIES: { final NetworkState ns = (NetworkState) obj; if (!mNetworkMap.containsKey(ns.network)) { // Ignore updates for networks for which we have not yet // received onAvailable() - which should never happen - // or for which we have already received onLost(). return null; } if (VDBG) { Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s", ns.network, ns.linkProperties)); } final NetworkState prev = mNetworkMap.get(ns.network); mNetworkMap.put(ns.network, new NetworkState(null, ns.linkProperties, prev.networkCapabilities, ns.network, null, null)); return mNetworkMap.get(ns.network); } case EVENT_ON_LOST: { final Network network = (Network) obj; if (VDBG) { Log.d(TAG, "EVENT_ON_LOST for " + network); } return mNetworkMap.remove(network); } default: return null; } } return false; } void processNetworkLost(Network network) { if (network != null) { mNetworkMap.remove(network); // Needed because the canonical source of upstream truth is just the // upstream interface name, |mCurrentUpstreamIface|. This is ripe for // future simplification, once the upstream Network is canonical. boolean pertainsToCurrentUpstream(NetworkState ns) { if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) { for (String ifname : ns.linkProperties.getAllInterfaceNames()) { if (mCurrentUpstreamIface.equals(ifname)) { return true; } } } return false; } class TetherMasterSM extends StateMachine { Loading @@ -1120,8 +1213,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering static final int CMD_RETRY_UPSTREAM = BASE_MASTER + 4; // Events from NetworkCallbacks that we process on the master state // machine thread on behalf of the UpstreamNetworkMonitor. static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED = BASE_MASTER + 5; static final int EVENT_UPSTREAM_LOST = BASE_MASTER + 6; static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5; private State mInitialState; private State mTetherModeAliveState; Loading Loading @@ -1278,6 +1370,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } protected void chooseUpstreamType(boolean tryCell) { final ConnectivityManager cm = getConnectivityManager(); int upType = ConnectivityManager.TYPE_NONE; String iface = null; Loading @@ -1292,8 +1385,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } for (Integer netType : mUpstreamIfaceTypes) { NetworkInfo info = getConnectivityManager().getNetworkInfo(netType.intValue()); NetworkInfo info = cm.getNetworkInfo(netType.intValue()); if ((info != null) && info.isConnected()) { upType = netType.intValue(); break; Loading Loading @@ -1334,9 +1426,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering break; } Network network = null; if (upType != ConnectivityManager.TYPE_NONE) { LinkProperties linkProperties = getConnectivityManager().getLinkProperties(upType); LinkProperties linkProperties = cm.getLinkProperties(upType); if (linkProperties != null) { // Find the interface with the default IPv4 route. It may be the // interface described by linkProperties, or one of the interfaces Loading @@ -1353,7 +1445,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } if (iface != null) { Network network = getConnectivityManager().getNetworkForType(upType); network = cm.getNetworkForType(upType); if (network == null) { Log.e(TAG, "No Network for upstream type " + upType + "!"); } Loading @@ -1361,6 +1453,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } notifyTetheredOfNewUpstreamIface(iface); NetworkState ns = mUpstreamNetworkMonitor.lookup(network); if (ns != null && pertainsToCurrentUpstream(ns)) { // If we already have NetworkState for this network examine // it immediately, because there likely will be no second // EVENT_ON_AVAILABLE (it was already received). handleNewUpstreamNetworkState(ns); } } protected void setDnsForwarders(final Network network, final LinkProperties lp) { Loading Loading @@ -1393,6 +1492,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering ifaceName); } } protected void handleNewUpstreamNetworkState(NetworkState ns) { mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns); } } private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0); Loading Loading @@ -1582,11 +1685,18 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(mTryCell); mTryCell = !mTryCell; break; case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED: NetworkState state = (NetworkState) message.obj; if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) { setDnsForwarders(state.network, state.linkProperties); } else if (mCurrentUpstreamIface == null) { case EVENT_UPSTREAM_CALLBACK: { // First: always update local state about every network. final NetworkState ns = mUpstreamNetworkMonitor.processCallback( message.arg1, message.obj); if (ns == null || !pertainsToCurrentUpstream(ns)) { // TODO: In future, this is where upstream evaluation and selection // could be handled for notifications which include sufficient data. // For example, after CONNECTIVITY_ACTION listening is removed, here // is where we could observe a Wi-Fi network becoming available and // passing validation. if (mCurrentUpstreamIface == null) { // If we have no upstream interface, try to run through upstream // selection again. If, for example, IPv4 connectivity has shown up // after IPv6 (e.g., 464xlat became available) we want the chance to Loading @@ -1594,12 +1704,36 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(false); } break; case EVENT_UPSTREAM_LOST: // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation // is triggered via received CONNECTIVITY_ACTION broadcasts that result // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED. mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj); } switch (message.arg1) { case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE: // The default network changed, or DUN connected // before this callback was processed. Updates // for the current NetworkCapabilities and // LinkProperties have been requested (default // request) or are being sent shortly (DUN). Do // nothing until they arrive; if no updates // arrive there's nothing to do. break; case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES: handleNewUpstreamNetworkState(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: setDnsForwarders(ns.network, ns.linkProperties); handleNewUpstreamNetworkState(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LOST: // TODO: Re-evaluate possible upstreams. Currently upstream // reevaluation is triggered via received CONNECTIVITY_ACTION // broadcasts that result in being passed a // TetherMasterSM.CMD_UPSTREAM_CHANGED. break; default: break; } break; } default: retValue = false; break; Loading