OSDN Git Service

Merge "Add support for background scanning"
authorIrfan Sheriff <isheriff@google.com>
Wed, 23 Feb 2011 18:41:12 +0000 (10:41 -0800)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 23 Feb 2011 18:41:12 +0000 (10:41 -0800)
core/jni/android_net_wifi_Wifi.cpp
core/res/res/values/config.xml
services/java/com/android/server/WifiService.java
wifi/java/android/net/wifi/WifiNative.java
wifi/java/android/net/wifi/WifiStateMachine.java

index fc806a5..667ba75 100644 (file)
@@ -556,6 +556,18 @@ static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, job
     return doBooleanCommand(cmdstr, "OK");
 }
 
+static void android_net_wifi_enableBackgroundScan(JNIEnv* env, jobject clazz, jboolean enable)
+{
+    //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
+    //and will need an update if the names are changed
+    if (enable) {
+        doBooleanCommand("DRIVER BGSCAN-START", "OK");
+    }
+    else {
+        doBooleanCommand("DRIVER BGSCAN-STOP", "OK");
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 /*
@@ -623,6 +635,7 @@ static JNINativeMethod gWifiMethods[] = {
         (void*) android_net_wifi_setSuspendOptimizationsCommand},
     { "setCountryCodeCommand", "(Ljava/lang/String;)Z",
         (void*) android_net_wifi_setCountryCodeCommand},
+    { "enableBackgroundScan", "(Z)V", (void*) android_net_wifi_enableBackgroundScan},
 };
 
 int register_android_net_wifi_WifiManager(JNIEnv* env)
index 0edd33e..ce37943 100644 (file)
     <!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
     <bool translatable="false" name="config_wifi_dual_band_support">false</bool>
 
+    <!-- Boolean indicating whether the wifi chipset supports background scanning mechanism.
+         This mechanism allows the host to remain in suspend state and the dongle to actively
+         scan and wake the host when a configured SSID is detected by the dongle. This chipset
+         capability can provide power savings when wifi needs to be always kept on.
+         The driver commands needed to support the feature are BGSCAN-START and BGSCAN-STOP -->
+    <bool translatable="false" name="config_wifi_background_scan_support">false</bool>
+
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->
index cc25e8d..f9b94a3 100644 (file)
@@ -96,6 +96,9 @@ public class WifiService extends IWifiManager.Stub {
     private boolean mDeviceIdle;
     private int mPluggedType;
 
+    /* Chipset supports background scan */
+    private final boolean mBackgroundScanSupported;
+
     // true if the user enabled Wifi while in airplane mode
     private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
 
@@ -369,6 +372,9 @@ public class WifiService extends IWifiManager.Stub {
                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
         mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
         mNotificationEnabledSettingObserver.register();
+
+        mBackgroundScanSupported = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_wifi_background_scan_support);
     }
 
     /**
@@ -900,6 +906,9 @@ public class WifiService extends IWifiManager.Stub {
                 reportStartWorkSource();
                 evaluateTrafficStatsPolling();
                 mWifiStateMachine.enableRssiPolling(true);
+                if (mBackgroundScanSupported) {
+                    mWifiStateMachine.enableBackgroundScan(false);
+                }
                 mWifiStateMachine.enableAllNetworks();
                 updateWifiState();
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
@@ -909,6 +918,9 @@ public class WifiService extends IWifiManager.Stub {
                 mScreenOff = true;
                 evaluateTrafficStatsPolling();
                 mWifiStateMachine.enableRssiPolling(false);
+                if (mBackgroundScanSupported) {
+                    mWifiStateMachine.enableBackgroundScan(true);
+                }
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
index 39676b0..909605d 100644 (file)
@@ -170,4 +170,6 @@ public class WifiNative {
      * @return the event string sent by the supplicant.
      */
     public native static String waitForEvent();
+
+    public native static void enableBackgroundScan(boolean enable);
 }
