diff options
| -rw-r--r-- | core/jni/android_net_wifi_Wifi.cpp | 14 | ||||
| -rw-r--r-- | core/res/res/values/config.xml | 7 | ||||
| -rw-r--r-- | services/java/com/android/server/WifiService.java | 12 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiNative.java | 2 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 70 |
5 files changed, 95 insertions, 10 deletions
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 3b102996adef..e1b8d298d5c3 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -575,7 +575,6 @@ static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, job return doBooleanCommand(cmdstr, "OK"); } - static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info) { jint ipaddr, gateway, mask, dns1, dns2, server, lease; @@ -598,6 +597,18 @@ static jstring android_net_wifi_getDhcpError(JNIEnv* env, jobject clazz) return env->NewStringUTF(::get_dhcp_error_string()); } +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"); + } +} + // ---------------------------------------------------------------------------- /* @@ -667,6 +678,7 @@ static JNINativeMethod gWifiMethods[] = { (void*) android_net_wifi_setCountryCodeCommand}, { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError }, + { "enableBackgroundScan", "(Z)V", (void*) android_net_wifi_enableBackgroundScan}, }; int register_android_net_wifi_WifiManager(JNIEnv* env) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 713fa8e96284..c4b2adeeedf6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -194,6 +194,13 @@ <!-- 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). --> diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index d2f2ec701910..22583f7b775c 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -94,6 +94,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); @@ -305,6 +308,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); } /** @@ -874,6 +880,9 @@ public class WifiService extends IWifiManager.Stub { // because of any locks so clear that tracking immediately. reportStartWorkSource(); mWifiStateMachine.enableRssiPolling(true); + if (mBackgroundScanSupported) { + mWifiStateMachine.enableBackgroundScan(false); + } mWifiStateMachine.enableAllNetworks(); updateWifiState(); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { @@ -882,6 +891,9 @@ public class WifiService extends IWifiManager.Stub { } mScreenOff = true; 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 diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 030048f09b6e..a113c5cbcfc7 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -176,4 +176,6 @@ public class WifiNative { * @return the event string sent by the supplicant. */ public native static String waitForEvent(); + + public native static void enableBackgroundScan(boolean enable); } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 4d0acdd7044c..65f2a19b2b30 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -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 */ @@ -819,6 +823,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); } @@ -1495,6 +1503,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: @@ -1930,6 +1941,7 @@ public class WifiStateMachine extends HierarchicalStateMachine { eventLoggingEnabled = false; setScanResults(WifiNative.scanResultsCommand()); sendScanResultsAvailableBroadcast(); + mScanResultIsPending = false; break; case CMD_PING_SUPPLICANT: boolean ok = WifiNative.pingCommand(); @@ -2137,6 +2149,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); @@ -2626,8 +2639,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; @@ -2716,21 +2729,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) { @@ -2745,6 +2772,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; @@ -2753,6 +2784,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; } @@ -2762,7 +2807,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; + } } } |