diff options
author | Irfan Sheriff <isheriff@google.com> | 2011-04-22 12:20:38 -0700 |
---|---|---|
committer | Irfan Sheriff <isheriff@google.com> | 2011-04-22 15:08:02 -0700 |
commit | d2127c438fc858a4f6c8ad75b7a1e4491da69a78 (patch) | |
tree | 29d8ee8241095523d3f110432beae43022988254 /wifi/java/android/net | |
parent | f0f1ceeb517ff226532a407da6d55602f195e5b5 (diff) | |
download | frameworks_base-d2127c438fc858a4f6c8ad75b7a1e4491da69a78.zip frameworks_base-d2127c438fc858a4f6c8ad75b7a1e4491da69a78.tar.gz frameworks_base-d2127c438fc858a4f6c8ad75b7a1e4491da69a78.tar.bz2 |
Handle DHCP renewal and wakeup in framework
The native DHCP client renews IP address, but can fail to do so when the device
is in suspend. This has lead to issues where device fails to renew in time and
on networks with lots of devices re-using expired DHCP IP addresses, it leads to
severe issues.
Handle DHCP renewal and wakeup in framework
Bug: 3344732
Change-Id: Ie4062e04a477f4a233946155e40a7c999b337c3f
Diffstat (limited to 'wifi/java/android/net')
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 153 |
1 files changed, 122 insertions, 31 deletions
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 27e6a72..f313259 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -23,6 +23,18 @@ import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; import android.app.ActivityManagerNative; +import android.app.AlarmManager; +import android.app.Notification; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothA2dp; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; import android.net.NetworkInfo; import android.net.NetworkStateTracker; import android.net.DhcpInfo; @@ -32,8 +44,10 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Message; import android.os.Parcelable; +import android.os.PowerManager; import android.os.Handler; import android.os.HandlerThread; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.Looper; import android.os.RemoteException; @@ -44,15 +58,6 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.util.Config; -import android.app.Notification; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothA2dp; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.Context; -import android.database.ContentObserver; import com.android.internal.app.IBatteryStats; import java.net.UnknownHostException; @@ -91,15 +96,16 @@ public class WifiStateTracker extends NetworkStateTracker { private static final int EVENT_INTERFACE_CONFIGURATION_FAILED = 7; private static final int EVENT_POLL_INTERVAL = 8; private static final int EVENT_DHCP_START = 9; - private static final int EVENT_DEFERRED_DISCONNECT = 10; - private static final int EVENT_DEFERRED_RECONNECT = 11; + private static final int EVENT_DHCP_RENEW = 10; + private static final int EVENT_DEFERRED_DISCONNECT = 11; + private static final int EVENT_DEFERRED_RECONNECT = 12; /** * The driver is started or stopped. The object will be the state: true for * started, false for stopped. */ - private static final int EVENT_DRIVER_STATE_CHANGED = 12; - private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT = 13; - private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT = 14; + private static final int EVENT_DRIVER_STATE_CHANGED = 13; + private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT = 14; + private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT = 15; /** * The driver state indication. @@ -218,6 +224,15 @@ public class WifiStateTracker extends NetworkStateTracker { private boolean mUseStaticIp = false; private int mReconnectCount; + private AlarmManager mAlarmManager; + private PendingIntent mDhcpRenewalIntent; + private PowerManager.WakeLock mDhcpRenewWakeLock; + private static final String WAKELOCK_TAG = "*wifi*"; + + private static final int DHCP_RENEW = 0; + private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW"; + + /* Tracks if any network in the configuration is disabled */ private AtomicBoolean mIsAnyNetworkDisabled = new AtomicBoolean(false); @@ -385,6 +400,27 @@ public class WifiStateTracker extends NetworkStateTracker { mDhcpInfo = new DhcpInfo(); mRunState = RUN_STATE_STARTING; + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null); + mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0); + + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + //DHCP renew + if (mDhcpTarget != null) { + Log.d(TAG, "Sending a DHCP renewal"); + //acquire a 40s wakelock to finish DHCP renewal + mDhcpRenewWakeLock.acquire(40000); + mDhcpTarget.sendEmptyMessage(EVENT_DHCP_RENEW); + } + } + },new IntentFilter(ACTION_DHCP_RENEW)); + + PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); + // Setting is in seconds NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; @@ -2388,7 +2424,7 @@ public class WifiStateTracker extends NetworkStateTracker { private class DhcpHandler extends Handler { - private Handler mTarget; + private Handler mWifiStateTrackerHandler; /** * Whether to skip the DHCP result callback to the target. For example, @@ -2409,10 +2445,10 @@ public class WifiStateTracker extends NetworkStateTracker { * in an error state and we will not disable coexistence. */ private BluetoothHeadset mBluetoothHeadset; - + public DhcpHandler(Looper looper, Handler target) { super(looper); - mTarget = target; + mWifiStateTrackerHandler = target; mBluetoothHeadset = new BluetoothHeadset(mContext, null); } @@ -2422,7 +2458,7 @@ public class WifiStateTracker extends NetworkStateTracker { switch (msg.what) { case EVENT_DHCP_START: - + case EVENT_DHCP_RENEW: boolean modifiedBluetoothCoexistenceMode = false; int powerMode = DRIVER_POWER_MODE_AUTO; @@ -2464,14 +2500,70 @@ public class WifiStateTracker extends NetworkStateTracker { // A new request is being made, so assume we will callback mCancelCallback = false; } - Log.d(TAG, "DhcpHandler: DHCP request started"); - if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) { - event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; - if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded"); - } else { - event = EVENT_INTERFACE_CONFIGURATION_FAILED; - Log.i(TAG, "DhcpHandler: DHCP request failed: " + - NetworkUtils.getDhcpError()); + + if (msg.what == EVENT_DHCP_START) { + Log.d(TAG, "DHCP request started"); + if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) { + event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; + Log.d(TAG, "DHCP succeeded with lease: " + mDhcpInfo.leaseDuration); + //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.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + + mDhcpInfo.leaseDuration * 480, //in milliseconds + mDhcpRenewalIntent); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + Log.e(TAG, "DHCP request failed: " + NetworkUtils.getDhcpError()); + } + synchronized (this) { + if (!mCancelCallback) { + mWifiStateTrackerHandler.sendEmptyMessage(event); + } + } + + } else if (msg.what == EVENT_DHCP_RENEW) { + Log.d(TAG, "DHCP renewal started"); + int oIp = mDhcpInfo.ipAddress; + int oGw = mDhcpInfo.gateway; + int oMsk = mDhcpInfo.netmask; + int oDns1 = mDhcpInfo.dns1; + int oDns2 = mDhcpInfo.dns2; + + if (NetworkUtils.runDhcpRenew(mInterfaceName, mDhcpInfo)) { + Log.d(TAG, "DHCP renewal with lease: " + mDhcpInfo.leaseDuration); + + boolean changed = + (oIp != mDhcpInfo.ipAddress || + oGw != mDhcpInfo.gateway || + oMsk != mDhcpInfo.netmask || + oDns1 != mDhcpInfo.dns1 || + oDns2 != mDhcpInfo.dns2); + + if (changed) { + Log.d(TAG, "IP config change on renewal"); + mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); + NetworkUtils.resetConnections(mInterfaceName); + msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, + mNetworkInfo); + msg.sendToTarget(); + } + + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + + mDhcpInfo.leaseDuration * 480, + mDhcpRenewalIntent); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + Log.d(TAG, "DHCP renewal failed: " + NetworkUtils.getDhcpError()); + + synchronized (this) { + if (!mCancelCallback) { + mWifiStateTrackerHandler.sendEmptyMessage(event); + } + } + } } if (powerMode != DRIVER_POWER_MODE_ACTIVE) { @@ -2484,17 +2576,15 @@ public class WifiStateTracker extends NetworkStateTracker { WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); } - synchronized (this) { - if (!mCancelCallback) { - mTarget.sendEmptyMessage(event); - } - } break; } } public synchronized void setCancelCallback(boolean cancelCallback) { mCancelCallback = cancelCallback; + if (cancelCallback) { + mAlarmManager.cancel(mDhcpRenewalIntent); + } } /** @@ -2510,6 +2600,7 @@ public class WifiStateTracker extends NetworkStateTracker { int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset()); return state == BluetoothHeadset.STATE_DISCONNECTED; } + } private void checkUseStaticIp() { |