diff options
-rw-r--r-- | services/java/com/android/server/connectivity/Tethering.java | 536 |
1 files changed, 238 insertions, 298 deletions
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index ccb5fc6..fcb39c9 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,156 +1174,100 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } return null; } - } - - class InitialState extends TetherMasterUtilState { - @Override - public void enter() { + 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; - } - @Override - public boolean processMessage(Message message) { - Log.d(TAG, "MasterInitialState.processMessage what=" + message.what); - boolean retValue = true; - switch (message.what) { - case CMD_TETHER_MODE_REQUESTED: - TetherInterfaceSM who = (TetherInterfaceSM)message.obj; - Log.d(TAG, "Tether Mode requested by " + who.toString()); - mNotifyList.add(who); - transitionTo(mCellDunRequestedState); - break; - case CMD_TETHER_MODE_UNREQUESTED: - who = (TetherInterfaceSM)message.obj; - Log.d(TAG, "Tether Mode unrequested by " + who.toString()); - int index = mNotifyList.indexOf(who); - if (index != -1) { - mNotifyList.remove(who); + 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(); } - 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); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling ConnectivityManager"); + notifyTetheredOfNewIface(null); + } + if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) { + turnOnMobileConnection(); } } else { - Log.d(TAG, "no Dun Required. Skipping to Active"); - sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED)); - } - } + if (iface == null) { + if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) { + Log.d(TAG, "turning on hipri"); + mUseHiPri = true; + turnOnMobileConnection(); // try to turn on hipri + } - @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); + } 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"); } - 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; + // 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); } - return retValue; } } - class CellDunAliveState extends TetherMasterUtilState { + class InitialState 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); + mUseHiPri = false; + mConnectionRequested = false; } - @Override public boolean processMessage(Message message) { - Log.d(TAG, "CellDunAliveState.processMessage what=" + message.what); + Log.d(TAG, "MasterInitialState.processMessage what=" + message.what); boolean retValue = true; switch (message.what) { case CMD_TETHER_MODE_REQUESTED: TetherInterfaceSM who = (TetherInterfaceSM)message.obj; + Log.d(TAG, "Tether Mode requested by " + who.toString()); mNotifyList.add(who); - turnOnMasterTetherSettings(); + transitionTo(mTetherModeAliveState); break; case CMD_TETHER_MODE_UNREQUESTED: who = (TetherInterfaceSM)message.obj; + Log.d(TAG, "Tether Mode unrequested by " + who.toString()); int index = mNotifyList.indexOf(who); if (index != -1) { - mNotifyList.remove(index); - if (mNotifyList.isEmpty()) { - if (mDunRequired || mUseHiPri) { - turnOffMobileDun(); - } - transitionTo(mInitialState); - } + mNotifyList.remove(who); } 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)); - } - turnOffMasterTetherSettings(); // transitions appropriately - mUpstreamIfaceName = null; + case CMD_UPSTREAM_CHANGED: + mTryCell = WAIT_FOR_NETWORK_TO_SETTLE; + chooseUpstreamType(mTryCell); + mTryCell = !mTryCell; 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); + 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(); + } 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() { |