diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 48a2992616eb6730ff7fa50801b24c9e6ec6dd4e..b42242eb44233c1dc5bc207ef887771990be5188 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -218,6 +218,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); } + private WifiManager getWifiManager() { + return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + private void updateConfiguration() { mConfig = new TetheringConfiguration(mContext); } @@ -396,8 +400,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private int setWifiTethering(final boolean enable) { synchronized (mPublicSync) { mWifiTetherRequested = enable; - final WifiManager wifiManager = - (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + final WifiManager wifiManager = getWifiManager(); if ((enable && wifiManager.startSoftAp(null /* use existing wifi config */)) || (!enable && wifiManager.stopSoftAp())) { return ConnectivityManager.TETHER_ERROR_NO_ERROR; @@ -1421,12 +1424,37 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } else { mForwardedDownstreams.remove(who); } + + // If this is a Wi-Fi interface, notify WifiManager of the active serving state. + if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) { + final WifiManager mgr = getWifiManager(); + final String iface = who.interfaceName(); + switch (mode) { + case IControlsTethering.STATE_TETHERED: + mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_TETHERED); + break; + case IControlsTethering.STATE_LOCAL_ONLY: + mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); + break; + default: + Log.wtf(TAG, "Unknown active serving mode: " + mode); + break; + } + } } private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) { mNotifyList.remove(who); mIPv6TetheringCoordinator.removeActiveDownstream(who); mForwardedDownstreams.remove(who); + + // If this is a Wi-Fi interface, tell WifiManager of any errors. + if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) { + if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + getWifiManager().updateInterfaceIpState( + who.interfaceName(), WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR); + } + } } class InitialState extends State { @@ -1743,7 +1771,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who, int state, int error) { synchronized (mPublicSync) { - TetherState tetherState = mTetherStates.get(iface); + final TetherState tetherState = mTetherStates.get(iface); if (tetherState != null && tetherState.stateMachine.equals(who)) { tetherState.lastState = state; tetherState.lastError = error; diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index e21349af8649ad4e5b052a4c7c111ac7cd441b1c..d3cfd875faae3669d98cb811634621e3e912dc54 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -117,9 +117,11 @@ public class TetherInterfaceStateMachine extends StateMachine { setInitialState(mInitialState); } - public int interfaceType() { - return mInterfaceType; - } + public String interfaceName() { return mIfaceName; } + + public int interfaceType() { return mInterfaceType; } + + public int lastError() { return mLastError; } // configured when we start tethering and unconfig'd on error or conclusion private boolean configureIfaceIp(boolean enabled) { diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index b2c1244af7082c31a031b51444d3438e184550be..7a1c2395c438e8f97270bbfd16dec243e6fd1b1f 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -236,6 +236,9 @@ public class TetheringTest { verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); + verify(mWifiManager).updateInterfaceIpState( + mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); + verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY); // UpstreamNetworkMonitor will be started, and will register two callbacks: // a "listen all" and a "track default". @@ -261,6 +264,7 @@ public class TetheringTest { verify(mNMService, times(1)).stopTethering(); verify(mNMService, times(1)).setIpForwardingEnabled(false); verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE, @@ -292,6 +296,9 @@ public class TetheringTest { verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); + verify(mWifiManager).updateInterfaceIpState( + mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED); + verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER); // UpstreamNetworkMonitor will be started, and will register two callbacks: // a "listen all" and a "track default". @@ -338,6 +345,7 @@ public class TetheringTest { verify(mNMService, times(1)).stopTethering(); verify(mNMService, times(1)).setIpForwardingEnabled(false); verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,