Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d46bc2e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Handle Wi-Fi passing explicit interface name and AP/IP mode" into oc-dev

parents bd75ee00 1454ee75
Loading
Loading
Loading
Loading
+74 −32
Original line number Diff line number Diff line
@@ -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;

@@ -800,44 +806,76 @@ 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 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);
                        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;
            TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
            if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
                                tism.sendMessage(
                                        TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
                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;
    }

    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);
        }
    }

@@ -873,22 +911,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;
        }
    }
@@ -1470,10 +1512,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);
@@ -1491,7 +1533,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);
                }
            }
        }
+52 −10
Original line number Diff line number Diff line
@@ -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;
@@ -201,12 +207,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 {
    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));
@@ -222,18 +238,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));
@@ -274,7 +293,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);

@@ -290,10 +318,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));
@@ -354,6 +386,16 @@ public class TetheringTest {
                mTethering.getLastTetherError(mTestIfname));
    }

    @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);