Skip to content

Commit d2127c4

Browse files
committed
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
1 parent f0f1cee commit d2127c4

File tree

1 file changed

+122
-31
lines changed

1 file changed

+122
-31
lines changed

wifi/java/android/net/wifi/WifiStateTracker.java

Lines changed: 122 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@
2323
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
2424

2525
import android.app.ActivityManagerNative;
26+
import android.app.AlarmManager;
27+
import android.app.Notification;
28+
import android.app.PendingIntent;
29+
import android.bluetooth.BluetoothDevice;
30+
import android.bluetooth.BluetoothHeadset;
31+
import android.bluetooth.BluetoothA2dp;
32+
import android.content.BroadcastReceiver;
33+
import android.content.ContentResolver;
34+
import android.content.Context;
35+
import android.content.Intent;
36+
import android.content.IntentFilter;
37+
import android.database.ContentObserver;
2638
import android.net.NetworkInfo;
2739
import android.net.NetworkStateTracker;
2840
import android.net.DhcpInfo;
@@ -32,8 +44,10 @@
3244
import android.net.NetworkInfo.State;
3345
import android.os.Message;
3446
import android.os.Parcelable;
47+
import android.os.PowerManager;
3548
import android.os.Handler;
3649
import android.os.HandlerThread;
50+
import android.os.SystemClock;
3751
import android.os.SystemProperties;
3852
import android.os.Looper;
3953
import android.os.RemoteException;
@@ -44,15 +58,6 @@
4458
import android.util.EventLog;
4559
import android.util.Log;
4660
import android.util.Config;
47-
import android.app.Notification;
48-
import android.app.PendingIntent;
49-
import android.bluetooth.BluetoothDevice;
50-
import android.bluetooth.BluetoothHeadset;
51-
import android.bluetooth.BluetoothA2dp;
52-
import android.content.ContentResolver;
53-
import android.content.Intent;
54-
import android.content.Context;
55-
import android.database.ContentObserver;
5661
import com.android.internal.app.IBatteryStats;
5762

