DhcpStateMachine.java revision 2c08ede34ceb0f847cc9f996db9832f5358f8726
1914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff/* 2914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Copyright (C) 2011 The Android Open Source Project 3914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 4914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License"); 5914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * you may not use this file except in compliance with the License. 6914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * You may obtain a copy of the License at 7914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 8914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * http://www.apache.org/licenses/LICENSE-2.0 9914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 10914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Unless required by applicable law or agreed to in writing, software 11914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS, 12914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * See the License for the specific language governing permissions and 14914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * limitations under the License. 15914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff */ 16914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 17914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffpackage android.net; 18914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 19914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport com.android.internal.util.Protocol; 20cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriffimport com.android.internal.util.State; 21cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriffimport com.android.internal.util.StateMachine; 22914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 23914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.app.AlarmManager; 24914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.app.PendingIntent; 25914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.content.BroadcastReceiver; 26914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.content.Context; 27914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.content.Intent; 28914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.content.IntentFilter; 29914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.net.DhcpInfoInternal; 30914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.net.NetworkUtils; 31914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.os.Message; 32914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.os.PowerManager; 33914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.os.SystemClock; 34914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffimport android.util.Log; 35914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 36914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff/** 37914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * StateMachine that interacts with the native DHCP client and can talk to 38914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * a controller that also needs to be a StateMachine 39914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 40914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * The Dhcp state machine provides the following features: 41914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * - Wakeup and renewal using the native DHCP client (which will not renew 42914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * on its own when the device is in suspend state and this can lead to device 43914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * holding IP address beyond expiry) 44914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * - A notification right before DHCP request or renewal is started. This 45914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * can be used for any additional setup before DHCP. For example, wifi sets 46914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * BT-Wifi coex settings right before DHCP is initiated 47914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 48914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * @hide 49914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff */ 50cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriffpublic class DhcpStateMachine extends StateMachine { 51914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 52914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final String TAG = "DhcpStateMachine"; 53914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final boolean DBG = false; 54914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 55914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 56914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* A StateMachine that controls the DhcpStateMachine */ 57cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private StateMachine mController; 58914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 59914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private Context mContext; 60914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private BroadcastReceiver mBroadcastReceiver; 61914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private AlarmManager mAlarmManager; 62914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private PendingIntent mDhcpRenewalIntent; 63914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private PowerManager.WakeLock mDhcpRenewWakeLock; 64914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final String WAKELOCK_TAG = "DHCP"; 65914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 662c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff //Remember DHCP configuration from first request 672c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff private DhcpInfoInternal mDhcpInfo; 682c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff 69914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final int DHCP_RENEW = 0; 70914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW"; 71914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 7241b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //Used for sanity check on setting up renewal 7341b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff private static final int MIN_RENEWAL_TIME_SECS = 5 * 60; // 5 minutes 7441b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff 75914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private enum DhcpAction { 76914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff START, 77914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff RENEW 78914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff }; 79914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 80914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private String mInterfaceName; 81914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private boolean mRegisteredForPreDhcpNotification = false; 82914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 83914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private static final int BASE = Protocol.BASE_DHCP; 84914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 85914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Commands from controller to start/stop DHCP */ 86914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_START_DHCP = BASE + 1; 87914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_STOP_DHCP = BASE + 2; 88914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_RENEW_DHCP = BASE + 3; 89914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 90914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notification from DHCP state machine prior to DHCP discovery/renewal */ 91914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_PRE_DHCP_ACTION = BASE + 4; 92914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates 93914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * success/failure */ 94914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_POST_DHCP_ACTION = BASE + 5; 95914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 96914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Command from controller to indicate DHCP discovery/renewal can continue 97914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * after pre DHCP action is complete */ 98914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6; 99914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 100914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Message.arg1 arguments to CMD_POST_DHCP notification */ 101914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int DHCP_SUCCESS = 1; 102914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int DHCP_FAILURE = 2; 103914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 104cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mDefaultState = new DefaultState(); 105cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mStoppedState = new StoppedState(); 106cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mWaitBeforeStartState = new WaitBeforeStartState(); 107cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mRunningState = new RunningState(); 108cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(); 109914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 110cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private DhcpStateMachine(Context context, StateMachine controller, String intf) { 111914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff super(TAG); 112914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 113914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mContext = context; 114914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController = controller; 115914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mInterfaceName = intf; 116914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 117914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 118914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null); 119914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0); 120914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 121914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 122914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 123cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.setReferenceCounted(false); 124914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 125914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mBroadcastReceiver = new BroadcastReceiver() { 126914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 127914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void onReceive(Context context, Intent intent) { 128914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //DHCP renew 129914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this); 130cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff //Lock released after 40s in worst case scenario 131914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewWakeLock.acquire(40000); 132914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff sendMessage(CMD_RENEW_DHCP); 133914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 134914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff }; 135914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW)); 136914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 137914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mDefaultState); 138914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mStoppedState, mDefaultState); 139914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mWaitBeforeStartState, mDefaultState); 140914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mRunningState, mDefaultState); 141914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mWaitBeforeRenewalState, mDefaultState); 142914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 143914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff setInitialState(mStoppedState); 144914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 145914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 146cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller, 147914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff String intf) { 148914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf); 149914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff dsm.start(); 150914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return dsm; 151914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 152914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 153914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /** 154914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * This sends a notification right before DHCP request/renewal so that the 155914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * controller can do certain actions before DHCP packets are sent out. 156914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message 157914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * to indicate DHCP can continue 158914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 159914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * This is used by Wifi at this time for the purpose of doing BT-Wifi coex 160914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * handling during Dhcp 161914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff */ 162914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void registerForPreDhcpNotification() { 163914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mRegisteredForPreDhcpNotification = true; 164914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 165914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 166cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class DefaultState extends State { 167914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 168914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 169914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 170914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 171914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_RENEW_DHCP: 172914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName); 173cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 174914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 175cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff case SM_QUIT_CMD: 176914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mContext.unregisterReceiver(mBroadcastReceiver); 177914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //let parent kill the state machine 178914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return NOT_HANDLED; 179914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 180914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Error! unhandled message " + message); 181914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 182914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 183914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return HANDLED; 184914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 185914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 186914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 187914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 188cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class StoppedState extends State { 189914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 190914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 191914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 192914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 193914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 194914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 195914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 196914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 197914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 198914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 199914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 200914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (mRegisteredForPreDhcpNotification) { 201914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notify controller before starting DHCP */ 202914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.sendMessage(CMD_PRE_DHCP_ACTION); 203914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mWaitBeforeStartState); 204914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 205914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.START)) { 206914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 207914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 208914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 209914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 210914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 211914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 212914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 213914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 214914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 215914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 216914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 217914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 218914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 219914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 220914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 221cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class WaitBeforeStartState extends State { 222914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 223914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 224914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 225914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 226914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 227914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 228914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 229914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 230914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 231914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 232914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_PRE_DHCP_ACTION_COMPLETE: 233914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.START)) { 234914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 235914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 236914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 237914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 238914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 239914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 240914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 241914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 242914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 243914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 244914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 245914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 246914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 247914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 248914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 249914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 250914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 251914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 252914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 253cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class RunningState extends State { 254914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 255914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 256914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 257914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 258914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 259914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 260914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 261914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 262914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 263914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 264914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 265914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager.cancel(mDhcpRenewalIntent); 266914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!NetworkUtils.stopDhcp(mInterfaceName)) { 267914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); 268914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 269914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 270914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 271914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_RENEW_DHCP: 272914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (mRegisteredForPreDhcpNotification) { 273914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notify controller before starting DHCP */ 274914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.sendMessage(CMD_PRE_DHCP_ACTION); 275914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mWaitBeforeRenewalState); 276cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff //mDhcpRenewWakeLock is released in WaitBeforeRenewalState 277914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 278914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!runDhcp(DhcpAction.RENEW)) { 279914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 280914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 281cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 282914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 283914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 284914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 285914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 286914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 287914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 288914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 289914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 290914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 291914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 292914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 293914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 294cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class WaitBeforeRenewalState extends State { 295914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 296914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 297914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 298914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 299914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 300914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 301914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 302914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 303914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 304914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 305914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 306914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager.cancel(mDhcpRenewalIntent); 307914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!NetworkUtils.stopDhcp(mInterfaceName)) { 308914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); 309914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 310914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 311914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 312914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_PRE_DHCP_ACTION_COMPLETE: 313914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.RENEW)) { 314914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 315914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 316914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 317914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 318914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 319914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 320914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 321914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 322914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 323914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 324914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 325914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 326914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 327914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 328cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff @Override 329cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff public void exit() { 330cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 331cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff } 332914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 333914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 334914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private boolean runDhcp(DhcpAction dhcpAction) { 335914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean success = false; 336914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); 337914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 338914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (dhcpAction == DhcpAction.START) { 339914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.d(TAG, "DHCP request on " + mInterfaceName); 340914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal); 3412c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff mDhcpInfo = dhcpInfoInternal; 342914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else if (dhcpAction == DhcpAction.RENEW) { 343914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.d(TAG, "DHCP renewal on " + mInterfaceName); 344914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal); 3452c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff dhcpInfoInternal.updateFromDhcpRequest(mDhcpInfo); 346914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 347914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 348914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (success) { 349914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.d(TAG, "DHCP succeeded on " + mInterfaceName); 35041b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff long leaseDuration = dhcpInfoInternal.leaseDuration; //int to long conversion 35141b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff 35241b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //Sanity check for renewal 35341b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //TODO: would be good to notify the user that his network configuration is 35441b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS 35541b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff if (leaseDuration < MIN_RENEWAL_TIME_SECS) { 35641b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff leaseDuration = MIN_RENEWAL_TIME_SECS; 35741b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff } 35841b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //Do it a bit earlier than half the lease duration time 35941b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //to beat the native DHCP client and avoid extra packets 36041b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff //48% for one hour lease time = 29 minutes 36141b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 36241b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff SystemClock.elapsedRealtime() + 36341b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff leaseDuration * 480, //in milliseconds 36441b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff mDhcpRenewalIntent); 365914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 366914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal) 367914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff .sendToTarget(); 368914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 369914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " + 370914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff NetworkUtils.getDhcpError()); 371914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff NetworkUtils.stopDhcp(mInterfaceName); 372914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) 373914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff .sendToTarget(); 374914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 375914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return success; 376914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 377914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff} 378