index fc42ab8..676218e 100644 (file)
@@ -112,9 +112,11 @@ public class WifiStateMachine extends HierarchicalStateMachine {
     private String mLastBssid;
     private int mLastNetworkId;
     private boolean mEnableRssiPolling = false;
+    private boolean mEnableBackgroundScan = false;
     private int mRssiPollToken = 0;
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
+    private boolean mScanResultIsPending = false;
 
     private boolean mBluetoothConnectionActive = false;
 
@@ -300,6 +302,8 @@ public class WifiStateMachine extends HierarchicalStateMachine {
     static final int CMD_START_WPS                        = 89;
     /* Set the frequency band */
     static final int CMD_SET_FREQUENCY_BAND               = 90;
+    /* Enable background scan for configured networks */
+    static final int CMD_ENABLE_BACKGROUND_SCAN           = 91;
 
     /* Commands from/to the SupplicantStateTracker */
     /* Reset the supplicant state tracker */
@@ -823,6 +827,10 @@ public class WifiStateMachine extends HierarchicalStateMachine {
        sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
     }
 
+    public void enableBackgroundScan(boolean enabled) {
+       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
+    }
+
     public void enableAllNetworks() {
         sendMessage(CMD_ENABLE_ALL_NETWORKS);
     }
@@ -1538,6 +1546,9 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                 case CMD_ENABLE_RSSI_POLL:
                     mEnableRssiPolling = (message.arg1 == 1);
                     break;
+                case CMD_ENABLE_BACKGROUND_SCAN:
+                    mEnableBackgroundScan = (message.arg1 == 1);
+                    break;
                     /* Discard */
                 case CMD_LOAD_DRIVER:
                 case CMD_UNLOAD_DRIVER:
@@ -1973,6 +1984,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                     eventLoggingEnabled = false;
                     setScanResults(WifiNative.scanResultsCommand());
                     sendScanResultsAvailableBroadcast();
+                    mScanResultIsPending = false;
                     break;
                 case CMD_PING_SUPPLICANT:
                     boolean ok = WifiNative.pingCommand();
@@ -2180,6 +2192,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                 case CMD_START_SCAN:
                     eventLoggingEnabled = false;
                     WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+                    mScanResultIsPending = true;
                     break;
                 case CMD_SET_HIGH_PERF_MODE:
                     setHighPerfModeEnabledNative(message.arg1 == 1);
@@ -2681,8 +2694,8 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                      * back to CONNECT_MODE.
                      */
                     WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
-                    WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
-                    break;
+                    /* Have the parent state handle the rest */
+                    return NOT_HANDLED;
                     /* Ignore connection to same network */
                 case CMD_CONNECT_NETWORK:
                     int netId = message.arg1;
@@ -2771,21 +2784,35 @@ public class WifiStateMachine extends HierarchicalStateMachine {
     }
 
     class DisconnectedState extends HierarchicalState {
+        private boolean mAlarmEnabled = false;
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
 
-            /**
-             * In a disconnected state, an infrequent scan that wakes
-             * up the device is needed to ensure a user connects to
-             * an access point on the move
+            /*
+             * We initiate background scanning if it is enabled, otherwise we
+             * initiate an infrequent scan that wakes up the device to ensure
+             * a user connects to an access point on the move
              */
-            long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
+            if (mEnableBackgroundScan) {
+                /* If a regular scan result is pending, do not initiate background
+                 * scan until the scan results are returned. This is needed because
+                 * initiating a background scan will cancel the regular scan and
+                 * scan results will not be returned until background scanning is
+                 * cleared
+                 */
+                if (!mScanResultIsPending) {
+                    WifiNative.enableBackgroundScan(true);
+                }
+            } else {
+                long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
                     Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
 
-            mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
+                mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                     System.currentTimeMillis() + scanMs, scanMs, mScanIntent);
+                mAlarmEnabled = true;
+            }
         }
         @Override
         public boolean processMessage(Message message) {
@@ -2800,6 +2827,10 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                         transitionTo(mScanModeState);
                     }
                     break;
+                case CMD_ENABLE_BACKGROUND_SCAN:
+                    mEnableBackgroundScan = (message.arg1 == 1);
+                    WifiNative.enableBackgroundScan(mEnableBackgroundScan);
+                    break;
                     /* Ignore network disconnect */
                 case NETWORK_DISCONNECTION_EVENT:
                     break;
@@ -2808,6 +2839,20 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
                     /* DriverStartedState does the rest of the handling */
                     return NOT_HANDLED;
+                case CMD_START_SCAN:
+                    /* Disable background scan temporarily during a regular scan */
+                    if (mEnableBackgroundScan) {
+                        WifiNative.enableBackgroundScan(false);
+                    }
+                    /* Handled in parent state */
+                    return NOT_HANDLED;
+                case SCAN_RESULTS_EVENT:
+                    /* Re-enable background scan when a pending scan result is received */
+                    if (mEnableBackgroundScan && mScanResultIsPending) {
+                        WifiNative.enableBackgroundScan(true);
+                    }
+                    /* Handled in parent state */
+                    return NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -2817,7 +2862,14 @@ public class WifiStateMachine extends HierarchicalStateMachine {
 
         @Override
         public void exit() {
-            mAlarmManager.cancel(mScanIntent);
+            /* No need for a background scan upon exit from a disconnected state */
+            if (mEnableBackgroundScan) {
+                WifiNative.enableBackgroundScan(false);
+            }
+            if (mAlarmEnabled) {
+                mAlarmManager.cancel(mScanIntent);
+                mAlarmEnabled = false;
+            }
         }
     }