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

Commit 35c89886 authored by Erik Kline's avatar Erik Kline Committed by Gerrit Code Review
Browse files

Merge "Update UpstreamNetworkMonitor to use custom Handlers"

parents 9017b256 b583b036
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -2923,15 +2923,6 @@ public class ConnectivityManager {
     * @hide
     */
    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
            int timeoutMs, int legacyType) {
        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
    }

    /**
     * Helper function to request a network with a particular legacy type.
     * @hide
     */
    private void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
            int timeoutMs, int legacyType, Handler handler) {
        CallbackHandler cbHandler = new CallbackHandler(handler);
        NetworkCapabilities nc = request.networkCapabilities;
@@ -3033,7 +3024,7 @@ public class ConnectivityManager {
    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
            int timeoutMs) {
        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
        requestNetwork(request, networkCallback, timeoutMs, legacyType);
        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
    }


+37 −15
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
@@ -72,6 +74,7 @@ public class UpstreamNetworkMonitor {

    private final Context mContext;
    private final StateMachine mTarget;
    private final Handler mHandler;
    private final int mWhat;
    private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
    private ConnectivityManager mCM;
@@ -84,6 +87,7 @@ public class UpstreamNetworkMonitor {
    public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
        mContext = ctx;
        mTarget = tgt;
        mHandler = mTarget.getHandler();
        mWhat = what;
    }

@@ -99,10 +103,10 @@ public class UpstreamNetworkMonitor {
        final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
                .clearCapabilities().build();
        mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);

        mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
    }

    public void stop() {
@@ -154,7 +158,7 @@ public class UpstreamNetworkMonitor {
        // Additionally, we log a message to aid in any subsequent debugging.
        Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);

        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType);
        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
    }

    public void releaseMobileNetworkRequest() {
@@ -185,11 +189,13 @@ public class UpstreamNetworkMonitor {
            case CALLBACK_TRACK_DEFAULT:
                if (mDefaultNetworkCallback == null) {
                    // The callback was unregistered in the interval between
                    // ConnectivityService calling onAvailable() and our
                    // handling of it here on the mTarget.getHandler() thread.
                    // ConnectivityService enqueueing onAvailable() and our
                    // handling of it here on the mHandler thread.
                    //
                    // Clean-up of this network entry is deferred to the
                    // handling of onLost() by other callbacks.
                    // TODO: change to Log.wtf() after oag/331764 is merged.
                    //
                    // These request*() calls can be deleted post oag/339444.
                    return;
                }

@@ -200,11 +206,13 @@ public class UpstreamNetworkMonitor {
            case CALLBACK_MOBILE_REQUEST:
                if (mMobileNetworkCallback == null) {
                    // The callback was unregistered in the interval between
                    // ConnectivityService calling onAvailable() and our
                    // handling of it here on the mTarget.getHandler() thread.
                    // ConnectivityService enqueueing onAvailable() and our
                    // handling of it here on the mHandler thread.
                    //
                    // Clean-up of this network entry is deferred to the
                    // handling of onLost() by other callbacks.
                    // TODO: change to Log.wtf() after oag/331764 is merged.
                    //
                    // These request*() calls can be deleted post oag/339444.
                    return;
                }

@@ -312,8 +320,9 @@ public class UpstreamNetworkMonitor {
    }

    /**
     * A NetworkCallback class that relays information of interest to the
     * tethering master state machine thread for subsequent processing.
     * A NetworkCallback class that handles information of interest directly
     * in the thread on which it is invoked. To avoid locking, this MUST be
     * run on the same thread as the target state machine's handler.
     */
    private class UpstreamNetworkCallback extends NetworkCallback {
        private final int mCallbackType;
@@ -324,22 +333,35 @@ public class UpstreamNetworkMonitor {

        @Override
        public void onAvailable(Network network) {
            mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
            checkExpectedThread();
            handleAvailable(mCallbackType, network);
        }

        @Override
        public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
            mTarget.getHandler().post(() -> handleNetCap(network, newNc));
            checkExpectedThread();
            handleNetCap(network, newNc);
        }

        @Override
        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
            mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
            checkExpectedThread();
            handleLinkProp(network, newLp);
        }

        // TODO: Handle onNetworkSuspended();
        // TODO: Handle onNetworkResumed();

        @Override
        public void onLost(Network network) {
            mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
            checkExpectedThread();
            handleLost(mCallbackType, network);
        }

        private void checkExpectedThread() {
            if (Looper.myLooper() != mHandler.getLooper()) {
                Log.wtf(TAG, "Handling callback in unexpected thread.");
            }
        }
    }

+77 −9
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@ import android.net.NetworkRequest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import com.android.internal.util.State;
import com.android.internal.util.StateMachine;

import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -49,6 +55,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -63,6 +70,7 @@ public class UpstreamNetworkMonitorTest {
    @Mock private Context mContext;
    @Mock private IConnectivityManager mCS;

    private TestStateMachine mSM;
    private TestConnectivityManager mCM;
    private UpstreamNetworkMonitor mUNM;

@@ -72,7 +80,15 @@ public class UpstreamNetworkMonitorTest {
        reset(mCS);

        mCM = spy(new TestConnectivityManager(mContext, mCS));
        mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
        mSM = new TestStateMachine();
        mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
    }

    @After public void tearDown() throws Exception {
        if (mSM != null) {
            mSM.quit();
            mSM = null;
        }
    }

    @Test
@@ -139,15 +155,17 @@ public class UpstreamNetworkMonitorTest {

        mUNM.start();
        verify(mCM, Mockito.times(1)).registerNetworkCallback(
                any(NetworkRequest.class), any(NetworkCallback.class));
        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
                any(NetworkCallback.class), any(Handler.class));
        assertFalse(mUNM.mobileNetworkRequested());
        assertEquals(0, mCM.requested.size());

        mUNM.updateMobileRequiresDun(true);
        mUNM.registerMobileNetworkRequest();
        verify(mCM, Mockito.times(1)).requestNetwork(
                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
                any(Handler.class));

        assertTrue(mUNM.mobileNetworkRequested());
        assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@ public class UpstreamNetworkMonitorTest {
    }

    public static class TestConnectivityManager extends ConnectivityManager {
        public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
        public Set<NetworkCallback> trackingDefault = new HashSet<>();
        public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
        public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@ public class UpstreamNetworkMonitorTest {
        }

        boolean hasNoCallbacks() {
            return trackingDefault.isEmpty() &&
            return allCallbacks.isEmpty() &&
                   trackingDefault.isEmpty() &&
                   listening.isEmpty() &&
                   requested.isEmpty() &&
                   legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@ public class UpstreamNetworkMonitorTest {
        }

        @Override
        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
        public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
            assertFalse(allCallbacks.containsKey(cb));
            allCallbacks.put(cb, h);
            assertFalse(requested.containsKey(cb));
            requested.put(cb, req);
        }

        @Override
        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
            fail("Should never be called.");
        }

        @Override
        public void requestNetwork(NetworkRequest req, NetworkCallback cb,
                int timeoutMs, int legacyType) {
                int timeoutMs, int legacyType, Handler h) {
            assertFalse(allCallbacks.containsKey(cb));
            allCallbacks.put(cb, h);
            assertFalse(requested.containsKey(cb));
            requested.put(cb, req);
            assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,17 +308,31 @@ public class UpstreamNetworkMonitorTest {
        }

        @Override
        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
            assertFalse(allCallbacks.containsKey(cb));
            allCallbacks.put(cb, h);
            assertFalse(listening.containsKey(cb));
            listening.put(cb, req);
        }

        @Override
        public void registerDefaultNetworkCallback(NetworkCallback cb) {
        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
            fail("Should never be called.");
        }

        @Override
        public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
            assertFalse(allCallbacks.containsKey(cb));
            allCallbacks.put(cb, h);
            assertFalse(trackingDefault.contains(cb));
            trackingDefault.add(cb);
        }

        @Override
        public void registerDefaultNetworkCallback(NetworkCallback cb) {
            fail("Should never be called.");
        }

        @Override
        public void unregisterNetworkCallback(NetworkCallback cb) {
            if (trackingDefault.contains(cb)) {
@@ -302,10 +345,35 @@ public class UpstreamNetworkMonitorTest {
            } else {
                fail("Unexpected callback removed");
            }
            allCallbacks.remove(cb);

            assertFalse(allCallbacks.containsKey(cb));
            assertFalse(trackingDefault.contains(cb));
            assertFalse(listening.containsKey(cb));
            assertFalse(requested.containsKey(cb));
        }
    }

    public static class TestStateMachine extends StateMachine {
        public final ArrayList<Message> messages = new ArrayList<>();
        private final State mLoggingState = new LoggingState();

        class LoggingState extends State {
            @Override public void enter() { messages.clear(); }

            @Override public void exit() { messages.clear(); }

            @Override public boolean processMessage(Message msg) {
                messages.add(msg);
                return true;
            }
        }

        public TestStateMachine() {
            super("UpstreamNetworkMonitor.TestStateMachine");
            addState(mLoggingState);
            setInitialState(mLoggingState);
            super.start();
        }
    }
}