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

Commit d2896669 authored by Christopher Wiley's avatar Christopher Wiley
Browse files

Extract TetherInterfaceSM to its own class.

( cherry-pick of e3f93b02 )

Attempt to keep all existing logic in place, except:

 + Marked a constructor as public, rather than default visible.
 + Added TAG, DBG, VDBG, and decoder ringer statics.
 + Moved static constants related to USB IPs into TetherInterfaceSM.

Bug: 28833951
Test: WiFi Tethering works on angler.

Change-Id: Id961220a9045832354cfe7381e5e9c0d8f54bf90
parent e03fb445
Loading
Loading
Loading
Loading
+1 −439
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.IoThread;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.TetherInterfaceSM;
import com.android.server.net.BaseNetworkObserver;

import java.io.FileDescriptor;
@@ -135,9 +136,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));

    private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
    private static final int USB_PREFIX_LENGTH        = 24;

    // USB is  192.168.42.1 and 255.255.255.0
    // Wifi is 192.168.43.1 and 255.255.255.0
    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
@@ -980,442 +978,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
        }
    }

    /**
     * @hide
     *
     * Tracks the eligibility of a given network interface for tethering.
     */
    public static class TetherInterfaceSM extends StateMachine {
        private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
        // notification from the master SM that it's not in tether mode
        static final int CMD_TETHER_MODE_DEAD            = BASE_IFACE + 1;
        // request from the user that it wants to tether
        static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
        // request from the user that it wants to untether
        static final int CMD_TETHER_UNREQUESTED          = BASE_IFACE + 3;
        // notification that this interface is down
        static final int CMD_INTERFACE_DOWN              = BASE_IFACE + 4;
        // notification that this interface is up
        static final int CMD_INTERFACE_UP                = BASE_IFACE + 5;
        // notification from the master SM that it had an error turning on cellular dun
        static final int CMD_CELL_DUN_ERROR              = BASE_IFACE + 6;
        // notification from the master SM that it had trouble enabling IP Forwarding
        static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IFACE + 7;
        // notification from the master SM that it had trouble disabling IP Forwarding
        static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
        // notification from the master SM that it had trouble starting tethering
        static final int CMD_START_TETHERING_ERROR       = BASE_IFACE + 9;
        // notification from the master SM that it had trouble stopping tethering
        static final int CMD_STOP_TETHERING_ERROR        = BASE_IFACE + 10;
        // notification from the master SM that it had trouble setting the DNS forwarders
        static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IFACE + 11;
        // the upstream connection has changed
        static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IFACE + 12;

        private final State mInitialState;
        private final State mStartingState;
        private final State mTetheredState;
        private final State mUnavailableState;

        private final INetworkManagementService mNMService;
        private final INetworkStatsService mStatsService;
        private final IControlsTethering mTetherController;

        private final boolean mUsb;
        private final String mIfaceName;

        private final Object mMutex;  // Protects the fields below.
        private boolean mAvailable;
        private boolean mTethered;
        private int mLastError;
        private String mMyUpstreamIfaceName;  // may change over time

        TetherInterfaceSM(String ifaceName, Looper looper, boolean usb, Object mutex,
                        INetworkManagementService nMService, INetworkStatsService statsService,
                        IControlsTethering tetherController) {
            super(ifaceName, looper);
            mNMService = nMService;
            mStatsService = statsService;
            mTetherController = tetherController;
            mIfaceName = ifaceName;
            mUsb = usb;
            mMutex = mutex;
            setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);

            mInitialState = new InitialState();
            addState(mInitialState);
            mStartingState = new StartingState();
            addState(mStartingState);
            mTetheredState = new TetheredState();
            addState(mTetheredState);
            mUnavailableState = new UnavailableState();
            addState(mUnavailableState);

            setInitialState(mInitialState);
        }

        @Override
        public String toString() {
            String res = new String();
            res += mIfaceName + " - ";
            IState current = getCurrentState();
            if (current == mInitialState) res += "InitialState";
            if (current == mStartingState) res += "StartingState";
            if (current == mTetheredState) res += "TetheredState";
            if (current == mUnavailableState) res += "UnavailableState";
            if (isAvailable()) res += " - Available";
            if (isTethered()) res += " - Tethered";
            res += " - lastError =" + getLastError();
            return res;
        }

        public int getLastError() {
            synchronized (mMutex) {
                return mLastError;
            }
        }

        private void setLastError(int error) {
            synchronized (mMutex) {
                mLastError = error;

                if (isErrored()) {
                    if (mUsb) {
                        // note everything's been unwound by this point so nothing to do on
                        // further error..
                        configureUsbIface(false, mIfaceName);
                    }
                }
            }
        }

        public boolean isAvailable() {
            synchronized (mMutex) {
                return mAvailable;
            }
        }

        private void setAvailable(boolean available) {
            synchronized (mMutex) {
                mAvailable = available;
            }
        }

        public boolean isTethered() {
            synchronized (mMutex) {
                return mTethered;
            }
        }

        private void setTethered(boolean tethered) {
            synchronized (mMutex) {
                mTethered = tethered;
            }
        }

        public boolean isErrored() {
            synchronized (mMutex) {
                return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
            }
        }

        // configured when we start tethering and unconfig'd on error or conclusion
        private boolean configureUsbIface(boolean enabled, String iface) {
            if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")");

            InterfaceConfiguration ifcg = null;
            try {
                ifcg = mNMService.getInterfaceConfig(iface);
                if (ifcg != null) {
                    InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR);
                    ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH));
                    if (enabled) {
                        ifcg.setInterfaceUp();
                    } else {
                        ifcg.setInterfaceDown();
                    }
                    ifcg.clearFlag("running");
                    mNMService.setInterfaceConfig(iface, ifcg);
                }
            } catch (Exception e) {
                Log.e(TAG, "Error configuring interface " + iface, e);
                return false;
            }

            return true;
        }

        private void maybeLogMessage(State state, int what) {
            if (DBG) {
                Log.d(TAG, state.getName() + " got " +
                        sMagicDecoderRing.get(what, Integer.toString(what)));
            }
        }

        class InitialState extends State {
            @Override
            public void enter() {
                setAvailable(true);
                setTethered(false);
                mTetherController.sendTetherStateChangedBroadcast();
            }

            @Override
            public boolean processMessage(Message message) {
                maybeLogMessage(this, message.what);
                boolean retValue = true;
                switch (message.what) {
                    case CMD_TETHER_REQUESTED:
                        setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
                        mTetherController.notifyInterfaceTetheringReadiness(true, TetherInterfaceSM.this);
                        transitionTo(mStartingState);
                        break;
                    case CMD_INTERFACE_DOWN:
                        transitionTo(mUnavailableState);
                        break;
                    default:
                        retValue = false;
                        break;
                }
                return retValue;
            }
        }

        class StartingState extends State {
            @Override
            public void enter() {
                setAvailable(false);
                if (mUsb) {
                    if (!configureUsbIface(true, mIfaceName)) {
                        mTetherController.notifyInterfaceTetheringReadiness(false, TetherInterfaceSM.this);
                        setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);

                        transitionTo(mInitialState);
                        return;
                    }
                }
                mTetherController.sendTetherStateChangedBroadcast();

                // Skipping StartingState
                transitionTo(mTetheredState);
            }
            @Override
            public boolean processMessage(Message message) {
                maybeLogMessage(this, message.what);
                boolean retValue = true;
                switch (message.what) {
                    // maybe a parent class?
                    case CMD_TETHER_UNREQUESTED:
                        mTetherController.notifyInterfaceTetheringReadiness(false, TetherInterfaceSM.this);
                        if (mUsb) {
                            if (!configureUsbIface(false, mIfaceName)) {
                                setLastErrorAndTransitionToInitialState(
                                    ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
                                break;
                            }
                        }
                        transitionTo(mInitialState);
                        break;
                    case CMD_CELL_DUN_ERROR:
                    case CMD_IP_FORWARDING_ENABLE_ERROR:
                    case CMD_IP_FORWARDING_DISABLE_ERROR:
                    case CMD_START_TETHERING_ERROR:
                    case CMD_STOP_TETHERING_ERROR:
                    case CMD_SET_DNS_FORWARDERS_ERROR:
                        setLastErrorAndTransitionToInitialState(
                                ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
                        break;
                    case CMD_INTERFACE_DOWN:
                        mTetherController.notifyInterfaceTetheringReadiness(false, TetherInterfaceSM.this);
                        transitionTo(mUnavailableState);
                        break;
                    default:
                        retValue = false;
                }
                return retValue;
            }
        }

        class TetheredState extends State {
            @Override
            public void enter() {
                try {
                    mNMService.tetherInterface(mIfaceName);
                } catch (Exception e) {
                    Log.e(TAG, "Error Tethering: " + e.toString());
                    setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);

                    try {
                        mNMService.untetherInterface(mIfaceName);
                    } catch (Exception ee) {
                        Log.e(TAG, "Error untethering after failure!" + ee.toString());
                    }
                    transitionTo(mInitialState);
                    return;
                }
                if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
                setAvailable(false);
                setTethered(true);
                mTetherController.sendTetherStateChangedBroadcast();
            }

            private void cleanupUpstream() {
                if (mMyUpstreamIfaceName != null) {
                    // note that we don't care about errors here.
                    // sometimes interfaces are gone before we get
                    // to remove their rules, which generates errors.
                    // just do the best we can.
                    try {
                        // about to tear down NAT; gather remaining statistics
                        mStatsService.forceUpdate();
                    } catch (Exception e) {
                        if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
                    }
                    try {
                        mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
                    } catch (Exception e) {
                        if (VDBG) Log.e(
                                TAG, "Exception in removeInterfaceForward: " + e.toString());
                    }
                    try {
                        mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
                    } catch (Exception e) {
                        if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
                    }
                    mMyUpstreamIfaceName = null;
                }
                return;
            }

            @Override
            public boolean processMessage(Message message) {
                maybeLogMessage(this, message.what);
                boolean retValue = true;
                boolean error = false;
                switch (message.what) {
                    case CMD_TETHER_UNREQUESTED:
                    case CMD_INTERFACE_DOWN:
                        cleanupUpstream();
                        try {
                            mNMService.untetherInterface(mIfaceName);
                        } catch (Exception e) {
                            setLastErrorAndTransitionToInitialState(
                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
                            break;
                        }
                        mTetherController.notifyInterfaceTetheringReadiness(false, TetherInterfaceSM.this);
                        if (message.what == CMD_TETHER_UNREQUESTED) {
                            if (mUsb) {
                                if (!configureUsbIface(false, mIfaceName)) {
                                    setLastError(
                                            ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
                                }
                            }
                            transitionTo(mInitialState);
                        } else if (message.what == CMD_INTERFACE_DOWN) {
                            transitionTo(mUnavailableState);
                        }
                        if (DBG) Log.d(TAG, "Untethered " + mIfaceName);
                        break;
                    case CMD_TETHER_CONNECTION_CHANGED:
                        String newUpstreamIfaceName = (String)(message.obj);
                        if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
                                (mMyUpstreamIfaceName != null &&
                                mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
                            if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
                            break;
                        }
                        cleanupUpstream();
                        if (newUpstreamIfaceName != null) {
                            try {
                                mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
                                mNMService.startInterfaceForwarding(mIfaceName,
                                        newUpstreamIfaceName);
                            } catch (Exception e) {
                                Log.e(TAG, "Exception enabling Nat: " + e.toString());
                                try {
                                    mNMService.disableNat(mIfaceName, newUpstreamIfaceName);
                                } catch (Exception ee) {}
                                try {
                                    mNMService.untetherInterface(mIfaceName);
                                } catch (Exception ee) {}

                                setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
                                transitionTo(mInitialState);
                                return true;
                            }
                        }
                        mMyUpstreamIfaceName = newUpstreamIfaceName;
                        break;
                    case CMD_CELL_DUN_ERROR:
                    case CMD_IP_FORWARDING_ENABLE_ERROR:
                    case CMD_IP_FORWARDING_DISABLE_ERROR:
                    case CMD_START_TETHERING_ERROR:
                    case CMD_STOP_TETHERING_ERROR:
                    case CMD_SET_DNS_FORWARDERS_ERROR:
                        error = true;
                        // fall through
                    case CMD_TETHER_MODE_DEAD:
                        cleanupUpstream();
                        try {
                            mNMService.untetherInterface(mIfaceName);
                        } catch (Exception e) {
                            setLastErrorAndTransitionToInitialState(
                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
                            break;
                        }
                        if (error) {
                            setLastErrorAndTransitionToInitialState(
                                    ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
                            break;
                        }
                        if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
                        mTetherController.sendTetherStateChangedBroadcast();
                        if (mUsb) {
                            if (!configureUsbIface(false, mIfaceName)) {
                                setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
                            }
                        }
                        transitionTo(mInitialState);
                        break;
                    default:
                        retValue = false;
                        break;
                }
                return retValue;
            }
        }

        class UnavailableState extends State {
            @Override
            public void enter() {
                setAvailable(false);
                setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
                setTethered(false);
                mTetherController.sendTetherStateChangedBroadcast();
            }
            @Override
            public boolean processMessage(Message message) {
                boolean retValue = true;
                switch (message.what) {
                    case CMD_INTERFACE_UP:
                        transitionTo(mInitialState);
                        break;
                    default:
                        retValue = false;
                        break;
                }
                return retValue;
            }
        }

        void setLastErrorAndTransitionToInitialState(int error) {
            setLastError(error);
            transitionTo(mInitialState);
        }

    }

    /**
     * A NetworkCallback class that relays information of interest to the
     * tethering master state machine thread for subsequent processing.
+1 −3
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.server.connectivity.tethering;

import com.android.server.connectivity.Tethering;

/**
 * @hide
 *
@@ -25,5 +23,5 @@ import com.android.server.connectivity.Tethering;
 */
public interface IControlsTethering {
    void sendTetherStateChangedBroadcast();
    void notifyInterfaceTetheringReadiness(boolean isReady, Tethering.TetherInterfaceSM who);
    void notifyInterfaceTetheringReadiness(boolean isReady, TetherInterfaceSM who);
}
 No newline at end of file
+483 −0

File added.

Preview size limit exceeded, changes collapsed.