Fix wake and scan behavior

- Add wakelock for driver start/stop to ensure a wifilock
  acquisition kick starts driver. Also cleaned up state machine
  driver start/stop behavior.
- Add periodic scans when driver is started to ensure wifi
  reconnections when wifilock exists or when user chooses
  never to sleep
- some minor clean up

Change-Id: I844eb70491d5aa2f8c8933b3d8dd01ba237ee534
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 56babdd2..17d4aa4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3297,6 +3297,14 @@
         public static final String WIFI_IDLE_MS = "wifi_idle_ms";
 
         /**
+         * The interval in milliseconds to issue scans when the driver is
+         * started. This is necessary to allow wifi to connect to an
+         * access point when the driver is suspended.
+         * @hide
+         */
+        public static final String WIFI_SCAN_INTERVAL_MS = "wifi_scan_interval_ms";
+
+        /**
          * The interval in milliseconds at which to check packet counts on the
          * mobile data interface when screen is on, to detect possible data
          * connection problems.
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 55b7c9e..1241a7e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -88,8 +88,10 @@
 
     private AlarmManager mAlarmManager;
     private PendingIntent mIdleIntent;
+    private PendingIntent mScanIntent;
     private BluetoothA2dp mBluetoothA2dp;
     private static final int IDLE_REQUEST = 0;
+    private static final int SCAN_REQUEST = 0;
     private boolean mScreenOff;
     private boolean mDeviceIdle;
     private int mPluggedType;
@@ -121,7 +123,13 @@
      * being enabled but not active exceeds the battery drain caused by
      * re-establishing a connection to the mobile data network.
      */
-    private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
+    private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
+
+    /**
+     * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
+     * Settings.Secure value is not present.
+     */
+    private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */
 
     /**
      * Number of allowed radio frequency channels in various regulatory domains.
@@ -132,6 +140,9 @@
     private static final String ACTION_DEVICE_IDLE =
             "com.android.server.WifiManager.action.DEVICE_IDLE";
 
+    private static final String ACTION_START_SCAN =
+        "com.android.server.WifiManager.action.START_SCAN";
+
     private boolean mIsReceiverRegistered = false;
 
 
@@ -202,6 +213,9 @@
         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
 
+        Intent scanIntent = new Intent(ACTION_START_SCAN, null);
+        mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
+
         HandlerThread wifiThread = new HandlerThread("WifiService");
         wifiThread.start();
 
@@ -824,7 +838,7 @@
 
             long idleMillis =
                 Settings.Secure.getLong(mContext.getContentResolver(),
-                                        Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
+                                        Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
             int stayAwakeConditions =
                 Settings.System.getInt(mContext.getContentResolver(),
                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
@@ -837,6 +851,7 @@
                 // because of any locks so clear that tracking immediately.
                 reportStartWorkSource();
                 mWifiStateMachine.enableRssiPolling(true);
+                updateWifiState();
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 Slog.d(TAG, "ACTION_SCREEN_OFF");
                 mScreenOff = true;
@@ -866,12 +881,11 @@
                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
                     }
                 }
-                /* we can return now -- there's nothing to do until we get the idle intent back */
-                return;
             } else if (action.equals(ACTION_DEVICE_IDLE)) {
                 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
                 mDeviceIdle = true;
                 reportStartWorkSource();
+                updateWifiState();
             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
@@ -886,19 +900,15 @@
                     long triggerTime = System.currentTimeMillis() + idleMillis;
                     Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
-                    mPluggedType = pluggedType;
-                    return;
                 }
                 mPluggedType = pluggedType;
             } else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                                BluetoothA2dp.STATE_NOT_PLAYING);
                 mWifiStateMachine.setBluetoothScanMode(state == BluetoothA2dp.STATE_PLAYING);
-            } else {
-                return;
+            } else if (action.equals(ACTION_START_SCAN)) {
+                mWifiStateMachine.startScan(true);
             }
