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; 956bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff /* Notification from DHCP state machine before quitting */ 966bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff public static final int CMD_ON_QUIT = BASE + 6; 97914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 98914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Command from controller to indicate DHCP discovery/renewal can continue 99914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * after pre DHCP action is complete */ 1006bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 7; 101914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 102914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Message.arg1 arguments to CMD_POST_DHCP notification */ 103914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int DHCP_SUCCESS = 1; 104914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public static final int DHCP_FAILURE = 2; 105914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 106cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mDefaultState = new DefaultState(); 107cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mStoppedState = new StoppedState(); 108cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mWaitBeforeStartState = new WaitBeforeStartState(); 109cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mRunningState = new RunningState(); 110cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(); 111914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 112cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff private DhcpStateMachine(Context context, StateMachine controller, String intf) { 113914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff super(TAG); 114914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 115914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mContext = context; 116914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController = controller; 117914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mInterfaceName = intf; 118914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 119914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 120914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null); 121914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0); 122914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 123914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 124914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 125cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.setReferenceCounted(false); 126914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 127914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mBroadcastReceiver = new BroadcastReceiver() { 128914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 129914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void onReceive(Context context, Intent intent) { 130914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //DHCP renew 131914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this); 132cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff //Lock released after 40s in worst case scenario 133914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mDhcpRenewWakeLock.acquire(40000); 134914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff sendMessage(CMD_RENEW_DHCP); 135914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 136914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff }; 137914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW)); 138914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 139914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mDefaultState); 140914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mStoppedState, mDefaultState); 141914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mWaitBeforeStartState, mDefaultState); 142914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mRunningState, mDefaultState); 143914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff addState(mWaitBeforeRenewalState, mDefaultState); 144914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 145914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff setInitialState(mStoppedState); 146914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 147914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 148cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller, 149914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff String intf) { 150914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf); 151914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff dsm.start(); 152914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return dsm; 153914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 154914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 155914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /** 156914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * This sends a notification right before DHCP request/renewal so that the 157914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * controller can do certain actions before DHCP packets are sent out. 158914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message 159914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * to indicate DHCP can continue 160914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * 161914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * This is used by Wifi at this time for the purpose of doing BT-Wifi coex 162914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * handling during Dhcp 163914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff */ 164914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void registerForPreDhcpNotification() { 165914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mRegisteredForPreDhcpNotification = true; 166914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 167914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 168bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville /** 169bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville * Quit the DhcpStateMachine. 170bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville * 171bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville * @hide 172bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville */ 173bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville public void doQuit() { 174bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville quit(); 175bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville } 176bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville 1776bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff protected void onQuitting() { 1786bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff mController.sendMessage(CMD_ON_QUIT); 1796bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff } 1806bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff 181cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class DefaultState extends State { 182914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 183bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville public void exit() { 184bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville mContext.unregisterReceiver(mBroadcastReceiver); 185bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville } 186bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville @Override 187914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 188914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 189914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 190914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_RENEW_DHCP: 191914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName); 192cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 193914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 194914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 195914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Error! unhandled message " + message); 196914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 197914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 198914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return HANDLED; 199914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 200914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 201914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 202914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 203cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class StoppedState extends State { 204914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 205914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 206914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 207914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 208914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 209914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 210914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 211914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 212914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 213914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 214914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 215914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (mRegisteredForPreDhcpNotification) { 216914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notify controller before starting DHCP */ 217914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.sendMessage(CMD_PRE_DHCP_ACTION); 218914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mWaitBeforeStartState); 219914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 220914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.START)) { 221914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 222914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 223914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 224914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 225914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 226914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 227914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 228914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 229914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 230914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 231914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 232914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 233914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 234914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 235914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 236cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class WaitBeforeStartState extends State { 237914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 238914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 239914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 240914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 241914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 242914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 243914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 244914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 245914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 246914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 247914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_PRE_DHCP_ACTION_COMPLETE: 248914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.START)) { 249914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 250914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 251914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 252914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 253914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 254914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 255914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 256914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 257914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 258914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 259914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 260914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 261914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 262914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 263914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 264914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 265914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 266914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 267914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 268cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class RunningState extends State { 269914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 270914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 271914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 272914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 273914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 274914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 275914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 276914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 277914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 278914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 279914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 280914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager.cancel(mDhcpRenewalIntent); 281914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!NetworkUtils.stopDhcp(mInterfaceName)) { 282914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); 283914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 284914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 285914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 286914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_RENEW_DHCP: 287914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (mRegisteredForPreDhcpNotification) { 288914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff /* Notify controller before starting DHCP */ 289914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.sendMessage(CMD_PRE_DHCP_ACTION); 290914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mWaitBeforeRenewalState); 291cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff //mDhcpRenewWakeLock is released in WaitBeforeRenewalState 292914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 293914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!runDhcp(DhcpAction.RENEW)) { 294914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 295914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 296cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 297914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 298914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 299914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 300914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 301914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 302914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 303914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 304914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 305914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 306914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 307914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 308914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 309cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff class WaitBeforeRenewalState extends State { 310914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 311914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public void enter() { 312914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + "\n"); 313914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 314914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 315914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff @Override 316914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff public boolean processMessage(Message message) { 317914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean retValue = HANDLED; 318914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 319914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff switch (message.what) { 320914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_STOP_DHCP: 321914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mAlarmManager.cancel(mDhcpRenewalIntent); 322914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (!NetworkUtils.stopDhcp(mInterfaceName)) { 323914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); 324914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 325914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 326914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 327914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_PRE_DHCP_ACTION_COMPLETE: 328914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (runDhcp(DhcpAction.RENEW)) { 329914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mRunningState); 330914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 331914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff transitionTo(mStoppedState); 332914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 333914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 334914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff case CMD_START_DHCP: 335914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff //ignore 336914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 337914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff default: 338914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff retValue = NOT_HANDLED; 339914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff break; 340914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 341914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return retValue; 342914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 343cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff @Override 344cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff public void exit() { 345cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff mDhcpRenewWakeLock.release(); 346cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff } 347914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 348914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 349914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff private boolean runDhcp(DhcpAction dhcpAction) { 350914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff boolean success = false; 351914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); 352914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 353914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (dhcpAction == DhcpAction.START) { 3547f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); 355914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal); 3562c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff mDhcpInfo = dhcpInfoInternal; 357914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else if (dhcpAction == DhcpAction.RENEW) { 3587f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName); 359914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal); 3602c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff dhcpInfoInternal.updateFromDhcpRequest(mDhcpInfo); 361914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 362914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 363914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff if (success) { 3647f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName); 365b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff long leaseDuration = dhcpInfoInternal.leaseDuration; //int to long conversion 366b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff 367b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //Sanity check for renewal 368b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff if (leaseDuration >= 0) { 369b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //TODO: would be good to notify the user that his network configuration is 370b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS 371b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff if (leaseDuration < MIN_RENEWAL_TIME_SECS) { 372b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff leaseDuration = MIN_RENEWAL_TIME_SECS; 373b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff } 374b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //Do it a bit earlier than half the lease duration time 375b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //to beat the native DHCP client and avoid extra packets 376b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //48% for one hour lease time = 29 minutes 377b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 378b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff SystemClock.elapsedRealtime() + 379b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff leaseDuration * 480, //in milliseconds 380b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff mDhcpRenewalIntent); 381b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff } else { 382b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff //infinite lease time, no renewal needed 383b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff } 384914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff 385914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal) 386914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff .sendToTarget(); 387914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } else { 3887f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff Log.e(TAG, "DHCP failed on " + mInterfaceName + ": " + 389914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff NetworkUtils.getDhcpError()); 390914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff NetworkUtils.stopDhcp(mInterfaceName); 391914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) 392914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff .sendToTarget(); 393914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 394914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff return success; 395914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff } 396914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff} 397