From b027e6e92b2003c063de1127cd60acf7c303006e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 1 Mar 2016 22:56:37 +0900 Subject: [PATCH 1/2] Use MessageUtils in ConnectivityManager. Change-Id: I0179b45bc54ffced8e5647d6f005b891b5de93ab --- core/java/android/net/ConnectivityManager.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 7004e9725b..09ea8f9b87 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -45,10 +45,12 @@ import android.provider.Settings; import android.telephony.SubscriptionManager; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseArray; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.Protocol; +import com.android.internal.util.MessageUtils; import libcore.net.event.NetworkEventDispatcher; @@ -79,6 +81,13 @@ import java.util.concurrent.atomic.AtomicInteger; public class ConnectivityManager { private static final String TAG = "ConnectivityManager"; + private static final SparseArray sMagicDecoderRing = MessageUtils.findMessageNames( + new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"}); + + private static final String whatToString(int what) { + return sMagicDecoderRing.get(what, Integer.toString(what)); + } + /** * A change in network connectivity has occurred. A default connection has either * been established or lost. The NetworkInfo for the affected network is @@ -2563,9 +2572,11 @@ public class ConnectivityManager { @Override public void handleMessage(Message message) { - if (DBG) Log.d(TAG, "CM callback handler got msg " + message.what); NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class); Network network = (Network) getObject(message, Network.class); + if (DBG) { + Log.d(TAG, whatToString(message.what) + " for network " + network); + } switch (message.what) { case CALLBACK_PRECHECK: { NetworkCallback callback = getCallback(request, "PRECHECK"); From 4b0c762011d5c1d720c729e76487a31008965d6f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 1 Mar 2016 12:55:58 +0900 Subject: [PATCH 2/2] Move PinningNetworkCallback out to a new NetworkPinner class. Also add tests. Bug: 19159232 Change-Id: Ic366b53259ee5944a8e864876425a6558c0a7216 --- .../server/ConnectivityServiceTest.java | 125 +++++++++++++++++- 1 file changed, 123 insertions(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 587442916d..20a0131dd7 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -67,6 +67,7 @@ import android.util.LogPrinter; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; +import com.android.server.net.NetworkPinner; import java.net.InetAddress; import java.util.concurrent.CountDownLatch; @@ -87,10 +88,30 @@ public class ConnectivityServiceTest extends AndroidTestCase { private BroadcastInterceptingContext mServiceContext; private WrappedConnectivityService mService; - private ConnectivityManager mCm; + private WrappedConnectivityManager mCm; private MockNetworkAgent mWiFiNetworkAgent; private MockNetworkAgent mCellNetworkAgent; + // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods + // do not go through ConnectivityService but talk to netd directly, so they don't automatically + // reflect the state of our test ConnectivityService. + private class WrappedConnectivityManager extends ConnectivityManager { + private Network mFakeBoundNetwork; + + public synchronized boolean bindProcessToNetwork(Network network) { + mFakeBoundNetwork = network; + return true; + } + + public synchronized Network getBoundNetworkForProcess() { + return mFakeBoundNetwork; + } + + public WrappedConnectivityManager(Context context, ConnectivityService service) { + super(context, service); + } + } + private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { super(base); @@ -607,7 +628,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { mock(INetworkPolicyManager.class)); mService.systemReady(); - mCm = new ConnectivityManager(getContext(), mService); + mCm = new WrappedConnectivityManager(getContext(), mService); + mCm.bindProcessToNetwork(null); } private int transportToLegacyType(int transport) { @@ -1543,4 +1565,103 @@ public class ConnectivityServiceTest extends AndroidTestCase { String url = mCm.getCaptivePortalServerUrl(); assertEquals("http://connectivitycheck.gstatic.com/generate_204", url); } + + private static class TestNetworkPinner extends NetworkPinner { + public static boolean awaitPin(int timeoutMs) { + synchronized(sLock) { + if (sNetwork == null) { + try { + sLock.wait(timeoutMs); + } catch (InterruptedException e) {} + } + return sNetwork != null; + } + } + + public static boolean awaitUnpin(int timeoutMs) { + synchronized(sLock) { + if (sNetwork != null) { + try { + sLock.wait(timeoutMs); + } catch (InterruptedException e) {} + } + return sNetwork == null; + } + } + } + + private void assertPinnedToWifiWithCellDefault() { + assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess()); + assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + } + + private void assertPinnedToWifiWithWifiDefault() { + assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess()); + assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + } + + private void assertNotPinnedToWifi() { + assertNull(mCm.getBoundNetworkForProcess()); + assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + } + + @SmallTest + public void testNetworkPinner() { + NetworkRequest wifiRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(); + assertNull(mCm.getBoundNetworkForProcess()); + + TestNetworkPinner.pin(mServiceContext, wifiRequest); + assertNull(mCm.getBoundNetworkForProcess()); + + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + + // When wi-fi connects, expect to be pinned. + assertTrue(TestNetworkPinner.awaitPin(100)); + assertPinnedToWifiWithCellDefault(); + + // Disconnect and expect the pin to drop. + mWiFiNetworkAgent.disconnect(); + assertTrue(TestNetworkPinner.awaitUnpin(100)); + assertNotPinnedToWifi(); + + // Reconnecting does not cause the pin to come back. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + assertFalse(TestNetworkPinner.awaitPin(100)); + assertNotPinnedToWifi(); + + // Pinning while connected causes the pin to take effect immediately. + TestNetworkPinner.pin(mServiceContext, wifiRequest); + assertTrue(TestNetworkPinner.awaitPin(100)); + assertPinnedToWifiWithCellDefault(); + + // Explicitly unpin and expect to use the default network again. + TestNetworkPinner.unpin(); + assertNotPinnedToWifi(); + + // Disconnect cell and wifi. + ConditionVariable cv = waitForConnectivityBroadcasts(3); // cell down, wifi up, wifi down. + mCellNetworkAgent.disconnect(); + mWiFiNetworkAgent.disconnect(); + waitFor(cv); + + // Pinning takes effect even if the pinned network is the default when the pin is set... + TestNetworkPinner.pin(mServiceContext, wifiRequest); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + assertTrue(TestNetworkPinner.awaitPin(100)); + assertPinnedToWifiWithWifiDefault(); + + // ... and is maintained even when that network is no longer the default. + cv = waitForConnectivityBroadcasts(1); + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mCellNetworkAgent.connect(true); + waitFor(cv); + assertPinnedToWifiWithCellDefault(); + } }