2323import static android .net .wifi .WifiManager .WIFI_STATE_UNKNOWN ;
2424
2525import 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 ;
2638import android .net .NetworkInfo ;
2739import android .net .NetworkStateTracker ;
2840import android .net .DhcpInfo ;
3244import android .net .NetworkInfo .State ;
3345import android .os .Message ;
3446import android .os .Parcelable ;
47+ import android .os .PowerManager ;
3548import android .os .Handler ;
3649import android .os .HandlerThread ;
50+ import android .os .SystemClock ;
3751import android .os .SystemProperties ;
3852import android .os .Looper ;
3953import android .os .RemoteException ;
4458import android .util .EventLog ;
4559import android .util .Log ;
4660import 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 ;
5661import com .android .internal .app .IBatteryStats ;
5762
5863import 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