diff options
-rw-r--r-- | core/java/android/net/DhcpStateMachine.java | 177 |
1 files changed, 120 insertions, 57 deletions
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 1b8adc8..73ef78e 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -37,7 +37,7 @@ import android.util.Log; * StateMachine that interacts with the native DHCP client and can talk to * a controller that also needs to be a StateMachine * - * The Dhcp state machine provides the following features: + * The DhcpStateMachine provides the following features: * - Wakeup and renewal using the native DHCP client (which will not renew * on its own when the device is in suspend state and this can lead to device * holding IP address beyond expiry) @@ -72,11 +72,6 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { //Used for sanity check on setting up renewal private static final int MIN_RENEWAL_TIME_SECS = 5 * 60; // 5 minutes - private enum DhcpAction { - START, - RENEW - }; - private final String mInterfaceName; private boolean mRegisteredForPreDhcpNotification = false; @@ -99,6 +94,9 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { * after pre DHCP action is complete */ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 7; + /* Command from ourselves to see if DHCP results are available */ + private static final int CMD_GET_DHCP_RESULTS = BASE + 8; + /* Message.arg1 arguments to CMD_POST_DHCP notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; @@ -108,6 +106,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { private State mWaitBeforeStartState = new WaitBeforeStartState(); private State mRunningState = new RunningState(); private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(); + private State mPollingState = new PollingState(); private DhcpStateMachine(Context context, StateMachine controller, String intf) { super(TAG); @@ -139,6 +138,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { addState(mDefaultState); addState(mStoppedState, mDefaultState); addState(mWaitBeforeStartState, mDefaultState); + addState(mPollingState, mDefaultState); addState(mRunningState, mDefaultState); addState(mWaitBeforeRenewalState, mDefaultState); @@ -206,6 +206,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); + } + mDhcpResults = null; } @Override @@ -219,7 +223,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { mController.sendMessage(CMD_PRE_DHCP_ACTION); transitionTo(mWaitBeforeStartState); } else { - if (runDhcp(DhcpAction.START)) { + if (runDhcpStart()) { transitionTo(mRunningState); } } @@ -247,10 +251,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case CMD_PRE_DHCP_ACTION_COMPLETE: - if (runDhcp(DhcpAction.START)) { + if (runDhcpStart()) { transitionTo(mRunningState); } else { - transitionTo(mStoppedState); + transitionTo(mPollingState); } break; case CMD_STOP_DHCP: @@ -267,6 +271,55 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { } } + class PollingState extends State { + private static final long MAX_DELAY_SECONDS = 32; + private long delaySeconds; + + private void scheduleNextResultsCheck() { + sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000); + delaySeconds *= 2; + if (delaySeconds > MAX_DELAY_SECONDS) { + delaySeconds = MAX_DELAY_SECONDS; + } + } + + @Override + public void enter() { + if (DBG) Log.d(TAG, "Entering " + getName() + "\n"); + delaySeconds = 1; + scheduleNextResultsCheck(); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_GET_DHCP_RESULTS: + if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName); + if (dhcpSucceeded()) { + transitionTo(mRunningState); + } else { + scheduleNextResultsCheck(); + } + break; + case CMD_STOP_DHCP: + transitionTo(mStoppedState); + break; + default: + retValue = NOT_HANDLED; + break; + } + return retValue; + } + + @Override + public void exit() { + if (DBG) Log.d(TAG, "Exiting " + getName() + "\n"); + removeMessages(CMD_GET_DHCP_RESULTS); + } + } + class RunningState extends State { @Override public void enter() { @@ -280,9 +333,6 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { switch (message.what) { case CMD_STOP_DHCP: mAlarmManager.cancel(mDhcpRenewalIntent); - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); - } transitionTo(mStoppedState); break; case CMD_RENEW_DHCP: @@ -292,7 +342,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { transitionTo(mWaitBeforeRenewalState); //mDhcpRenewWakeLock is released in WaitBeforeRenewalState } else { - if (!runDhcp(DhcpAction.RENEW)) { + if (!runDhcpRenew()) { transitionTo(mStoppedState); } mDhcpRenewWakeLock.release(); @@ -321,13 +371,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { switch (message.what) { case CMD_STOP_DHCP: mAlarmManager.cancel(mDhcpRenewalIntent); - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); - } transitionTo(mStoppedState); break; case CMD_PRE_DHCP_ACTION_COMPLETE: - if (runDhcp(DhcpAction.RENEW)) { + if (runDhcpRenew()) { transitionTo(mRunningState); } else { transitionTo(mStoppedState); @@ -348,52 +395,68 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { } } - private boolean runDhcp(DhcpAction dhcpAction) { - boolean success = false; + private boolean dhcpSucceeded() { DhcpResults dhcpResults = new DhcpResults(); - - if (dhcpAction == DhcpAction.START) { - /* Stop any existing DHCP daemon before starting new */ - NetworkUtils.stopDhcp(mInterfaceName); - if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); - success = NetworkUtils.runDhcp(mInterfaceName, dhcpResults); - } else if (dhcpAction == DhcpAction.RENEW) { - if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName); - success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpResults); - if (success) dhcpResults.updateFromDhcpRequest(mDhcpResults); + if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) { + return false; } - if (success) { - if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName); - long leaseDuration = dhcpResults.leaseDuration; //int to long conversion - - //Sanity check for renewal - if (leaseDuration >= 0) { - //TODO: would be good to notify the user that his network configuration is - //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS - if (leaseDuration < MIN_RENEWAL_TIME_SECS) { - leaseDuration = MIN_RENEWAL_TIME_SECS; - } - //Do it a bit earlier than half the lease duration time - //to beat the native DHCP client and avoid extra packets - //48% for one hour lease time = 29 minutes - mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + - leaseDuration * 480, //in milliseconds - mDhcpRenewalIntent); - } else { - //infinite lease time, no renewal needed - } - mDhcpResults = dhcpResults; - mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults) - .sendToTarget(); + if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName); + long leaseDuration = dhcpResults.leaseDuration; //int to long conversion + + //Sanity check for renewal + if (leaseDuration >= 0) { + //TODO: would be good to notify the user that his network configuration is + //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS + if (leaseDuration < MIN_RENEWAL_TIME_SECS) { + leaseDuration = MIN_RENEWAL_TIME_SECS; + } + //Do it a bit earlier than half the lease duration time + //to beat the native DHCP client and avoid extra packets + //48% for one hour lease time = 29 minutes + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + + leaseDuration * 480, //in milliseconds + mDhcpRenewalIntent); } else { - Log.e(TAG, "DHCP failed on " + mInterfaceName + ": " + + //infinite lease time, no renewal needed + } + + // Fill in any missing fields in dhcpResults from the previous results. + // If mDhcpResults is null (i.e. this is the first server response), + // this is a noop. + dhcpResults.updateFromDhcpRequest(mDhcpResults); + mDhcpResults = dhcpResults; + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults) + .sendToTarget(); + return true; + } + + private boolean runDhcpStart() { + /* Stop any existing DHCP daemon before starting new */ + NetworkUtils.stopDhcp(mInterfaceName); + mDhcpResults = null; + + if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); + if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) { + Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " + + NetworkUtils.getDhcpError()); + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) + .sendToTarget(); + return false; + } + return true; + } + + private boolean runDhcpRenew() { + if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName); + if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) { + Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " + NetworkUtils.getDhcpError()); - NetworkUtils.stopDhcp(mInterfaceName); mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) - .sendToTarget(); + .sendToTarget(); + return false; } - return success; + return true; } } |