-
-            updateWifiState();
         }
 
         /**
@@ -967,6 +977,10 @@
             strongestLockMode = WifiManager.WIFI_MODE_FULL;
         }
 
+        /* Scan interval when driver is started */
+        long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
+                Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
+
         /* Disable tethering when airplane mode is enabled */
         if (airplaneMode) {
             mWifiStateMachine.setWifiApEnabled(null, false);
@@ -979,9 +993,12 @@
                 mWifiStateMachine.setScanOnlyMode(
                         strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
                 mWifiStateMachine.setDriverStart(true);
+                mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
+                        System.currentTimeMillis() + scanMs, scanMs, mScanIntent);
             } else {
                 mWifiStateMachine.requestCmWakeLock();
                 mWifiStateMachine.setDriverStart(false);
+                mAlarmManager.cancel(mScanIntent);
             }
         } else {
             mWifiStateMachine.setWifiEnabled(false);
@@ -994,6 +1011,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(ACTION_DEVICE_IDLE);
+        intentFilter.addAction(ACTION_START_SCAN);
         intentFilter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter);
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 3a9d272..f2fdbad 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -132,8 +132,8 @@
 
     private LinkProperties mLinkProperties;
 
-    // Held during driver load and unload
-    private static PowerManager.WakeLock sWakeLock;
+    // Wakelock held during wifi start/stop and driver load/unload
+    private PowerManager.WakeLock mWakeLock;
 
     private Context mContext;
 
@@ -469,7 +469,7 @@
         };
 
         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
         addState(mDefaultState);
             addState(mInitialState, mDefaultState);
@@ -624,11 +624,11 @@
      * TODO: doc
      */
     public void setDriverStart(boolean enable) {
-      if (enable) {
-          sendMessage(CMD_START_DRIVER);
-      } else {
-          sendMessage(CMD_STOP_DRIVER);
-      }
+        if (enable) {
+            sendMessage(CMD_START_DRIVER);
+        } else {
+            sendMessage(CMD_STOP_DRIVER);
+        }
     }
 
     /**
@@ -951,6 +951,7 @@
                         mReportedRunning = false;
                     }
                 }
+                mWakeLock.setWorkSource(newSource);
             } catch (RemoteException ignore) {
             }
         }
@@ -1678,7 +1679,7 @@
              */
             new Thread(new Runnable() {
                 public void run() {
-                    sWakeLock.acquire();
+                    mWakeLock.acquire();
                     //enabling state
                     switch(message.arg1) {
                         case WIFI_STATE_ENABLING:
@@ -1704,7 +1705,7 @@
                         }
                         sendMessage(CMD_LOAD_DRIVER_FAILURE);
                     }
-                    sWakeLock.release();
+                    mWakeLock.release();
                 }
             }).start();
         }
@@ -1802,7 +1803,7 @@
             new Thread(new Runnable() {
                 public void run() {
                     if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-                    sWakeLock.acquire();
+                    mWakeLock.acquire();
                     if(WifiNative.unloadDriver()) {
                         Log.d(TAG, "Driver unload successful");
                         sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
@@ -1832,7 +1833,7 @@
                                 break;
                         }
                     }
-                    sWakeLock.release();
+                    mWakeLock.release();
                 }
             }).start();
         }
@@ -1936,7 +1937,7 @@
                     checkIsBluetoothPlaying();
 
                     sendSupplicantConnectionChangedBroadcast(true);
-                    transitionTo(mDriverSupReadyState);
+                    transitionTo(mDriverStartedState);
                     break;
                 case SUP_DISCONNECTION_EVENT:
                     Log.e(TAG, "Failed to setup control channel, restart supplicant");
@@ -2004,11 +2005,6 @@
                     transitionTo(mDriverLoadedState);
                     sendMessageAtFrontOfQueue(CMD_START_SUPPLICANT); /* restart */
                     break;
-                case CMD_START_DRIVER:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    WifiNative.startDriverCommand();
-                    transitionTo(mDriverStartingState);
-                    break;
                 case SCAN_RESULTS_EVENT:
                     setScanResults(WifiNative.scanResultsCommand());
                     sendScanResultsAvailableBroadcast();
@@ -2185,12 +2181,11 @@
                     mNumAllowedChannels = message.arg1;
                     WifiNative.setNumAllowedChannelsCommand(message.arg1);
                     break;
-                case CMD_START_DRIVER:
-                    /* Ignore another driver start */
-                    break;
                 case CMD_STOP_DRIVER:
+                    mWakeLock.acquire();
                     WifiNative.stopDriverCommand();
                     transitionTo(mDriverStoppingState);
+                    mWakeLock.release();
                     break;
                 case CMD_REQUEST_CM_WAKELOCK:
                     if (mCm == null) {
@@ -2266,7 +2261,18 @@
         @Override
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            return NOT_HANDLED;
+            switch (message.what) {
+                case CMD_START_DRIVER:
+                    mWakeLock.acquire();
+                    WifiNative.startDriverCommand();
+                    transitionTo(mDriverStartingState);
+                    mWakeLock.release();
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
         }
     }