Loading services/core/java/com/android/server/connectivity/Tethering.java +105 −63 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private Map<String, TetherInterfaceStateMachine> mIfaces; // all tethered/tetherable ifaces private BroadcastReceiver mStateReceiver; private final BroadcastReceiver mStateReceiver; // {@link ComponentName} of the Service used to run tether provisioning. private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources Loading Loading @@ -163,6 +163,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private boolean mUsbTetherRequested; // true if USB tethering should be started // when RNDIS is enabled // True iff WiFi tethering should be started when soft AP is ready. private boolean mWifiTetherRequested; public Tethering(Context context, INetworkManagementService nmService, INetworkStatsService statsService) { mContext = context; Loading @@ -184,6 +187,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mStateReceiver, filter); Loading Loading @@ -245,29 +249,22 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // Never called directly: only called from interfaceLinkStateChanged. // See NetlinkHandler.cpp:71. if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up); boolean found = false; boolean usb = false; synchronized (mPublicSync) { if (isWifi(iface)) { found = true; } else if (isUsb(iface)) { found = true; usb = true; } else if (isBluetooth(iface)) { found = true; int interfaceType = ifaceNameToType(iface); if (interfaceType == ConnectivityManager.TETHERING_INVALID) { return; } if (found == false) return; TetherInterfaceStateMachine sm = mIfaces.get(iface); if (up) { if (sm == null) { sm = new TetherInterfaceStateMachine(iface, mLooper, usb, sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType, mNMService, mStatsService, this); mIfaces.put(iface, sm); sm.start(); } } else { if (isUsb(iface)) { if (interfaceType == ConnectivityManager.TETHERING_USB) { // ignore usb0 down after enabling RNDIS // we will handle disconnect in interfaceRemoved instead if (VDBG) Log.d(TAG, "ignore interface down for " + iface); Loading @@ -293,7 +290,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } public boolean isWifi(String iface) { private boolean isWifi(String iface) { synchronized (mPublicSync) { for (String regex : mTetherableWifiRegexs) { if (iface.matches(regex)) return true; Loading @@ -302,7 +299,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } public boolean isBluetooth(String iface) { private boolean isBluetooth(String iface) { synchronized (mPublicSync) { for (String regex : mTetherableBluetoothRegexs) { if (iface.matches(regex)) return true; Loading @@ -311,23 +308,23 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } private int ifaceNameToType(String iface) { if (isWifi(iface)) { return ConnectivityManager.TETHERING_WIFI; } else if (isUsb(iface)) { return ConnectivityManager.TETHERING_USB; } else if (isBluetooth(iface)) { return ConnectivityManager.TETHERING_BLUETOOTH; } return ConnectivityManager.TETHERING_INVALID; } @Override public void interfaceAdded(String iface) { if (VDBG) Log.d(TAG, "interfaceAdded " + iface); boolean found = false; boolean usb = false; synchronized (mPublicSync) { if (isWifi(iface)) { found = true; } if (isUsb(iface)) { found = true; usb = true; } if (isBluetooth(iface)) { found = true; } if (found == false) { int interfaceType = ifaceNameToType(iface); if (interfaceType == ConnectivityManager.TETHERING_INVALID) { if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); return; } Loading @@ -337,7 +334,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring"); return; } sm = new TetherInterfaceStateMachine(iface, mLooper, usb, sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType, mNMService, mStatsService, this); mIfaces.put(iface, sm); sm.start(); Loading Loading @@ -412,24 +409,19 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * for the specified interface. */ private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) { boolean isProvisioningRequired = isTetherProvisioningRequired(); boolean isProvisioningRequired = enable && isTetherProvisioningRequired(); int result; switch (type) { case ConnectivityManager.TETHERING_WIFI: final WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); if (wifiManager.setWifiApEnabled(null, enable)) { sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_NO_ERROR); if (enable && isProvisioningRequired) { result = setWifiTethering(enable); if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); } } else{ sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_MASTER_ERROR); } sendTetherResult(receiver, result); break; case ConnectivityManager.TETHERING_USB: int result = setUsbTethering(enable); if (enable && isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { result = setUsbTethering(enable); if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); } sendTetherResult(receiver, result); Loading @@ -449,6 +441,20 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } private int setWifiTethering(final boolean enable) { synchronized (mPublicSync) { // Note that we're maintaining a predicate that mWifiTetherRequested always matches // our last request to WifiManager re: its AP enabled status. mWifiTetherRequested = enable; final WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) { return ConnectivityManager.TETHER_ERROR_NO_ERROR; } return ConnectivityManager.TETHER_ERROR_MASTER_ERROR; } } private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null || !adapter.isEnabled()) { Loading Loading @@ -770,7 +776,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false); // start tethering if we have a request pending if (usbConnected && mRndisEnabled && mUsbTetherRequested) { tetherUsb(true); tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB); } mUsbTetherRequested = false; } Loading @@ -782,31 +788,72 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION"); mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED); } } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { synchronized (Tethering.this.mPublicSync) { if (!mWifiTetherRequested) { // We only care when we're trying to tether via our WiFi interface. return; } int curState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_DISABLED); switch (curState) { case WifiManager.WIFI_AP_STATE_ENABLING: // We can see this state on the way to both enabled and failure states. break; case WifiManager.WIFI_AP_STATE_ENABLED: // Tell an appropriate interface state machine that it should tether. tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI); break; case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_DISABLING: case WifiManager.WIFI_AP_STATE_FAILED: default: if (DBG) { Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + curState); } // Tell an appropriate interface state machine that // it needs to tear itself down. tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_WIFI); setWifiTethering(false); break; } } } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { updateConfiguration(); } } } private void tetherUsb(boolean enable) { if (VDBG) Log.d(TAG, "tetherUsb " + enable); private void tetherMatchingInterfaces(boolean enable, int interfaceType) { if (VDBG) Log.d(TAG, "tetherMatchingInterfaces(" + enable + ", " + interfaceType + ")"); String[] ifaces = new String[0]; String[] ifaces = null; try { ifaces = mNMService.listInterfaces(); } catch (Exception e) { Log.e(TAG, "Error listing Interfaces", e); return; } String chosenIface = null; if (ifaces != null) { for (String iface : ifaces) { if (isUsb(iface)) { int result = (enable ? tether(iface) : untether(iface)); if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { return; if (ifaceNameToType(iface) == interfaceType) { chosenIface = iface; break; } } } Log.e(TAG, "unable start or stop USB tethering"); if (chosenIface == null) { Log.e(TAG, "could not find iface of type " + interfaceType); return; } int result = (enable ? tether(chosenIface) : untether(chosenIface)); if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) { Log.e(TAG, "unable start or stop tethering on iface " + chosenIface); return; } } // TODO - return copies so people can't tamper Loading @@ -831,7 +878,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (mRndisEnabled) { final long ident = Binder.clearCallingIdentity(); try { tetherUsb(true); tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -842,7 +889,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } else { final long ident = Binder.clearCallingIdentity(); try { tetherUsb(false); tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_USB); } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -1410,15 +1457,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering for (String iface : ifaces) { TetherInterfaceStateMachine sm = mIfaces.get(iface); if (sm != null && sm.isTethered()) { if (isUsb(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_USB)); } else if (isWifi(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_WIFI)); } else if (isBluetooth(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_BLUETOOTH)); int interfaceType = ifaceNameToType(iface); if (interfaceType != ConnectivityManager.TETHERING_INVALID) { tethered.add(new Integer(interfaceType)); } } } Loading services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +30 −19 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ import java.net.InetAddress; public class TetherInterfaceStateMachine extends StateMachine { private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; private static final int USB_PREFIX_LENGTH = 24; private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; private final static String TAG = "TetherInterfaceSM"; private final static boolean DBG = false; Loading Loading @@ -81,13 +83,13 @@ public class TetherInterfaceStateMachine extends StateMachine { private final INetworkStatsService mStatsService; private final IControlsTethering mTetherController; private final boolean mUsb; private final String mIfaceName; private final int mInterfaceType; private int mLastError; private String mMyUpstreamIfaceName; // may change over time public TetherInterfaceStateMachine(String ifaceName, Looper looper, boolean usb, public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, INetworkManagementService nMService, INetworkStatsService statsService, IControlsTethering tetherController) { super(ifaceName, looper); Loading @@ -95,7 +97,7 @@ public class TetherInterfaceStateMachine extends StateMachine { mStatsService = statsService; mTetherController = tetherController; mIfaceName = ifaceName; mUsb = usb; mInterfaceType = interfaceType; setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR); mInitialState = new InitialState(); Loading Loading @@ -143,25 +145,38 @@ public class TetherInterfaceStateMachine extends StateMachine { } // configured when we start tethering and unconfig'd on error or conclusion private boolean configureUsbIface(boolean enabled, String iface) { if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")"); private boolean configureIfaceIp(boolean enabled) { if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")"); String ipAsString = null; int prefixLen = 0; if (mInterfaceType == ConnectivityManager.TETHERING_USB) { ipAsString = USB_NEAR_IFACE_ADDR; prefixLen = USB_PREFIX_LENGTH; } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { ipAsString = WIFI_HOST_IFACE_ADDR; prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; } else { // Nothing to do, BT does this elsewhere. return true; } InterfaceConfiguration ifcg = null; try { ifcg = mNMService.getInterfaceConfig(iface); ifcg = mNMService.getInterfaceConfig(mIfaceName); if (ifcg != null) { InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR); ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH)); InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString); ifcg.setLinkAddress(new LinkAddress(addr, prefixLen)); if (enabled) { ifcg.setInterfaceUp(); } else { ifcg.setInterfaceDown(); } ifcg.clearFlag("running"); mNMService.setInterfaceConfig(iface, ifcg); mNMService.setInterfaceConfig(mIfaceName, ifcg); } } catch (Exception e) { Log.e(TAG, "Error configuring interface " + iface, e); Log.e(TAG, "Error configuring interface " + mIfaceName, e); return false; } Loading Loading @@ -205,13 +220,11 @@ public class TetherInterfaceStateMachine extends StateMachine { class TetheredState extends State { @Override public void enter() { if (mUsb) { if (!configureUsbIface(true, mIfaceName)) { if (!configureIfaceIp(true)) { setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR); transitionTo(mInitialState); return; } } try { mNMService.tetherInterface(mIfaceName); Loading Loading @@ -242,9 +255,7 @@ public class TetherInterfaceStateMachine extends StateMachine { Log.e(TAG, "Failed to untether interface: " + ee.toString()); } if (mUsb) { configureUsbIface(false, mIfaceName); } configureIfaceIp(false); } private void cleanupUpstream() { Loading services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java +18 −17 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.os.INetworkManagementService; Loading Loading @@ -56,8 +57,8 @@ public class TetherInterfaceStateMachineTest { private final TestLooper mLooper = new TestLooper(); private TetherInterfaceStateMachine mTestedSm; private void initStateMachine(boolean isUsb) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), isUsb, private void initStateMachine(int interfaceType) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType, mNMService, mStatsService, mTetherHelper); mTestedSm.start(); // Starting the state machine always puts us in a consistent state and notifies Loading @@ -67,8 +68,8 @@ public class TetherInterfaceStateMachineTest { when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); } private void initTetheredStateMachine(boolean isUsb, String upstreamIface) throws Exception { initStateMachine(isUsb); private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception { initStateMachine(interfaceType); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); if (upstreamIface != null) { dispatchTetherConnectionChanged(upstreamIface); Loading @@ -84,8 +85,8 @@ public class TetherInterfaceStateMachineTest { @Test public void startsOutAvailable() { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), false, mNMService, mStatsService, mTetherHelper); mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper); mTestedSm.start(); mLooper.dispatchAll(); assertTrue("Should start out available for tethering", mTestedSm.isAvailable()); Loading @@ -97,7 +98,7 @@ public class TetherInterfaceStateMachineTest { @Test public void shouldDoNothingUntilRequested() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); final int [] NOOP_COMMANDS = { TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED, TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR, Loading @@ -117,7 +118,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesImmediateInterfaceDown() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); verify(mTetherHelper).sendTetherStateChangedBroadcast(); verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); Loading @@ -129,7 +130,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canBeTethered() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); InOrder inOrder = inOrder(mTetherHelper, mNMService); inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(true, mTestedSm); Loading @@ -144,7 +145,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canUnrequestTethering() throws Exception { initTetheredStateMachine(false, null); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); Loading @@ -159,7 +160,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canBeTetheredAsUsb() throws Exception { initStateMachine(true); initStateMachine(ConnectivityManager.TETHERING_USB); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); InOrder inOrder = inOrder(mTetherHelper, mNMService); Loading @@ -177,7 +178,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesFirstUpstreamChange() throws Exception { initTetheredStateMachine(false, null); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null); // Telling the state machine about its upstream interface triggers a little more configuration. dispatchTetherConnectionChanged(UPSTREAM_IFACE); Loading @@ -192,7 +193,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesChangingUpstream() throws Exception { initTetheredStateMachine(false, UPSTREAM_IFACE); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); InOrder inOrder = inOrder(mNMService, mStatsService); Loading @@ -209,7 +210,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canUnrequestTetheringWithUpstream() throws Exception { initTetheredStateMachine(false, UPSTREAM_IFACE); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); Loading @@ -228,7 +229,7 @@ public class TetherInterfaceStateMachineTest { @Test public void interfaceDownLeadsToUnavailable() throws Exception { for (boolean shouldThrow : new boolean[]{true, false}) { initTetheredStateMachine(true, null); initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null); if (shouldThrow) { doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); Loading @@ -246,7 +247,7 @@ public class TetherInterfaceStateMachineTest { @Test public void usbShouldBeTornDownOnTetherError() throws Exception { initStateMachine(true); initStateMachine(ConnectivityManager.TETHERING_USB); doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); Loading @@ -263,7 +264,7 @@ public class TetherInterfaceStateMachineTest { @Test public void shouldTearDownUsbOnUpstreamError() throws Exception { initTetheredStateMachine(true, null); initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null); doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); dispatchTetherConnectionChanged(UPSTREAM_IFACE); Loading Loading
services/core/java/com/android/server/connectivity/Tethering.java +105 −63 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private Map<String, TetherInterfaceStateMachine> mIfaces; // all tethered/tetherable ifaces private BroadcastReceiver mStateReceiver; private final BroadcastReceiver mStateReceiver; // {@link ComponentName} of the Service used to run tether provisioning. private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources Loading Loading @@ -163,6 +163,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private boolean mUsbTetherRequested; // true if USB tethering should be started // when RNDIS is enabled // True iff WiFi tethering should be started when soft AP is ready. private boolean mWifiTetherRequested; public Tethering(Context context, INetworkManagementService nmService, INetworkStatsService statsService) { mContext = context; Loading @@ -184,6 +187,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mStateReceiver, filter); Loading Loading @@ -245,29 +249,22 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // Never called directly: only called from interfaceLinkStateChanged. // See NetlinkHandler.cpp:71. if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up); boolean found = false; boolean usb = false; synchronized (mPublicSync) { if (isWifi(iface)) { found = true; } else if (isUsb(iface)) { found = true; usb = true; } else if (isBluetooth(iface)) { found = true; int interfaceType = ifaceNameToType(iface); if (interfaceType == ConnectivityManager.TETHERING_INVALID) { return; } if (found == false) return; TetherInterfaceStateMachine sm = mIfaces.get(iface); if (up) { if (sm == null) { sm = new TetherInterfaceStateMachine(iface, mLooper, usb, sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType, mNMService, mStatsService, this); mIfaces.put(iface, sm); sm.start(); } } else { if (isUsb(iface)) { if (interfaceType == ConnectivityManager.TETHERING_USB) { // ignore usb0 down after enabling RNDIS // we will handle disconnect in interfaceRemoved instead if (VDBG) Log.d(TAG, "ignore interface down for " + iface); Loading @@ -293,7 +290,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } public boolean isWifi(String iface) { private boolean isWifi(String iface) { synchronized (mPublicSync) { for (String regex : mTetherableWifiRegexs) { if (iface.matches(regex)) return true; Loading @@ -302,7 +299,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } public boolean isBluetooth(String iface) { private boolean isBluetooth(String iface) { synchronized (mPublicSync) { for (String regex : mTetherableBluetoothRegexs) { if (iface.matches(regex)) return true; Loading @@ -311,23 +308,23 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } private int ifaceNameToType(String iface) { if (isWifi(iface)) { return ConnectivityManager.TETHERING_WIFI; } else if (isUsb(iface)) { return ConnectivityManager.TETHERING_USB; } else if (isBluetooth(iface)) { return ConnectivityManager.TETHERING_BLUETOOTH; } return ConnectivityManager.TETHERING_INVALID; } @Override public void interfaceAdded(String iface) { if (VDBG) Log.d(TAG, "interfaceAdded " + iface); boolean found = false; boolean usb = false; synchronized (mPublicSync) { if (isWifi(iface)) { found = true; } if (isUsb(iface)) { found = true; usb = true; } if (isBluetooth(iface)) { found = true; } if (found == false) { int interfaceType = ifaceNameToType(iface); if (interfaceType == ConnectivityManager.TETHERING_INVALID) { if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); return; } Loading @@ -337,7 +334,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring"); return; } sm = new TetherInterfaceStateMachine(iface, mLooper, usb, sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType, mNMService, mStatsService, this); mIfaces.put(iface, sm); sm.start(); Loading Loading @@ -412,24 +409,19 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering * for the specified interface. */ private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) { boolean isProvisioningRequired = isTetherProvisioningRequired(); boolean isProvisioningRequired = enable && isTetherProvisioningRequired(); int result; switch (type) { case ConnectivityManager.TETHERING_WIFI: final WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); if (wifiManager.setWifiApEnabled(null, enable)) { sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_NO_ERROR); if (enable && isProvisioningRequired) { result = setWifiTethering(enable); if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); } } else{ sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_MASTER_ERROR); } sendTetherResult(receiver, result); break; case ConnectivityManager.TETHERING_USB: int result = setUsbTethering(enable); if (enable && isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { result = setUsbTethering(enable); if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { scheduleProvisioningRechecks(type); } sendTetherResult(receiver, result); Loading @@ -449,6 +441,20 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } } private int setWifiTethering(final boolean enable) { synchronized (mPublicSync) { // Note that we're maintaining a predicate that mWifiTetherRequested always matches // our last request to WifiManager re: its AP enabled status. mWifiTetherRequested = enable; final WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) { return ConnectivityManager.TETHER_ERROR_NO_ERROR; } return ConnectivityManager.TETHER_ERROR_MASTER_ERROR; } } private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null || !adapter.isEnabled()) { Loading Loading @@ -770,7 +776,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false); // start tethering if we have a request pending if (usbConnected && mRndisEnabled && mUsbTetherRequested) { tetherUsb(true); tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB); } mUsbTetherRequested = false; } Loading @@ -782,31 +788,72 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION"); mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED); } } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { synchronized (Tethering.this.mPublicSync) { if (!mWifiTetherRequested) { // We only care when we're trying to tether via our WiFi interface. return; } int curState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_DISABLED); switch (curState) { case WifiManager.WIFI_AP_STATE_ENABLING: // We can see this state on the way to both enabled and failure states. break; case WifiManager.WIFI_AP_STATE_ENABLED: // Tell an appropriate interface state machine that it should tether. tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI); break; case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_DISABLING: case WifiManager.WIFI_AP_STATE_FAILED: default: if (DBG) { Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + curState); } // Tell an appropriate interface state machine that // it needs to tear itself down. tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_WIFI); setWifiTethering(false); break; } } } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { updateConfiguration(); } } } private void tetherUsb(boolean enable) { if (VDBG) Log.d(TAG, "tetherUsb " + enable); private void tetherMatchingInterfaces(boolean enable, int interfaceType) { if (VDBG) Log.d(TAG, "tetherMatchingInterfaces(" + enable + ", " + interfaceType + ")"); String[] ifaces = new String[0]; String[] ifaces = null; try { ifaces = mNMService.listInterfaces(); } catch (Exception e) { Log.e(TAG, "Error listing Interfaces", e); return; } String chosenIface = null; if (ifaces != null) { for (String iface : ifaces) { if (isUsb(iface)) { int result = (enable ? tether(iface) : untether(iface)); if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { return; if (ifaceNameToType(iface) == interfaceType) { chosenIface = iface; break; } } } Log.e(TAG, "unable start or stop USB tethering"); if (chosenIface == null) { Log.e(TAG, "could not find iface of type " + interfaceType); return; } int result = (enable ? tether(chosenIface) : untether(chosenIface)); if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) { Log.e(TAG, "unable start or stop tethering on iface " + chosenIface); return; } } // TODO - return copies so people can't tamper Loading @@ -831,7 +878,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering if (mRndisEnabled) { final long ident = Binder.clearCallingIdentity(); try { tetherUsb(true); tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -842,7 +889,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering } else { final long ident = Binder.clearCallingIdentity(); try { tetherUsb(false); tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_USB); } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -1410,15 +1457,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering for (String iface : ifaces) { TetherInterfaceStateMachine sm = mIfaces.get(iface); if (sm != null && sm.isTethered()) { if (isUsb(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_USB)); } else if (isWifi(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_WIFI)); } else if (isBluetooth(iface)) { tethered.add(new Integer( ConnectivityManager.TETHERING_BLUETOOTH)); int interfaceType = ifaceNameToType(iface); if (interfaceType != ConnectivityManager.TETHERING_INVALID) { tethered.add(new Integer(interfaceType)); } } } Loading
services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +30 −19 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ import java.net.InetAddress; public class TetherInterfaceStateMachine extends StateMachine { private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; private static final int USB_PREFIX_LENGTH = 24; private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; private final static String TAG = "TetherInterfaceSM"; private final static boolean DBG = false; Loading Loading @@ -81,13 +83,13 @@ public class TetherInterfaceStateMachine extends StateMachine { private final INetworkStatsService mStatsService; private final IControlsTethering mTetherController; private final boolean mUsb; private final String mIfaceName; private final int mInterfaceType; private int mLastError; private String mMyUpstreamIfaceName; // may change over time public TetherInterfaceStateMachine(String ifaceName, Looper looper, boolean usb, public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, INetworkManagementService nMService, INetworkStatsService statsService, IControlsTethering tetherController) { super(ifaceName, looper); Loading @@ -95,7 +97,7 @@ public class TetherInterfaceStateMachine extends StateMachine { mStatsService = statsService; mTetherController = tetherController; mIfaceName = ifaceName; mUsb = usb; mInterfaceType = interfaceType; setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR); mInitialState = new InitialState(); Loading Loading @@ -143,25 +145,38 @@ public class TetherInterfaceStateMachine extends StateMachine { } // configured when we start tethering and unconfig'd on error or conclusion private boolean configureUsbIface(boolean enabled, String iface) { if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")"); private boolean configureIfaceIp(boolean enabled) { if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")"); String ipAsString = null; int prefixLen = 0; if (mInterfaceType == ConnectivityManager.TETHERING_USB) { ipAsString = USB_NEAR_IFACE_ADDR; prefixLen = USB_PREFIX_LENGTH; } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { ipAsString = WIFI_HOST_IFACE_ADDR; prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; } else { // Nothing to do, BT does this elsewhere. return true; } InterfaceConfiguration ifcg = null; try { ifcg = mNMService.getInterfaceConfig(iface); ifcg = mNMService.getInterfaceConfig(mIfaceName); if (ifcg != null) { InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR); ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH)); InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString); ifcg.setLinkAddress(new LinkAddress(addr, prefixLen)); if (enabled) { ifcg.setInterfaceUp(); } else { ifcg.setInterfaceDown(); } ifcg.clearFlag("running"); mNMService.setInterfaceConfig(iface, ifcg); mNMService.setInterfaceConfig(mIfaceName, ifcg); } } catch (Exception e) { Log.e(TAG, "Error configuring interface " + iface, e); Log.e(TAG, "Error configuring interface " + mIfaceName, e); return false; } Loading Loading @@ -205,13 +220,11 @@ public class TetherInterfaceStateMachine extends StateMachine { class TetheredState extends State { @Override public void enter() { if (mUsb) { if (!configureUsbIface(true, mIfaceName)) { if (!configureIfaceIp(true)) { setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR); transitionTo(mInitialState); return; } } try { mNMService.tetherInterface(mIfaceName); Loading Loading @@ -242,9 +255,7 @@ public class TetherInterfaceStateMachine extends StateMachine { Log.e(TAG, "Failed to untether interface: " + ee.toString()); } if (mUsb) { configureUsbIface(false, mIfaceName); } configureIfaceIp(false); } private void cleanupUpstream() { Loading
services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java +18 −17 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.os.INetworkManagementService; Loading Loading @@ -56,8 +57,8 @@ public class TetherInterfaceStateMachineTest { private final TestLooper mLooper = new TestLooper(); private TetherInterfaceStateMachine mTestedSm; private void initStateMachine(boolean isUsb) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), isUsb, private void initStateMachine(int interfaceType) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType, mNMService, mStatsService, mTetherHelper); mTestedSm.start(); // Starting the state machine always puts us in a consistent state and notifies Loading @@ -67,8 +68,8 @@ public class TetherInterfaceStateMachineTest { when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); } private void initTetheredStateMachine(boolean isUsb, String upstreamIface) throws Exception { initStateMachine(isUsb); private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception { initStateMachine(interfaceType); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); if (upstreamIface != null) { dispatchTetherConnectionChanged(upstreamIface); Loading @@ -84,8 +85,8 @@ public class TetherInterfaceStateMachineTest { @Test public void startsOutAvailable() { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), false, mNMService, mStatsService, mTetherHelper); mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper); mTestedSm.start(); mLooper.dispatchAll(); assertTrue("Should start out available for tethering", mTestedSm.isAvailable()); Loading @@ -97,7 +98,7 @@ public class TetherInterfaceStateMachineTest { @Test public void shouldDoNothingUntilRequested() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); final int [] NOOP_COMMANDS = { TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED, TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR, Loading @@ -117,7 +118,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesImmediateInterfaceDown() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); verify(mTetherHelper).sendTetherStateChangedBroadcast(); verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); Loading @@ -129,7 +130,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canBeTethered() throws Exception { initStateMachine(false); initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); InOrder inOrder = inOrder(mTetherHelper, mNMService); inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(true, mTestedSm); Loading @@ -144,7 +145,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canUnrequestTethering() throws Exception { initTetheredStateMachine(false, null); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); Loading @@ -159,7 +160,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canBeTetheredAsUsb() throws Exception { initStateMachine(true); initStateMachine(ConnectivityManager.TETHERING_USB); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); InOrder inOrder = inOrder(mTetherHelper, mNMService); Loading @@ -177,7 +178,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesFirstUpstreamChange() throws Exception { initTetheredStateMachine(false, null); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null); // Telling the state machine about its upstream interface triggers a little more configuration. dispatchTetherConnectionChanged(UPSTREAM_IFACE); Loading @@ -192,7 +193,7 @@ public class TetherInterfaceStateMachineTest { @Test public void handlesChangingUpstream() throws Exception { initTetheredStateMachine(false, UPSTREAM_IFACE); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); InOrder inOrder = inOrder(mNMService, mStatsService); Loading @@ -209,7 +210,7 @@ public class TetherInterfaceStateMachineTest { @Test public void canUnrequestTetheringWithUpstream() throws Exception { initTetheredStateMachine(false, UPSTREAM_IFACE); initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); Loading @@ -228,7 +229,7 @@ public class TetherInterfaceStateMachineTest { @Test public void interfaceDownLeadsToUnavailable() throws Exception { for (boolean shouldThrow : new boolean[]{true, false}) { initTetheredStateMachine(true, null); initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null); if (shouldThrow) { doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); Loading @@ -246,7 +247,7 @@ public class TetherInterfaceStateMachineTest { @Test public void usbShouldBeTornDownOnTetherError() throws Exception { initStateMachine(true); initStateMachine(ConnectivityManager.TETHERING_USB); doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED); Loading @@ -263,7 +264,7 @@ public class TetherInterfaceStateMachineTest { @Test public void shouldTearDownUsbOnUpstreamError() throws Exception { initTetheredStateMachine(true, null); initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null); doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); dispatchTetherConnectionChanged(UPSTREAM_IFACE); Loading