From: Erik Kline Date: Wed, 31 May 2017 06:53:53 +0000 (+0900) Subject: Handle Wi-Fi passing explicit interface name and AP/IP mode X-Git-Tag: android-x86-9.0-r1~1029^2^2~8^2~110^2~50^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=2efb827f61db989ab55792052c99713ef5f5eefa;p=android-x86%2Fframeworks-base.git Handle Wi-Fi passing explicit interface name and AP/IP mode Test: as follows - built - flashed - booted - runtest frameworks-net passes Bug: 31466854 Bug: 32163131 Bug: 62076211 Change-Id: I3557a9c14f4e9f1de1869084566a179003d98ffe --- diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index dffa670f6e7a..31100000e501 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -18,7 +18,13 @@ package com.android.server.connectivity; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; +import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; +import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static com.android.server.ConnectivityService.SHORT_ARG; @@ -788,48 +794,80 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } private void handleWifiApAction(Intent intent) { - final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED); + final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED); + final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME); + final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED); + synchronized (Tethering.this.mPublicSync) { switch (curState) { case WifiManager.WIFI_AP_STATE_ENABLING: // We can see this state on the way to both enabled and failure states. break; case WifiManager.WIFI_AP_STATE_ENABLED: - // When the AP comes up and we've been requested to tether it, do so. - // Otherwise, assume it's a local-only hotspot request. - final int state = mWifiTetherRequested - ? IControlsTethering.STATE_TETHERED - : IControlsTethering.STATE_LOCAL_ONLY; - tetherMatchingInterfaces(state, ConnectivityManager.TETHERING_WIFI); + enableWifiIpServingLocked(ifname, ipmode); break; case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_DISABLING: case WifiManager.WIFI_AP_STATE_FAILED: default: - if (DBG) { - Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + - curState); - } - // Tell appropriate interface state machines that they should tear - // themselves down. - for (int i = 0; i < mTetherStates.size(); i++) { - TetherInterfaceStateMachine tism = - mTetherStates.valueAt(i).stateMachine; - if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) { - tism.sendMessage( - TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); - break; // There should be at most one of these. - } - } - // Regardless of whether we requested this transition, the AP has gone - // down. Don't try to tether again unless we're requested to do so. - mWifiTetherRequested = false; - break; + disableWifiIpServingLocked(curState); + break; } } } } + // TODO: Pass in the interface name and, if non-empty, only turn down IP + // serving on that one interface. + private void disableWifiIpServingLocked(int apState) { + if (DBG) Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + apState); + + // Tell appropriate interface state machines that they should tear + // themselves down. + for (int i = 0; i < mTetherStates.size(); i++) { + TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine; + if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) { + tism.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); + break; // There should be at most one of these. + } + } + // Regardless of whether we requested this transition, the AP has gone + // down. Don't try to tether again unless we're requested to do so. + mWifiTetherRequested = false; + } + + private void enableWifiIpServingLocked(String ifname, int wifiIpMode) { + // Map wifiIpMode values to IControlsTethering serving states, inferring + // from mWifiTetherRequested as a final "best guess". + final int ipServingMode; + switch (wifiIpMode) { + case IFACE_IP_MODE_TETHERED: + ipServingMode = IControlsTethering.STATE_TETHERED; + break; + case IFACE_IP_MODE_LOCAL_ONLY: + ipServingMode = IControlsTethering.STATE_LOCAL_ONLY; + break; + default: + // Resort to legacy "guessing" behaviour. + // + // When the AP comes up and we've been requested to tether it, + // do so. Otherwise, assume it's a local-only hotspot request. + // + // TODO: Once all AP broadcasts are known to include ifname and + // mode information delete this code path and log an error. + ipServingMode = mWifiTetherRequested + ? IControlsTethering.STATE_TETHERED + : IControlsTethering.STATE_LOCAL_ONLY; + break; + } + + if (!TextUtils.isEmpty(ifname)) { + changeInterfaceState(ifname, ipServingMode); + } else { + tetherMatchingInterfaces(ipServingMode, ConnectivityManager.TETHERING_WIFI); + } + } + // TODO: Consider renaming to something more accurate in its description. // This method: // - allows requesting either tethering or local hotspot serving states @@ -862,22 +900,26 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering return; } + changeInterfaceState(chosenIface, requestedState); + } + + private void changeInterfaceState(String ifname, int requestedState) { final int result; switch (requestedState) { case IControlsTethering.STATE_UNAVAILABLE: case IControlsTethering.STATE_AVAILABLE: - result = untether(chosenIface); + result = untether(ifname); break; case IControlsTethering.STATE_TETHERED: case IControlsTethering.STATE_LOCAL_ONLY: - result = tether(chosenIface, requestedState); + result = tether(ifname, requestedState); break; default: Log.wtf(TAG, "Unknown interface state: " + requestedState); return; } if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) { - Log.e(TAG, "unable start or stop tethering on iface " + chosenIface); + Log.e(TAG, "unable start or stop tethering on iface " + ifname); return; } } @@ -1360,10 +1402,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering final String iface = who.interfaceName(); switch (mode) { case IControlsTethering.STATE_TETHERED: - mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_TETHERED); + mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED); break; case IControlsTethering.STATE_LOCAL_ONLY: - mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); + mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY); break; default: Log.wtf(TAG, "Unknown active serving mode: " + mode); @@ -1381,7 +1423,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) { if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) { getWifiManager().updateInterfaceIpState( - who.interfaceName(), WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR); + who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR); } } } diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 241b828d8f4d..b6922d4be6ff 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -16,6 +16,12 @@ package com.android.server.connectivity; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; +import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; +import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; +import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; +import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyBoolean; @@ -222,12 +228,22 @@ public class TetheringTest { private void sendWifiApStateChanged(int state) { final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); - intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, state); + intent.putExtra(EXTRA_WIFI_AP_STATE, state); mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void verifyInterfaceServingModeStarted() throws Exception { - verify(mNMService, times(1)).listInterfaces(); + private void sendWifiApStateChanged(int state, String ifname, int ipmode) { + final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); + intent.putExtra(EXTRA_WIFI_AP_STATE, state); + intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname); + intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode); + mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } + + private void verifyInterfaceServingModeStarted(boolean ifnameKnown) throws Exception { + if (!ifnameKnown) { + verify(mNMService, times(1)).listInterfaces(); + } verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); verify(mNMService, times(1)) .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); @@ -243,18 +259,21 @@ public class TetheringTest { mIntents.remove(bcast); } - @Test - public void workingLocalOnlyHotspot() throws Exception { + public void workingLocalOnlyHotspot(boolean enrichedApBroadcast) throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that // hotspot mode is to be started. mTethering.interfaceStatusChanged(mTestIfname, true); - sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED); + if (enrichedApBroadcast) { + sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY); + } else { + sendWifiApStateChanged(WIFI_AP_STATE_ENABLED); + } mLooper.dispatchAll(); - verifyInterfaceServingModeStarted(); + verifyInterfaceServingModeStarted(enrichedApBroadcast); verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER); verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); @@ -295,7 +314,16 @@ public class TetheringTest { } @Test - public void workingWifiTethering() throws Exception { + public void workingLocalOnlyHotspotLegacyApBroadcast() throws Exception { + workingLocalOnlyHotspot(false); + } + + @Test + public void workingLocalOnlyHotspotEnrichedApBroadcast() throws Exception { + workingLocalOnlyHotspot(true); + } + + public void workingWifiTethering(boolean enrichedApBroadcast) throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); @@ -311,10 +339,14 @@ public class TetheringTest { // per-interface state machine to start up, and telling us that // tethering mode is to be started. mTethering.interfaceStatusChanged(mTestIfname, true); - sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED); + if (enrichedApBroadcast) { + sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED); + } else { + sendWifiApStateChanged(WIFI_AP_STATE_ENABLED); + } mLooper.dispatchAll(); - verifyInterfaceServingModeStarted(); + verifyInterfaceServingModeStarted(enrichedApBroadcast); verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER); verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); @@ -376,6 +408,16 @@ public class TetheringTest { } @Test + public void workingWifiTetheringLegacyApBroadcast() throws Exception { + workingWifiTethering(false); + } + + @Test + public void workingWifiTetheringEnrichedApBroadcast() throws Exception { + workingWifiTethering(true); + } + + @Test public void failureEnablingIpForwarding() throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);