From 8351faa900acdba1022f03bb3f18e26f539eadae Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Mon, 17 Apr 2017 16:47:23 +0900 Subject: [PATCH] Add local-only hotspot info into tether state change broadcast Test: as follows - build - flashed - booted - "runtest frameworks-net" passes - manually starting tethering shows Settings and icon updates Bug: 31466854 Bug: 32163131 Change-Id: I938074587dfeec221c5cdb43a392802ad3fc3589 --- core/java/android/net/ConnectivityManager.java | 14 ++++-- .../com/android/server/connectivity/Tethering.java | 42 +++++++++------- .../android/server/connectivity/TetheringTest.java | 58 ++++++++++++++++++---- 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 739b9dc60e53..ac42be9e0de5 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -301,7 +301,8 @@ public class ConnectivityManager { /** * Broadcast Action: A tetherable connection has come or gone. * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER}, - * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and + * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY}, + * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate * the current state of tethering. Each include a list of * interface names in that state (may be empty). @@ -320,10 +321,17 @@ public class ConnectivityManager { /** * @hide + * gives a String[] listing all the interfaces currently in local-only + * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) + */ + public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + + /** + * @hide * gives a String[] listing all the interfaces currently tethered - * (ie, has dhcp support and packets potentially forwarded/NATed) + * (ie, has DHCPv4 support and packets potentially forwarded/NATed) */ - public static final String EXTRA_ACTIVE_TETHER = "activeArray"; + public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; /** * @hide diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 460d5f9f1db8..a8cd06899bc2 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -623,9 +623,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private void sendTetherStateChangedBroadcast() { if (!getConnectivityManager().isTetheringSupported()) return; - ArrayList availableList = new ArrayList(); - ArrayList activeList = new ArrayList(); - ArrayList erroredList = new ArrayList(); + final ArrayList availableList = new ArrayList<>(); + final ArrayList tetherList = new ArrayList<>(); + final ArrayList localOnlyList = new ArrayList<>(); + final ArrayList erroredList = new ArrayList<>(); boolean wifiTethered = false; boolean usbTethered = false; @@ -641,6 +642,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering erroredList.add(iface); } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) { availableList.add(iface); + } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_HOTSPOT) { + localOnlyList.add(iface); } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) { if (cfg.isUsb(iface)) { usbTethered = true; @@ -649,25 +652,25 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } else if (cfg.isBluetooth(iface)) { bluetoothTethered = true; } - activeList.add(iface); + tetherList.add(iface); } } } - Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); - broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | + final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); + bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, - availableList); - broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList); - broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, - erroredList); - mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); + bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList); + bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList); + bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList); + bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList); + mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL); if (DBG) { Log.d(TAG, String.format( - "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]", - TextUtils.join(",", availableList), - TextUtils.join(",", activeList), - TextUtils.join(",", erroredList))); + "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]", + "avail", TextUtils.join(",", availableList), + "local_only", TextUtils.join(",", localOnlyList), + "tether", TextUtils.join(",", tetherList), + "error", TextUtils.join(",", erroredList))); } if (usbTethered) { @@ -1338,7 +1341,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mForwardedDownstreams.remove(who); } - class InitialState extends TetherMasterUtilState { + class InitialState extends State { @Override public boolean processMessage(Message message) { maybeLogMessage(this, message.what); @@ -1516,7 +1519,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } class ErrorState extends State { - int mErrorNotification; + private int mErrorNotification; + @Override public boolean processMessage(Message message) { boolean retValue = true; @@ -1534,6 +1538,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } return retValue; } + void notify(int msgType) { mErrorNotification = msgType; for (TetherInterfaceStateMachine sm : mNotifyList) { @@ -1542,6 +1547,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } + class SetIpForwardingEnabledErrorState extends ErrorState { @Override public void enter() { diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index e527d57f7367..47630e28b372 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -29,9 +29,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; @@ -53,12 +55,16 @@ import android.telephony.CarrierConfigManager; import com.android.internal.util.test.BroadcastInterceptingContext; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Vector; + @RunWith(AndroidJUnit4.class) @SmallTest public class TetheringTest { @@ -81,7 +87,9 @@ public class TetheringTest { private final TestLooper mLooper = new TestLooper(); private final String mTestIfname = "test_wlan0"; + private Vector mIntents; private BroadcastInterceptingContext mServiceContext; + private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; private class MockContext extends BroadcastInterceptingContext { @@ -100,7 +108,8 @@ public class TetheringTest { } } - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); @@ -118,10 +127,24 @@ public class TetheringTest { .thenReturn(new InterfaceConfiguration()); mServiceContext = new MockContext(mContext); + mIntents = new Vector<>(); + mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mIntents.addElement(intent); + } + }; + mServiceContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager, mLooper.getLooper(), mSystemProperties); } + @After + public void tearDown() { + mServiceContext.unregisterReceiver(mBroadcastReceiver); + } + private void setupForRequiredProvisioning() { // Produce some acceptable looking provision app setting if requested. when(mResources.getStringArray( @@ -180,6 +203,23 @@ public class TetheringTest { mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } + private void verifyInterfaceServingModeStarted() throws Exception { + verify(mNMService, times(1)).listInterfaces(); + verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); + verify(mNMService, times(1)) + .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); + verify(mNMService, times(1)).tetherInterface(mTestIfname); + } + + private void verifyTetheringBroadcast(String ifname, String whichExtra) { + // Verify that ifname is in the whichExtra array of the tether state changed broadcast. + final Intent bcast = mIntents.get(0); + assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction()); + final ArrayList ifnames = bcast.getStringArrayListExtra(whichExtra); + assertTrue(ifnames.contains(ifname)); + mIntents.remove(bcast); + } + @Test public void workingLocalOnlyHotspot() throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); @@ -193,14 +233,12 @@ public class TetheringTest { sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED); mLooper.dispatchAll(); - verify(mNMService, times(1)).listInterfaces(); - verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); - verify(mNMService, times(1)) - .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).tetherInterface(mTestIfname); + verifyInterfaceServingModeStarted(); + verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER); verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); + verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY); // UpstreamNetworkMonitor will be started, and will register two callbacks: // a "listen all" and a "track default". verify(mConnectivityManager, times(1)).registerNetworkCallback( @@ -252,14 +290,12 @@ public class TetheringTest { sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED); mLooper.dispatchAll(); - verify(mNMService, times(1)).listInterfaces(); - verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); - verify(mNMService, times(1)) - .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).tetherInterface(mTestIfname); + verifyInterfaceServingModeStarted(); + verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER); verify(mNMService, times(1)).setIpForwardingEnabled(true); verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); + verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER); // UpstreamNetworkMonitor will be started, and will register two callbacks: // a "listen all" and a "track default". verify(mConnectivityManager, times(1)).registerNetworkCallback( -- 2.11.0