From 6a1967c9088b9f05665462efa9d98210143500bd Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 17 Mar 2010 11:19:57 -0700 Subject: [PATCH] Make Tethering not disconnect on every net change. Tethering will now persist to on (until turned off) through upstream net drops, tunnels, switches to wifi or 2G, mms sends, etc. It will also strive to use the most natural connection and only go to HiPri/Dun APNs when needed. bug:2519915 bug:2501837 Change-Id: Iedf6647daad8df507d7c87d1130b204b0a0acc7b --- .../server/connectivity/Tethering.java | 542 ++++++++---------- 1 file changed, 241 insertions(+), 301 deletions(-) diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index ccb5fc6346aaa..fcb39c957049b 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -93,8 +93,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private boolean mDunRequired; // configuration info - must use DUN apn on 3g private boolean mUseHiPri; - private String mUpstreamIfaceName; - private HierarchicalStateMachine mTetherMasterSM; private Notification mTetheredNotification; @@ -189,7 +187,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } else { if (sm != null) { - sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN)); + sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN); mIfaces.remove(iface); } } @@ -247,7 +245,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring"); return; } - sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN)); + sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN); mIfaces.remove(iface); } } @@ -266,7 +264,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring"); return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE; } - sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED)); + sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED); return ConnectivityManager.TETHER_ERROR_NO_ERROR; } @@ -284,7 +282,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring"); return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE; } - sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED)); + sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED); return ConnectivityManager.TETHER_ERROR_NO_ERROR; } @@ -423,20 +421,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mUsbMassStorageOff = true; updateUsbStatus(); } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); - try { - int netType = (mUseHiPri ? ConnectivityManager.TYPE_MOBILE_HIPRI: - ConnectivityManager.TYPE_MOBILE_DUN); - NetworkInfo info = service.getNetworkInfo(netType); - int msg; - if (info != null && info.isConnected() == true) { - msg = TetherMasterSM.CMD_CELL_DUN_ENABLED; - } else { - msg = TetherMasterSM.CMD_CELL_DUN_DISABLED; - } - mTetherMasterSM.sendMessage(mTetherMasterSM.obtainMessage(msg)); - } catch (RemoteException e) {} + Log.d(TAG, "Tethering got CONNECTIVITY_ACTION"); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED); } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { mBooted = true; updateUsbStatus(); @@ -605,32 +591,32 @@ public class Tethering extends INetworkManagementEventObserver.Stub { class TetherInterfaceSM extends HierarchicalStateMachine { - // notification from the master SM that it's in tether mode - static final int CMD_TETHER_MODE_ALIVE = 1; // notification from the master SM that it's not in tether mode - static final int CMD_TETHER_MODE_DEAD = 2; + static final int CMD_TETHER_MODE_DEAD = 1; // request from the user that it wants to tether - static final int CMD_TETHER_REQUESTED = 3; + static final int CMD_TETHER_REQUESTED = 2; // request from the user that it wants to untether - static final int CMD_TETHER_UNREQUESTED = 4; + static final int CMD_TETHER_UNREQUESTED = 3; // notification that this interface is down - static final int CMD_INTERFACE_DOWN = 5; + static final int CMD_INTERFACE_DOWN = 4; // notification that this interface is up - static final int CMD_INTERFACE_UP = 6; + static final int CMD_INTERFACE_UP = 5; // notification from the master SM that it had an error turning on cellular dun - static final int CMD_CELL_DUN_ERROR = 10; + static final int CMD_CELL_DUN_ERROR = 6; // notification from the master SM that it had trouble enabling IP Forwarding - static final int CMD_IP_FORWARDING_ENABLE_ERROR = 11; + static final int CMD_IP_FORWARDING_ENABLE_ERROR = 7; // notification from the master SM that it had trouble disabling IP Forwarding - static final int CMD_IP_FORWARDING_DISABLE_ERROR = 12; + static final int CMD_IP_FORWARDING_DISABLE_ERROR = 8; // notification from the master SM that it had trouble staring tethering - static final int CMD_START_TETHERING_ERROR = 13; + static final int CMD_START_TETHERING_ERROR = 9; // notification from the master SM that it had trouble stopping tethering - static final int CMD_STOP_TETHERING_ERROR = 14; + static final int CMD_STOP_TETHERING_ERROR = 10; // notification from the master SM that it had trouble setting the DNS forwarders - static final int CMD_SET_DNS_FORWARDERS_ERROR = 15; + static final int CMD_SET_DNS_FORWARDERS_ERROR = 11; // a mechanism to transition self to another state from an enter function - static final int CMD_TRANSITION_TO_STATE = 16; + static final int CMD_TRANSITION_TO_STATE = 12; + // the upstream connection has changed + static final int CMD_TETHER_CONNECTION_CHANGED = 13; private HierarchicalState mDefaultState; @@ -645,6 +631,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { int mLastError; String mIfaceName; + String mMyUpstreamIfaceName; // may change over time + boolean mUsb; TetherInterfaceSM(String name, Looper looper, boolean usb) { @@ -733,10 +721,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { switch (message.what) { case CMD_TETHER_REQUESTED: setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR); - Message m = mTetherMasterSM.obtainMessage( - TetherMasterSM.CMD_TETHER_MODE_REQUESTED); - m.obj = TetherInterfaceSM.this; - mTetherMasterSM.sendMessage(m); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED, + TetherInterfaceSM.this); transitionTo(mStartingState); break; case CMD_INTERFACE_DOWN: @@ -756,20 +742,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub { setAvailable(false); if (mUsb) { if (!Tethering.this.configureUsbIface(true)) { - Message m = mTetherMasterSM.obtainMessage( - TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED); - m.obj = TetherInterfaceSM.this; - mTetherMasterSM.sendMessage(m); - + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, + TetherInterfaceSM.this); setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR); - m = obtainMessage(CMD_TRANSITION_TO_STATE); - m.obj = mInitialState; - sendMessageAtFrontOfQueue(m); + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mInitialState); return; } } sendTetherStateChangedBroadcast(); + + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mTetheredState); } @Override public boolean processMessage(Message message) { @@ -778,10 +761,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { switch (message.what) { // maybe a parent class? case CMD_TETHER_UNREQUESTED: - Message m = mTetherMasterSM.obtainMessage( - TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED); - m.obj = TetherInterfaceSM.this; - mTetherMasterSM.sendMessage(m); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, + TetherInterfaceSM.this); if (mUsb) { if (!Tethering.this.configureUsbIface(false)) { setLastErrorAndTransitionToInitialState( @@ -791,9 +772,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } transitionTo(mInitialState); break; - case CMD_TETHER_MODE_ALIVE: - transitionTo(mTetheredState); - break; case CMD_CELL_DUN_ERROR: case CMD_IP_FORWARDING_ENABLE_ERROR: case CMD_IP_FORWARDING_DISABLE_ERROR: @@ -804,10 +782,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { ConnectivityManager.TETHER_ERROR_MASTER_ERROR); break; case CMD_INTERFACE_DOWN: - m = mTetherMasterSM.obtainMessage( - TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED); - m.obj = TetherInterfaceSM.this; - mTetherMasterSM.sendMessage(m); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, + TetherInterfaceSM.this); transitionTo(mUnavailableState); break; case CMD_TRANSITION_TO_STATE: @@ -832,23 +808,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } catch (Exception e) { setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR); - Message m = obtainMessage(CMD_TRANSITION_TO_STATE); - m.obj = mInitialState; - sendMessageAtFrontOfQueue(m); - return; - } - try { - service.enableNat(mIfaceName, mUpstreamIfaceName); - } catch (Exception e) { - try { - service.untetherInterface(mIfaceName); - } catch (Exception ee) {} - - setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR); - - Message m = obtainMessage(CMD_TRANSITION_TO_STATE); - m.obj = mInitialState; - sendMessageAtFrontOfQueue(m); + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mInitialState); return; } if (mUsb) Tethering.this.enableUsbRndis(true); @@ -872,16 +832,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); - try { - service.disableNat(mIfaceName, mUpstreamIfaceName); - } catch (Exception e) { + if (mMyUpstreamIfaceName != null) { try { - service.untetherInterface(mIfaceName); - } catch (Exception ee) {} + service.disableNat(mIfaceName, mMyUpstreamIfaceName); + } catch (Exception e) { + try { + service.untetherInterface(mIfaceName); + } catch (Exception ee) {} - setLastErrorAndTransitionToInitialState( - ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR); - break; + setLastErrorAndTransitionToInitialState( + ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR); + break; + } } try { service.untetherInterface(mIfaceName); @@ -890,10 +852,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR); break; } - Message m = mTetherMasterSM.obtainMessage( - TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED); - m.obj = TetherInterfaceSM.this; - mTetherMasterSM.sendMessage(m); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, + TetherInterfaceSM.this); if (message.what == CMD_TETHER_UNREQUESTED) { if (mUsb) { if (!Tethering.this.configureUsbIface(false)) { @@ -907,6 +867,39 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } Log.d(TAG, "Untethered " + mIfaceName); break; + case CMD_TETHER_CONNECTION_CHANGED: + String newUpstreamIfaceName = (String)(message.obj); + b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + service = INetworkManagementService.Stub.asInterface(b); + + if (mMyUpstreamIfaceName != null) { + try { + service.disableNat(mIfaceName, mMyUpstreamIfaceName); + } catch (Exception e) { + try { + service.untetherInterface(mIfaceName); + } catch (Exception ee) {} + + setLastErrorAndTransitionToInitialState( + ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR); + break; + } + } + if (newUpstreamIfaceName != null) { + try { + service.enableNat(mIfaceName, newUpstreamIfaceName); + } catch (Exception e) { + try { + service.untetherInterface(mIfaceName); + } catch (Exception ee) {} + + setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR); + transitionTo(mInitialState); + return true; + } + } + mMyUpstreamIfaceName = newUpstreamIfaceName; + break; case CMD_CELL_DUN_ERROR: case CMD_IP_FORWARDING_ENABLE_ERROR: case CMD_IP_FORWARDING_DISABLE_ERROR: @@ -918,16 +911,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub { case CMD_TETHER_MODE_DEAD: b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); service = INetworkManagementService.Stub.asInterface(b); - try { - service.disableNat(mIfaceName, mUpstreamIfaceName); - } catch (Exception e) { + if (mMyUpstreamIfaceName != null) { try { - service.untetherInterface(mIfaceName); - } catch (Exception ee) {} + service.disableNat(mIfaceName, mMyUpstreamIfaceName); + } catch (Exception e) { + try { + service.untetherInterface(mIfaceName); + } catch (Exception ee) {} - setLastErrorAndTransitionToInitialState( - ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR); - break; + setLastErrorAndTransitionToInitialState( + ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR); + break; + } } try { service.untetherInterface(mIfaceName); @@ -997,14 +992,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub { static final int CMD_TETHER_MODE_REQUESTED = 1; // an interface SM has unrequested Tethering static final int CMD_TETHER_MODE_UNREQUESTED = 2; + // upstream connection change - do the right thing + static final int CMD_UPSTREAM_CHANGED = 3; // we received notice that the cellular DUN connection is up - static final int CMD_CELL_DUN_ENABLED = 3; - // we received notice that the cellular DUN connection is down - static final int CMD_CELL_DUN_DISABLED = 4; - // we timed out on a cellular DUN toggle - static final int CMD_CELL_DUN_TIMEOUT = 5; - // it's time to renew our cellular DUN reservation - static final int CMD_CELL_DUN_RENEW = 6; + static final int CMD_CELL_CONNECTION_RENEW = 4; + // need to do delayed transition from enter/exit + static final int CMD_TRANSITION_TO_STATE = 5; + // we don't have a valid upstream conn, check again after a delay + static final int CMD_RETRY_UPSTREAM = 6; // This indicates what a timeout event relates to. A state that // sends itself a delayed timeout event and handles incoming timeout events @@ -1013,11 +1008,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private int mSequenceNumber; private HierarchicalState mInitialState; - private HierarchicalState mCellDunRequestedState; - private HierarchicalState mCellDunAliveState; private HierarchicalState mTetherModeAliveState; - private HierarchicalState mCellDunErrorState; private HierarchicalState mSetIpForwardingEnabledErrorState; private HierarchicalState mSetIpForwardingDisabledErrorState; private HierarchicalState mStartTetheringErrorState; @@ -1026,10 +1018,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private ArrayList mNotifyList; + private boolean mConnectionRequested = false; - private static final int CELL_DUN_TIMEOUT_MS = 45000; - private static final int CELL_DISABLE_DUN_TIMEOUT_MS = 3000; - private static final int CELL_DUN_RENEW_MS = 40000; + private static final int UPSTREAM_SETTLE_TIME_MS = 10000; + private static final int CELL_CONNECTION_RENEW_MS = 40000; TetherMasterSM(String name, Looper looper) { super(name, looper); @@ -1037,15 +1029,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { //Add states mInitialState = new InitialState(); addState(mInitialState); - mCellDunRequestedState = new CellDunRequestedState(); - addState(mCellDunRequestedState); - mCellDunAliveState = new CellDunAliveState(); - addState(mCellDunAliveState); mTetherModeAliveState = new TetherModeAliveState(); addState(mTetherModeAliveState); - mCellDunErrorState = new CellDunErrorState(); - addState(mCellDunErrorState); mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState(); addState(mSetIpForwardingEnabledErrorState); mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState(); @@ -1058,16 +1044,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub { addState(mSetDnsForwardersErrorState); mNotifyList = new ArrayList(); - setInitialState(mInitialState); } class TetherMasterUtilState extends HierarchicalState { + protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true; + protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false; + @Override public boolean processMessage(Message m) { return false; } - public int turnOnMobileDun() { + protected int turnOnMobileConnection() { + Log.d(TAG, "turnonMobileConnection with mUseHiPri="+mUseHiPri); IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); int retValue = Phone.APN_REQUEST_FAILED; @@ -1077,46 +1066,63 @@ public class Tethering extends INetworkManagementEventObserver.Stub { new Binder()); } catch (Exception e) { } + switch (retValue) { + case Phone.APN_ALREADY_ACTIVE: + case Phone.APN_REQUEST_STARTED: + sendMessageDelayed(CMD_CELL_CONNECTION_RENEW, CELL_CONNECTION_RENEW_MS); + mConnectionRequested = true; + break; + case Phone.APN_REQUEST_FAILED: + default: + mConnectionRequested = false; + break; + } + return retValue; } - public boolean turnOffMobileDun() { - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager service = - IConnectivityManager.Stub.asInterface(b); - try { - service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN)); - } catch (Exception e) { - return false; + protected boolean turnOffMobileConnection() { + if (mConnectionRequested) { + IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); + IConnectivityManager service = + IConnectivityManager.Stub.asInterface(b); + try { + service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : + Phone.FEATURE_ENABLE_DUN)); + } catch (Exception e) { + return false; + } + mConnectionRequested = false; } return true; } - public boolean turnOnMasterTetherSettings() { + protected boolean turnOnMasterTetherSettings() { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); try { service.setIpForwardingEnabled(true); } catch (Exception e) { - transitionTo(mSetIpForwardingEnabledErrorState); + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, + mSetIpForwardingEnabledErrorState); return false; } try { service.startTethering(mDhcpRange[0], mDhcpRange[1]); } catch (Exception e) { - transitionTo(mStartTetheringErrorState); + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, mStartTetheringErrorState); return false; } try { service.setDnsForwarders(mDnsServers); } catch (Exception e) { - transitionTo(mSetDnsForwardersErrorState); + sendMessageAtFrontOfQueue(CMD_TRANSITION_TO_STATE, + mSetDnsForwardersErrorState); return false; } - transitionTo(mTetherModeAliveState); return true; } - public boolean turnOffMasterTetherSettings() { + protected boolean turnOffMasterTetherSettings() { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); @@ -1135,7 +1141,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { transitionTo(mInitialState); return true; } - public String findActiveUpstreamIface() { + protected String findActiveUpstreamIface() { // check for what iface we can use - if none found switch to error. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); @@ -1147,6 +1153,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { Log.e(TAG, "Error listing Interfaces :" + e); return null; } + for (String iface : ifaces) { for (String regex : mUpstreamIfaceRegexs) { if (iface.matches(regex)) { @@ -1167,12 +1174,80 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } return null; } + protected void chooseUpstreamType(boolean tryCell) { + // decide if the current upstream is good or not and if not + // do something about it (start up DUN if required or HiPri if not) + String iface = findActiveUpstreamIface(); + IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); + IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); + mConnectionRequested = false; + mUseHiPri = false; + Log.d(TAG, "chooseUpstreamType(" + tryCell + "), dunRequired =" + + mDunRequired + ", iface=" + iface); + if (mDunRequired) { + // check if Dun is on + try { + NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_DUN); + if (info.isConnected()) { + Log.d(TAG, "setting dun ifacename =" + iface); + notifyTetheredOfNewIface(iface); + // even if we're already connected - it may be somebody else's + // refcount, so add our own + turnOnMobileConnection(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling ConnectivityManager"); + notifyTetheredOfNewIface(null); + } + if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) { + turnOnMobileConnection(); + } + } else { + if (iface == null) { + if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) { + Log.d(TAG, "turning on hipri"); + mUseHiPri = true; + turnOnMobileConnection(); // try to turn on hipri + } + + } else { + try { + Log.d(TAG, "checking if hipri brought us this connection"); + NetworkInfo info = cm.getNetworkInfo( + ConnectivityManager.TYPE_MOBILE_HIPRI); + if (info.isConnected()) { + Log.d(TAG, "yes - hipri in use"); + mUseHiPri = true; + turnOnMobileConnection(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling ConnectivityManager"); + } + // we don't require Dun and have an iface that satisfies, so use it + Log.d(TAG, "setting non-dun iface =" + iface); + notifyTetheredOfNewIface(iface); + } + } + if (iface == null) { + // wait for things to settle and retry + sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS); + } + } + protected void notifyTetheredOfNewIface(String ifaceName) { + Log.d(TAG, "notifying tethered with iface =" + ifaceName); + for (Object o : mNotifyList) { + TetherInterfaceSM sm = (TetherInterfaceSM)o; + sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED, + ifaceName); + } + } } class InitialState extends TetherMasterUtilState { @Override public void enter() { mUseHiPri = false; + mConnectionRequested = false; } @Override public boolean processMessage(Message message) { @@ -1183,7 +1258,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { TetherInterfaceSM who = (TetherInterfaceSM)message.obj; Log.d(TAG, "Tether Mode requested by " + who.toString()); mNotifyList.add(who); - transitionTo(mCellDunRequestedState); + transitionTo(mTetherModeAliveState); break; case CMD_TETHER_MODE_UNREQUESTED: who = (TetherInterfaceSM)message.obj; @@ -1193,130 +1268,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mNotifyList.remove(who); } break; - case CMD_CELL_DUN_ENABLED: - transitionTo(mCellDunAliveState); - break; - default: - retValue = false; - break; - } - return retValue; - } - } - class CellDunRequestedState extends TetherMasterUtilState { - @Override - public void enter() { - mUseHiPri = (findActiveUpstreamIface() == null && !mDunRequired); - if (mDunRequired || mUseHiPri) { - ++mSequenceNumber; - int result = turnOnMobileDun(); - switch (result) { - case Phone.APN_ALREADY_ACTIVE: - Log.d(TAG, "Dun already active"); - sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED)); - break; - case Phone.APN_REQUEST_FAILED: - case Phone.APN_TYPE_NOT_AVAILABLE: - Log.d(TAG, "Error bringing up Dun connection"); - Message m = obtainMessage(CMD_CELL_DUN_TIMEOUT); - m.arg1 = mSequenceNumber; - sendMessage(m); - break; - case Phone.APN_REQUEST_STARTED: - Log.d(TAG, "Started bringing up Dun connection"); - m = obtainMessage(CMD_CELL_DUN_TIMEOUT); - m.arg1 = mSequenceNumber; - sendMessageDelayed(m, CELL_DUN_TIMEOUT_MS); - break; - default: - Log.e(TAG, "Unknown return value from startUsingNetworkFeature " + - result); - } - } else { - Log.d(TAG, "no Dun Required. Skipping to Active"); - sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED)); - } - } - - @Override - public boolean processMessage(Message message) { - Log.d(TAG, "CellDunRequestedState.processMessage what=" + message.what); - boolean retValue = true; - switch (message.what) { - case CMD_TETHER_MODE_REQUESTED: - TetherInterfaceSM who = (TetherInterfaceSM)message.obj; - mNotifyList.add(who); - break; - case CMD_TETHER_MODE_UNREQUESTED: - who = (TetherInterfaceSM)message.obj; - int index = mNotifyList.indexOf(who); - if (index != -1) { - mNotifyList.remove(index); - if (mNotifyList.isEmpty()) { - if (mDunRequired || mUseHiPri) { - turnOffMobileDun(); - } - transitionTo(mInitialState); - } - } - break; - case CMD_CELL_DUN_ENABLED: - turnOnMasterTetherSettings(); - break; - case CMD_CELL_DUN_DISABLED: - break; - case CMD_CELL_DUN_TIMEOUT: - if (message.arg1 == mSequenceNumber) { - transitionTo(mCellDunErrorState); - } - break; - default: - retValue = false; - break; - } - return retValue; - } - } - - class CellDunAliveState extends TetherMasterUtilState { - @Override - public void enter() { - Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms"); - sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS); - } - - @Override - public boolean processMessage(Message message) { - Log.d(TAG, "CellDunAliveState.processMessage what=" + message.what); - boolean retValue = true; - switch (message.what) { - case CMD_TETHER_MODE_REQUESTED: - TetherInterfaceSM who = (TetherInterfaceSM)message.obj; - mNotifyList.add(who); - turnOnMasterTetherSettings(); - break; - case CMD_TETHER_MODE_UNREQUESTED: - who = (TetherInterfaceSM)message.obj; - int index = mNotifyList.indexOf(who); - if (index != -1) { - mNotifyList.remove(index); - if (mNotifyList.isEmpty()) { - if (mDunRequired || mUseHiPri) { - turnOffMobileDun(); - } - transitionTo(mInitialState); - } - } - break; - case CMD_CELL_DUN_DISABLED: - transitionTo(mInitialState); - break; - case CMD_CELL_DUN_RENEW: - Log.d(TAG, "renewing dun connection - requeuing for another " + - CELL_DUN_RENEW_MS + "ms"); - turnOnMobileDun(); - sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS); - break; default: retValue = false; break; @@ -1326,22 +1277,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } class TetherModeAliveState extends TetherMasterUtilState { + boolean mTryCell = WAIT_FOR_NETWORK_TO_SETTLE; @Override public void enter() { - if (mDunRequired || mUseHiPri) { - Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms"); - sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS); - } - mUpstreamIfaceName = findActiveUpstreamIface(); - if (mUpstreamIfaceName == null) { - Log.d(TAG, "Erroring our of tether - no upstream ifaces available"); - sendMessage(obtainMessage(CMD_CELL_DUN_DISABLED)); - } else { - for (Object o : mNotifyList) { - TetherInterfaceSM sm = (TetherInterfaceSM)o; - sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE)); - } - } + mTryCell = WAIT_FOR_NETWORK_TO_SETTLE; // first pass lets just see what we have. + chooseUpstreamType(mTryCell); + mTryCell = !mTryCell; + turnOnMasterTetherSettings(); // may transition us out + } + @Override + public void exit() { + turnOffMobileConnection(); + notifyTetheredOfNewIface(null); } @Override public boolean processMessage(Message message) { @@ -1351,7 +1298,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { case CMD_TETHER_MODE_REQUESTED: TetherInterfaceSM who = (TetherInterfaceSM)message.obj; mNotifyList.add(who); - who.sendMessage(who.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE)); + who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED); break; case CMD_TETHER_MODE_UNREQUESTED: who = (TetherInterfaceSM)message.obj; @@ -1359,32 +1306,33 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (index != -1) { mNotifyList.remove(index); if (mNotifyList.isEmpty()) { - if (mDunRequired || mUseHiPri) { - turnOffMobileDun(); - } turnOffMasterTetherSettings(); // transitions appropriately - mUpstreamIfaceName = null; } } break; - case CMD_CELL_DUN_DISABLED: - int size = mNotifyList.size(); - for (int i = 0; i < size; i++) { - TetherInterfaceSM sm = (TetherInterfaceSM)mNotifyList.get(i); - mNotifyList.remove(i); - sm.sendMessage(sm.obtainMessage( - TetherInterfaceSM.CMD_TETHER_MODE_DEAD)); + case CMD_UPSTREAM_CHANGED: + mTryCell = WAIT_FOR_NETWORK_TO_SETTLE; + chooseUpstreamType(mTryCell); + mTryCell = !mTryCell; + break; + case CMD_CELL_CONNECTION_RENEW: + // make sure we're still using a requested connection - may have found + // wifi or something since then. + if (mConnectionRequested) { + Log.d(TAG, "renewing mobile connection - requeuing for another " + + CELL_CONNECTION_RENEW_MS + "ms"); + turnOnMobileConnection(); } - turnOffMasterTetherSettings(); // transitions appropriately - mUpstreamIfaceName = null; break; - case CMD_CELL_DUN_RENEW: - Log.d(TAG, "renewing dun connection - requeuing for another " + - CELL_DUN_RENEW_MS + "ms"); - turnOnMobileDun(); - sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS); - break; - default: + case CMD_RETRY_UPSTREAM: + chooseUpstreamType(mTryCell); + mTryCell = !mTryCell; + break; + case CMD_TRANSITION_TO_STATE: + HierarchicalState s = (HierarchicalState)(message.obj); + transitionTo(s); + break; + default: retValue = false; break; } @@ -1400,7 +1348,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { switch (message.what) { case CMD_TETHER_MODE_REQUESTED: TetherInterfaceSM who = (TetherInterfaceSM)message.obj; - who.sendMessage(who.obtainMessage(mErrorNotification)); + who.sendMessage(mErrorNotification); break; default: retValue = false; @@ -1411,19 +1359,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mErrorNotification = msgType; for (Object o : mNotifyList) { TetherInterfaceSM sm = (TetherInterfaceSM)o; - sm.sendMessage(sm.obtainMessage(msgType)); + sm.sendMessage(msgType); } } } - class CellDunErrorState extends ErrorState { - @Override - public void enter() { - Log.e(TAG, "Error trying to enable Cell DUN"); - notify(TetherInterfaceSM.CMD_CELL_DUN_ERROR); - } - } - class SetIpForwardingEnabledErrorState extends ErrorState { @Override public void enter() {