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

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

Merge "Move findPreferredUpstreamType into UNM" into oc-dr1-dev

parents a3fe8ac3 3760999e
Loading
Loading
Loading
Loading
+2 −54
Original line number Diff line number Diff line
@@ -1247,8 +1247,8 @@ public class Tethering extends BaseNetworkObserver {
            protected void chooseUpstreamType(boolean tryCell) {
                updateConfiguration(); // TODO - remove?

                final int upstreamType = findPreferredUpstreamType(
                        getConnectivityManager(), mConfig);
                final int upstreamType = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
                        mConfig.preferredUpstreamIfaceTypes);
                if (upstreamType == ConnectivityManager.TYPE_NONE) {
                    if (tryCell) {
                        mUpstreamNetworkMonitor.registerMobileNetworkRequest();
@@ -1260,58 +1260,6 @@ public class Tethering extends BaseNetworkObserver {
                setUpstreamByType(upstreamType);
            }

            // TODO: Move this function into UpstreamNetworkMonitor.
            protected int findPreferredUpstreamType(ConnectivityManager cm,
                                                    TetheringConfiguration cfg) {
                int upType = ConnectivityManager.TYPE_NONE;

                if (VDBG) {
                    Log.d(TAG, "chooseUpstreamType has upstream iface types:");
                    for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
                        Log.d(TAG, " " + netType);
                    }
                }

                for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
                    NetworkInfo info = cm.getNetworkInfo(netType.intValue());
                    // TODO: if the network is suspended we should consider
                    // that to be the same as connected here.
                    if ((info != null) && info.isConnected()) {
                        upType = netType.intValue();
                        break;
                    }
                }

                final int preferredUpstreamMobileApn = cfg.isDunRequired
                        ? ConnectivityManager.TYPE_MOBILE_DUN
                        : ConnectivityManager.TYPE_MOBILE_HIPRI;
                mLog.log(String.format(
                        "findPreferredUpstreamType(), preferredApn=%s, got type=%s",
                        getNetworkTypeName(preferredUpstreamMobileApn),
                        getNetworkTypeName(upType)));

                switch (upType) {
                    case ConnectivityManager.TYPE_MOBILE_DUN:
                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
                        // If we're on DUN, put our own grab on it.
                        mUpstreamNetworkMonitor.registerMobileNetworkRequest();
                        break;
                    case ConnectivityManager.TYPE_NONE:
                        break;
                    default:
                        /* If we've found an active upstream connection that's not DUN/HIPRI
                         * we should stop any outstanding DUN/HIPRI start requests.
                         *
                         * If we found NONE we don't want to do this as we want any previous
                         * requests to keep trying to bring up something we can use.
                         */
                        mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
                        break;
                }

                return upType;
            }

            protected void setUpstreamByType(int upType) {
                final ConnectivityManager cm = getConnectivityManager();
                Network network = null;
+70 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.connectivity.tethering;

import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;

@@ -176,6 +178,41 @@ public class UpstreamNetworkMonitor {
        return (network != null) ? mNetworkMap.get(network) : null;
    }

    // So many TODOs here, but chief among them is: make this functionality an
    // integral part of this class such that whenever a higher priority network
    // becomes available and useful we (a) file a request to keep it up as
    // necessary and (b) change all upstream tracking state accordingly (by
    // passing LinkProperties up to Tethering).
    //
    // Next TODO: return NetworkState instead of just the type.
    public int selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
        final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
                mNetworkMap.values(), preferredTypes);

        mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));

        switch (typeStatePair.type) {
            case TYPE_MOBILE_DUN:
            case TYPE_MOBILE_HIPRI:
                // If we're on DUN, put our own grab on it.
                registerMobileNetworkRequest();
                break;
            case TYPE_NONE:
                break;
            default:
                /* If we've found an active upstream connection that's not DUN/HIPRI
                 * we should stop any outstanding DUN/HIPRI start requests.
                 *
                 * If we found NONE we don't want to do this as we want any previous
                 * requests to keep trying to bring up something we can use.
                 */
                releaseMobileNetworkRequest();
                break;
        }

        return typeStatePair.type;
    }

    private void handleAvailable(int callbackType, Network network) {
        if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);

@@ -365,4 +402,37 @@ public class UpstreamNetworkMonitor {
    private void notifyTarget(int which, NetworkState netstate) {
        mTarget.sendMessage(mWhat, which, 0, netstate);
    }

    static private class TypeStatePair {
        public int type = TYPE_NONE;
        public NetworkState ns = null;
    }

    static private TypeStatePair findFirstAvailableUpstreamByType(
            Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
        final TypeStatePair result = new TypeStatePair();

        for (int type : preferredTypes) {
            NetworkCapabilities nc;
            try {
                nc = ConnectivityManager.networkCapabilitiesForType(type);
            } catch (IllegalArgumentException iae) {
                Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
                       ConnectivityManager.getNetworkTypeName(type));
                continue;
            }

            for (NetworkState value : netStates) {
                if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
                    continue;
                }

                result.type = type;
                result.ns = value;
                return result;
            }
        }

        return result;
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -394,7 +394,6 @@ public class TetheringTest {
                any(NetworkCallback.class), any(Handler.class));
        // In tethering mode, in the default configuration, an explicit request
        // for a mobile network is also made.
        verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
        verify(mConnectivityManager, times(1)).requestNetwork(
                any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
                any(Handler.class));