5863
import java.net.UnknownHostException;
@@ -91,15 +96,16 @@ public class WifiStateTracker extends NetworkStateTracker {
9196
private static final int EVENT_INTERFACE_CONFIGURATION_FAILED = 7;
9297
private static final int EVENT_POLL_INTERVAL = 8;
9398
private static final int EVENT_DHCP_START = 9;
94-
private static final int EVENT_DEFERRED_DISCONNECT = 10;
95-
private static final int EVENT_DEFERRED_RECONNECT = 11;
99+
private static final int EVENT_DHCP_RENEW = 10;
100+
private static final int EVENT_DEFERRED_DISCONNECT = 11;
101+
private static final int EVENT_DEFERRED_RECONNECT = 12;
96102
/**
97103
* The driver is started or stopped. The object will be the state: true for
98104
* started, false for stopped.
99105
*/
100-
private static final int EVENT_DRIVER_STATE_CHANGED = 12;
101-
private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT = 13;
102-
private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT = 14;
106+
private static final int EVENT_DRIVER_STATE_CHANGED = 13;
107+
private static final int EVENT_PASSWORD_KEY_MAY_BE_INCORRECT = 14;
108+
private static final int EVENT_MAYBE_START_SCAN_POST_DISCONNECT = 15;
103109

104110
/**
105111
* The driver state indication.
@@ -218,6 +224,15 @@ public class WifiStateTracker extends NetworkStateTracker {
218224
private boolean mUseStaticIp = false;
219225
private int mReconnectCount;
220226

227+
private AlarmManager mAlarmManager;
228+
private PendingIntent mDhcpRenewalIntent;
229+
private PowerManager.WakeLock mDhcpRenewWakeLock;
230+
private static final String WAKELOCK_TAG = "*wifi*";
231+
232+
private static final int DHCP_RENEW = 0;
233+
private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
234+
235+
221236
/* Tracks if any network in the configuration is disabled */
222237
private AtomicBoolean mIsAnyNetworkDisabled = new AtomicBoolean(false);
223238

@@ -385,6 +400,27 @@ public WifiStateTracker(Context context, Handler target) {
385400
mDhcpInfo = new DhcpInfo();
386401
mRunState = RUN_STATE_STARTING;
387402

403+
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
404+
Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
405+
mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
406+
407+
mContext.registerReceiver(
408+
new BroadcastReceiver() {
409+
@Override
410+
public void onReceive(Context context, Intent intent) {
411+
//DHCP renew
412+
if (mDhcpTarget != null) {
413+
Log.d(TAG, "Sending a DHCP renewal");
414+
//acquire a 40s wakelock to finish DHCP renewal
415+
mDhcpRenewWakeLock.acquire(40000);
416+
mDhcpTarget.sendEmptyMessage(EVENT_DHCP_RENEW);
417+
}
418+
}
419+
},new IntentFilter(ACTION_DHCP_RENEW));
420+
421+
PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
422+
mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
423+
388424
// Setting is in seconds
389425
NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
390426
Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
@@ -2388,7 +2424,7 @@ public String toString() {
23882424

23892425
private class DhcpHandler extends Handler {
23902426

2391-
private Handler mTarget;
2427+
private Handler mWifiStateTrackerHandler;
23922428

23932429
/**
23942430
* Whether to skip the DHCP result callback to the target. For example,
@@ -2409,10 +2445,10 @@ private class DhcpHandler extends Handler {
24092445
* in an error state and we will not disable coexistence.
24102446
*/
24112447
private BluetoothHeadset mBluetoothHeadset;
2412-
2448+
24132449
public DhcpHandler(Looper looper, Handler target) {
24142450
super(looper);
2415-
mTarget = target;
2451+
mWifiStateTrackerHandler = target;
24162452

24172453
mBluetoothHeadset = new BluetoothHeadset(mContext, null);
24182454
}
@@ -2422,7 +2458,7 @@ public void handleMessage(Message msg) {
24222458

24232459
switch (msg.what) {
24242460
case EVENT_DHCP_START:
2425-
2461+
case EVENT_DHCP_RENEW:
24262462
boolean modifiedBluetoothCoexistenceMode = false;
24272463
int powerMode = DRIVER_POWER_MODE_AUTO;
24282464

@@ -2464,14 +2500,70 @@ public void handleMessage(Message msg) {
24642500
// A new request is being made, so assume we will callback
24652501
mCancelCallback = false;
24662502
}
2467-
Log.d(TAG, "DhcpHandler: DHCP request started");
2468-
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
2469-
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
2470-
if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");
2471-
} else {
2472-
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
2473-
Log.i(TAG, "DhcpHandler: DHCP request failed: " +
2474-
NetworkUtils.getDhcpError());
2503+
2504+
if (msg.what == EVENT_DHCP_START) {
2505+
Log.d(TAG, "DHCP request started");
2506+
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
2507+
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
2508+
Log.d(TAG, "DHCP succeeded with lease: " + mDhcpInfo.leaseDuration);
2509+
//Do it a bit earlier than half the lease duration time
2510+
//to beat the native DHCP client and avoid extra packets
2511+
//48% for one hour lease time = 29 minutes
2512+
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2513+
SystemClock.elapsedRealtime() +
2514+
mDhcpInfo.leaseDuration * 480, //in milliseconds
2515+
mDhcpRenewalIntent);
2516+
} else {
2517+
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
2518+
Log.e(TAG, "DHCP request failed: " + NetworkUtils.getDhcpError());
2519+
}
2520+
synchronized (this) {
2521+
if (!mCancelCallback) {
2522+
mWifiStateTrackerHandler.sendEmptyMessage(event);
2523+
}
2524+
}
2525+
2526+
} else if (msg.what == EVENT_DHCP_RENEW) {
2527+
Log.d(TAG, "DHCP renewal started");
2528+
int oIp = mDhcpInfo.ipAddress;
2529+
int oGw = mDhcpInfo.gateway;
2530+
int oMsk = mDhcpInfo.netmask;
2531+
int oDns1 = mDhcpInfo.dns1;
2532+
int oDns2 = mDhcpInfo.dns2;
2533+
2534+
if (NetworkUtils.runDhcpRenew(mInterfaceName, mDhcpInfo)) {
2535+
Log.d(TAG, "DHCP renewal with lease: " + mDhcpInfo.leaseDuration);
2536+
2537+
boolean changed =
2538+
(oIp != mDhcpInfo.ipAddress ||
2539+
oGw != mDhcpInfo.gateway ||
2540+
oMsk != mDhcpInfo.netmask ||
2541+
oDns1 != mDhcpInfo.dns1 ||
2542+
oDns2 != mDhcpInfo.dns2);
2543+
2544+
if (changed) {
2545+
Log.d(TAG, "IP config change on renewal");
2546+
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
2547+
NetworkUtils.resetConnections(mInterfaceName);
2548+
msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED,
2549+
mNetworkInfo);
2550+
msg.sendToTarget();
2551+
}
2552+
2553+
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2554+
SystemClock.elapsedRealtime() +
2555+
mDhcpInfo.leaseDuration * 480,
2556+
mDhcpRenewalIntent);
2557+
} else {
2558+
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
2559+
Log.d(TAG, "DHCP renewal failed: " + NetworkUtils.getDhcpError());
2560+
2561+
synchronized (this) {
2562+
if (!mCancelCallback) {
2563+
mWifiStateTrackerHandler.sendEmptyMessage(event);
2564+
}
2565+
}
2566+
}
24752567
}
24762568

24772569
if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
@@ -2484,17 +2576,15 @@ public void handleMessage(Message msg) {
24842576
WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
24852577
}
24862578

2487-
synchronized (this) {
2488-
if (!mCancelCallback) {
2489-
mTarget.sendEmptyMessage(event);
2490-
}
2491-
}
24922579
break;
24932580
}
24942581
}
24952582

24962583
public synchronized void setCancelCallback(boolean cancelCallback) {
24972584
mCancelCallback = cancelCallback;
2585+
if (cancelCallback) {
2586+
mAlarmManager.cancel(mDhcpRenewalIntent);
2587+
}
24982588
}
24992589

25002590
/**
@@ -2510,6 +2600,7 @@ private boolean shouldDisableCoexistenceMode() {
25102600
int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
25112601
return state == BluetoothHeadset.STATE_DISCONNECTED;
25122602
}
2603+
25132604
}
25142605

25152606
private void checkUseStaticIp() {

0 commit comments

Comments
 (0)