Loading core/java/android/net/ConnectivityManager.java +11 −3 Original line number Diff line number Diff line Loading @@ -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). Loading @@ -318,12 +319,19 @@ public class ConnectivityManager { */ public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; /** * @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 Loading services/core/java/com/android/server/connectivity/Tethering.java +24 −18 Original line number Diff line number Diff line Loading @@ -623,9 +623,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private void sendTetherStateChangedBroadcast() { if (!getConnectivityManager().isTetheringSupported()) return; ArrayList<String> availableList = new ArrayList<String>(); ArrayList<String> activeList = new ArrayList<String>(); ArrayList<String> erroredList = new ArrayList<String>(); final ArrayList<String> availableList = new ArrayList<>(); final ArrayList<String> tetherList = new ArrayList<>(); final ArrayList<String> localOnlyList = new ArrayList<>(); final ArrayList<String> erroredList = new ArrayList<>(); boolean wifiTethered = false; boolean usbTethered = false; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1534,6 +1538,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } return retValue; } void notify(int msgType) { mErrorNotification = msgType; for (TetherInterfaceStateMachine sm : mNotifyList) { Loading @@ -1542,6 +1547,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } class SetIpForwardingEnabledErrorState extends ErrorState { @Override public void enter() { Loading tests/net/java/com/android/server/connectivity/TetheringTest.java +47 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -81,7 +87,9 @@ public class TetheringTest { private final TestLooper mLooper = new TestLooper(); private final String mTestIfname = "test_wlan0"; private Vector<Intent> mIntents; private BroadcastInterceptingContext mServiceContext; private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; private class MockContext extends BroadcastInterceptingContext { Loading @@ -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]); Loading @@ -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( Loading Loading @@ -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<String> ifnames = bcast.getStringArrayListExtra(whichExtra); assertTrue(ifnames.contains(ifname)); mIntents.remove(bcast); } @Test public void workingLocalOnlyHotspot() throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); Loading @@ -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( Loading Loading @@ -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( Loading Loading
core/java/android/net/ConnectivityManager.java +11 −3 Original line number Diff line number Diff line Loading @@ -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). Loading @@ -318,12 +319,19 @@ public class ConnectivityManager { */ public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; /** * @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 Loading
services/core/java/com/android/server/connectivity/Tethering.java +24 −18 Original line number Diff line number Diff line Loading @@ -623,9 +623,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private void sendTetherStateChangedBroadcast() { if (!getConnectivityManager().isTetheringSupported()) return; ArrayList<String> availableList = new ArrayList<String>(); ArrayList<String> activeList = new ArrayList<String>(); ArrayList<String> erroredList = new ArrayList<String>(); final ArrayList<String> availableList = new ArrayList<>(); final ArrayList<String> tetherList = new ArrayList<>(); final ArrayList<String> localOnlyList = new ArrayList<>(); final ArrayList<String> erroredList = new ArrayList<>(); boolean wifiTethered = false; boolean usbTethered = false; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1534,6 +1538,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } return retValue; } void notify(int msgType) { mErrorNotification = msgType; for (TetherInterfaceStateMachine sm : mNotifyList) { Loading @@ -1542,6 +1547,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } class SetIpForwardingEnabledErrorState extends ErrorState { @Override public void enter() { Loading
tests/net/java/com/android/server/connectivity/TetheringTest.java +47 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -81,7 +87,9 @@ public class TetheringTest { private final TestLooper mLooper = new TestLooper(); private final String mTestIfname = "test_wlan0"; private Vector<Intent> mIntents; private BroadcastInterceptingContext mServiceContext; private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; private class MockContext extends BroadcastInterceptingContext { Loading @@ -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]); Loading @@ -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( Loading Loading @@ -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<String> ifnames = bcast.getStringArrayListExtra(whichExtra); assertTrue(ifnames.contains(ifname)); mIntents.remove(bcast); } @Test public void workingLocalOnlyHotspot() throws Exception { when(mConnectivityManager.isTetheringSupported()).thenReturn(true); Loading @@ -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( Loading Loading @@ -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( Loading