+109 −0
Original line number Diff line number Diff line
@@ -18,7 +18,12 @@ package com.android.server.connectivity.tethering;

import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -59,6 +64,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -240,6 +246,72 @@ public class UpstreamNetworkMonitorTest {
        assertFalse(mUNM.mobileNetworkRequested());
    }

    @Test
    public void testSelectPreferredUpstreamType() throws Exception {
        final Collection<Integer> preferredTypes = new ArrayList<>();
        preferredTypes.add(TYPE_WIFI);

        mUNM.start();
        // There are no networks, so there is nothing to select.
        assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));

        final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
        wifiAgent.fakeConnect();
        // WiFi is up, we should prefer it.
        assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
        wifiAgent.fakeDisconnect();
        // There are no networks, so there is nothing to select.
        assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));

        final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
        cellAgent.fakeConnect();
        assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));

        preferredTypes.add(TYPE_MOBILE_DUN);
        // This is coupled with preferred types in TetheringConfiguration.
        mUNM.updateMobileRequiresDun(true);
        // DUN is available, but only use regular cell: no upstream selected.
        assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
        preferredTypes.remove(TYPE_MOBILE_DUN);
        // No WiFi, but our preferred flavour of cell is up.
        preferredTypes.add(TYPE_MOBILE_HIPRI);
        // This is coupled with preferred types in TetheringConfiguration.
        mUNM.updateMobileRequiresDun(false);
        assertEquals(TYPE_MOBILE_HIPRI, mUNM.selectPreferredUpstreamType(preferredTypes));
        // Check to see we filed an explicit request.
        assertEquals(1, mCM.requested.size());
        NetworkRequest netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
        assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
        assertFalse(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));

        wifiAgent.fakeConnect();
        // WiFi is up, and we should prefer it over cell.
        assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
        assertEquals(0, mCM.requested.size());

        preferredTypes.remove(TYPE_MOBILE_HIPRI);
        preferredTypes.add(TYPE_MOBILE_DUN);
        // This is coupled with preferred types in TetheringConfiguration.
        mUNM.updateMobileRequiresDun(true);
        assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));

        final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
        dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
        dunAgent.fakeConnect();

        // WiFi is still preferred.
        assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));

        // WiFi goes down, cell and DUN are still up but only DUN is preferred.
        wifiAgent.fakeDisconnect();
        assertEquals(TYPE_MOBILE_DUN, mUNM.selectPreferredUpstreamType(preferredTypes));
        // Check to see we filed an explicit request.
        assertEquals(1, mCM.requested.size());
        netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
        assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
        assertTrue(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
    }

    private void assertUpstreamTypeRequested(int upstreamType) throws Exception {
        assertEquals(1, mCM.requested.size());
        assertEquals(1, mCM.legacyTypeMap.size());
@@ -254,6 +326,8 @@ public class UpstreamNetworkMonitorTest {
        public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
        public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();

        private int mNetworkId = 100;

        public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
            super(ctx, svc);
        }
@@ -287,6 +361,8 @@ public class UpstreamNetworkMonitorTest {
            return false;
        }

        int getNetworkId() { return ++mNetworkId; }

        @Override
        public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
            assertFalse(allCallbacks.containsKey(cb));
@@ -360,6 +436,35 @@ public class UpstreamNetworkMonitorTest {
        }
    }

    public static class TestNetworkAgent {
        public final TestConnectivityManager cm;
        public final Network networkId;
        public final int transportType;
        public final NetworkCapabilities networkCapabilities;

        public TestNetworkAgent(TestConnectivityManager cm, int transportType) {
            this.cm = cm;
            this.networkId = new Network(cm.getNetworkId());
            this.transportType = transportType;
            networkCapabilities = new NetworkCapabilities();
            networkCapabilities.addTransportType(transportType);
            networkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
        }

        public void fakeConnect() {
            for (NetworkCallback cb : cm.listening.keySet()) {
                cb.onAvailable(networkId);
                cb.onCapabilitiesChanged(networkId, copy(networkCapabilities));
            }
        }

        public void fakeDisconnect() {
            for (NetworkCallback cb : cm.listening.keySet()) {
                cb.onLost(networkId);
            }
        }
    }

    public static class TestStateMachine extends StateMachine {
        public final ArrayList<Message> messages = new ArrayList<>();
        private final State mLoggingState = new LoggingState();
@@ -382,4 +487,8 @@ public class UpstreamNetworkMonitorTest {
            super.start();
        }
    }

    static NetworkCapabilities copy(NetworkCapabilities nc) {
        return new NetworkCapabilities(nc);
    }
}