diff options
Diffstat (limited to 'service')
4 files changed, 367 insertions, 105 deletions
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java index a971dcd56..cd71f487c 100644 --- a/service/java/com/android/server/wifi/WifiAutoJoinController.java +++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java @@ -158,6 +158,7 @@ public class WifiAutoJoinController { int numScanResultsKnown = 0; // Record number of scan results we knew about WifiConfiguration associatedConfig = null; boolean didAssociate = false; + long now = System.currentTimeMillis(); ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>(); @@ -224,7 +225,11 @@ public class WifiAutoJoinController { if (associatedConfig != null && associatedConfig.SSID != null) { if (VDBG) { logDbg("addToScanCache save associated config " - + associatedConfig.SSID + " with " + result.SSID); + + associatedConfig.SSID + " with " + result.SSID + + " status " + associatedConfig.autoJoinStatus + + " reason " + associatedConfig.disableReason + + " tsp " + associatedConfig.blackListTimestamp + + " was " + (now - associatedConfig.blackListTimestamp)); } mWifiStateMachine.sendMessage( WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig); @@ -232,7 +237,6 @@ public class WifiAutoJoinController { } } else { // If the scan result has been blacklisted fir 18 hours -> unblacklist - long now = System.currentTimeMillis(); if ((now - result.blackListTimestamp) > loseBlackListHardMilli) { result.setAutoJoinStatus(ScanResult.ENABLED); } @@ -1129,6 +1133,8 @@ public class WifiAutoJoinController { didBailDueToWeakRssi = false; int networkSwitchType = AUTO_JOIN_IDLE; + long now = System.currentTimeMillis(); + String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration(); // Reset the currentConfiguration Key, and set it only if WifiStateMachine and @@ -1261,19 +1267,52 @@ public class WifiAutoJoinController { if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { + // Wait for 5 minutes before reenabling config that have known, + // repeated connection or DHCP failures + if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE + || config.disableReason + == WifiConfiguration.DISABLED_ASSOCIATION_REJECT + || config.disableReason + == WifiConfiguration.DISABLED_AUTH_FAILURE) { + if (config.blackListTimestamp == 0 + || (config.blackListTimestamp > now)) { + // Sanitize the timestamp + config.blackListTimestamp = now; + } + if ((now - config.blackListTimestamp) > + mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) { + // Re-enable the WifiConfiguration + config.status = WifiConfiguration.Status.ENABLED; + + // Reset the blacklist condition + config.numConnectionFailures = 0; + config.numIpConfigFailures = 0; + config.numAuthFailures = 0; + config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); + + config.dirty = true; + } else { + if (VDBG) { + long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli + - (now - config.blackListTimestamp); + logDbg("attemptautoJoin " + config.configKey() + + " dont unblacklist yet, waiting for " + + delay + " ms"); + } + } + } // Avoid networks disabled because of AUTH failure altogether if (DBG) { logDbg("attemptAutoJoin skip candidate due to auto join status " + Integer.toString(config.autoJoinStatus) + " key " + config.configKey(true) - + " reason " + config.disableReason); + + " reason " + config.disableReason); } continue; } // Try to un-blacklist based on elapsed time if (config.blackListTimestamp > 0) { - long now = System.currentTimeMillis(); if (now < config.blackListTimestamp) { /** * looks like there was a change in the system clock since we black listed, and @@ -1489,6 +1528,11 @@ public class WifiAutoJoinController { !isOpenNetwork(result)) { continue; } + if (mWifiConfigStore.mDeletedEphemeralSSIDs.contains + ("\"" + result.SSID + "\"")) { + // SSID had been Forgotten by user, then don't score it + continue; + } if ((nowMs - result.seen) < mScanResultAutoJoinAge) { // Increment usage count for the network mWifiConnectionStatistics.incrementOrAddUntrusted(result.SSID, 0, 1); diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index c7b8ab301..9d5844523 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -158,6 +158,15 @@ public class WifiConfigStore extends IpConfigStore { */ private Set<Long> mDeletedSSIDs = new HashSet<Long>(); + /** + * Framework keeps a list of ephemeral SSIDs that where deleted by user, + * so as, framework knows not to autojoin again those SSIDs based on scorer input. + * The list is never cleared up. + * + * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. + */ + public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); + /* Tracks the highest priority of configured networks */ private int mLastPriority = -1; @@ -209,6 +218,7 @@ public class WifiConfigStore extends IpConfigStore { private static final String EPHEMERAL_KEY = "EPHEMERAL: "; private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION: "; private static final String DELETED_CRC32_KEY = "DELETED_CRC32: "; + private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL: "; private static final String JOIN_ATTEMPT_BOOST_KEY = "JOIN_ATTEMPT_BOOST: "; private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY @@ -346,6 +356,9 @@ public class WifiConfigStore extends IpConfigStore { public int maxConnectionErrorsToBlacklist = 4; public int wifiConfigBlacklistMinTimeMilli = 1000 * 60 * 5; + // How long a disconnected config remain considered as the last user selection + public int wifiConfigLastSelectionHysteresis = 1000 * 60 * 3; + // Boost RSSI values of associated networks public int associatedHysteresisHigh = +14; public int associatedHysteresisLow = +8; @@ -730,7 +743,7 @@ public class WifiConfigStore extends IpConfigStore { && (config.autoJoinStatus <= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { - // Wait for 20 minutes before reenabling config that have known, repeated connection + // Wait for 5 minutes before reenabling config that have known, repeated connection // or DHCP failures if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE || config.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT @@ -830,6 +843,15 @@ public class WifiConfigStore extends IpConfigStore { + " Uid=" + Integer.toString(config.creatorUid) + "/" + Integer.toString(config.lastUpdateUid)); } + + if (mDeletedEphemeralSSIDs.remove(config.SSID)) { + if (VDBG) { + loge("WifiConfigStore: removed from ephemeral blacklist: " + config.SSID); + } + // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call + // below, since we're creating/modifying a config. + } + boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); int netId = result.getNetworkId(); @@ -947,6 +969,42 @@ public class WifiConfigStore extends IpConfigStore { } } + + /** + * Disable an ephemeral SSID for the purpose of auto-joining thru scored. + * This SSID will never be scored anymore. + * The only way to "un-disable it" is if the user create a network for that SSID and then + * forget it. + * + * @param SSID caller must ensure that the SSID passed thru this API match + * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. + * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can + * disconnect if this is the current network. + */ + WifiConfiguration disableEphemeralNetwork(String SSID) { + if (SSID == null) { + return null; + } + + WifiConfiguration foundConfig = null; + + mDeletedEphemeralSSIDs.add(SSID); + loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size()); + + for (WifiConfiguration config : mConfiguredNetworks.values()) { + if (SSID.equals(config.SSID) && config.ephemeral) { + loge("Found ephemeral config in disableEphemeralNetwork: " + config.networkId); + foundConfig = config; + } + } + + // Force a write, because the mDeletedEphemeralSSIDs list has changed even though the + // configurations may not have. + writeKnownNetworkHistory(true); + + return foundConfig; + } + /** * Forget the specified network and save config * @@ -1719,6 +1777,13 @@ public class WifiConfigStore extends IpConfigStore { out.writeUTF(SEPARATOR_KEY); } } + if (mDeletedEphemeralSSIDs != null && mDeletedEphemeralSSIDs.size() > 0) { + for (String ssid : mDeletedEphemeralSSIDs) { + out.writeUTF(DELETED_EPHEMERAL_KEY); + out.writeUTF(ssid); + out.writeUTF(SEPARATOR_KEY); + } + } } }); } @@ -2049,6 +2114,13 @@ public class WifiConfigStore extends IpConfigStore { Long c = Long.parseLong(crc); mDeletedSSIDs.add(c); } + if (key.startsWith(DELETED_EPHEMERAL_KEY)) { + String s = key.replace(DELETED_EPHEMERAL_KEY, ""); + if (!TextUtils.isEmpty(s)) { + s = s.replace(SEPARATOR_KEY, ""); + mDeletedEphemeralSSIDs.add(s); + } + } } } } @@ -3066,8 +3138,9 @@ public class WifiConfigStore extends IpConfigStore { // Try to make a non verified WifiConfiguration, but only if the original // configuration was not self already added if (VDBG) { - loge("associateWithConfiguration: will create " + - result.SSID + " and associate it with: " + link.SSID); + loge("associateWithConfiguration: try to create " + + result.SSID + " and associate it with: " + link.SSID + + " key " + link.configKey()); } config = wifiConfigurationFromScanResult(result); if (config != null) { @@ -3077,6 +3150,10 @@ public class WifiConfigStore extends IpConfigStore { config.peerWifiConfiguration = link.configKey(); if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { + if (VDBG && config != null) { + loge("associateWithConfiguration: got a config from beacon" + + config.SSID + " key " + config.configKey()); + } // Transfer the credentials from the configuration we are linking from String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); if (psk != null) { @@ -3108,6 +3185,10 @@ public class WifiConfigStore extends IpConfigStore { } if (config != null) break; } + if (VDBG && config != null) { + loge("associateWithConfiguration: success, created: " + config.SSID + + " key " + config.configKey()); + } } } return config; diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 8066b4c4b..cc5824e67 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -1313,6 +1313,14 @@ public final class WifiServiceImpl extends IWifiManager.Stub { return new Messenger(mClientHandler); } + /** + * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer + */ + public void disableEphemeralNetwork(String SSID) { + enforceAccessPermission(); + enforceChangePermission(); + mWifiStateMachine.disableEphemeralNetwork(SSID); + } /** * Get the IP and proxy configuration file diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 09920f5d1..a1ff29484 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -578,6 +578,9 @@ public class WifiStateMachine extends StateMachine { /* Disconnecting state watchdog */ static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96; + /* Disable an ephemeral network */ + static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98; + /* P2p commands */ /* We are ok with no response here since we wont do much with it anyway */ public static final int CMD_ENABLE_P2P = BASE + 131; @@ -862,6 +865,8 @@ public class WifiStateMachine extends StateMachine { // Used for debug and stats gathering private static int sScanAlarmIntentCount = 0; + final static int frameworkMinScanIntervalSaneValue = 10000; + public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller){ super("WifiStateMachine"); @@ -910,9 +915,13 @@ public class WifiStateMachine extends StateMachine { mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST); mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0); - mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( + // Make sure the interval is not configured less than 10 seconds + int period = mContext.getResources().getInteger( R.integer.config_wifi_framework_scan_interval); - + if (period < frameworkMinScanIntervalSaneValue) { + period = frameworkMinScanIntervalSaneValue; + } + mDefaultFrameworkScanIntervalMs = period; mDriverStopDelayMs = mContext.getResources().getInteger( R.integer.config_wifi_driver_stop_delay); @@ -949,10 +958,10 @@ public class WifiStateMachine extends StateMachine { new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - sScanAlarmIntentCount++; - startScan(SCAN_ALARM_SOURCE, -2, null, null); + sScanAlarmIntentCount++; // Used for debug only + startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null); if (VDBG) - loge("WiFiStateMachine SCAN ALARM"); + loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get()); } }, new IntentFilter(ACTION_START_SCAN)); @@ -1123,35 +1132,27 @@ public class WifiStateMachine extends StateMachine { */ private long mFrameworkScanIntervalMs = 10000; - private long mCurrentScanAlarmMs = 10000; - private void setScanAlarm(boolean enabled, int delayMilli) { + private AtomicInteger mDelayedScanCounter = new AtomicInteger(); + + private void setScanAlarm(boolean enabled) { if (PDBG) { loge("setScanAlarm " + enabled - + " period " + mCurrentScanAlarmMs - + " initial delay " + delayMilli); + + " period " + mDefaultFrameworkScanIntervalMs + + " mBackgroundScanSupported " + mBackgroundScanSupported); + } + if (mBackgroundScanSupported == false) { + // Scan alarm is only used for background scans if they are not + // offloaded to the wifi chipset, hence enable the scan alarm + // gicing us RTC_WAKEUP of backgroundScan is NOT supported + enabled = true; } - if (mCurrentScanAlarmMs <= 0) enabled = false; + if (enabled == mAlarmEnabled) return; if (enabled) { - long initialDelayMilli; - if (delayMilli <= 0) { - // scan now - startScan(SCAN_ALARM_SOURCE, 0, null, null); - initialDelayMilli = mCurrentScanAlarmMs; - } else { - initialDelayMilli = delayMilli; - } - - int type = AlarmManager.RTC; - /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */ /* going to wake up the host processor to look for access points */ - if (mBackgroundScanSupported == false) - type = AlarmManager.RTC_WAKEUP; - - mAlarmManager.setRepeating(type, - System.currentTimeMillis() + initialDelayMilli, - mCurrentScanAlarmMs, + mAlarmManager.set(AlarmManager.RTC_WAKEUP, + System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs, mScanIntent); mAlarmEnabled = true; } else { @@ -1160,6 +1161,53 @@ public class WifiStateMachine extends StateMachine { } } + private void cancelDelayedScan() { + mDelayedScanCounter.incrementAndGet(); + loge("cancelDelayedScan -> " + mDelayedScanCounter); + } + + private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli, + ScanSettings settings, WorkSource workSource) { + if (counter != mDelayedScanCounter.get()) { + return false; + } + if (restart) + startDelayedScan(milli, settings, workSource); + return true; + } + + private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) { + if (milli <= 0) return; + /** + * The cases where the scan alarm should be run are : + * - DisconnectedState && screenOn => used delayed timer + * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO + * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm + * - ConnectedState && screenOn => used delayed timer + */ + + mDelayedScanCounter.incrementAndGet(); + if (mScreenOn && + (getCurrentState() == mDisconnectedState + || getCurrentState() == mConnectedState)) { + Bundle bundle = new Bundle(); + bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); + bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); + bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); + sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE, + mDelayedScanCounter.get(), bundle, milli); + if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli); + } else if (mBackgroundScanSupported == false + && !mScreenOn && getCurrentState() == mDisconnectedState) { + setScanAlarm(true); + if (DBG) loge("startDelayedScan start scan alarm -> " + + mDelayedScanCounter + " milli " + milli); + } else { + if (DBG) loge("startDelayedScan unhandled -> " + + mDelayedScanCounter + " milli " + milli); + } + } + private boolean setRandomMacOui() { String oui = mContext.getResources().getString( R.string.config_wifi_random_mac_oui, GOOGLE_OUI); @@ -1592,7 +1640,7 @@ public class WifiStateMachine extends StateMachine { private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0; private static int MESSAGE_HANDLING_STATUS_REFUSED = -1; private static int MESSAGE_HANDLING_STATUS_FAIL = -2; - private static int MESSAGE_HANDLING_STATUS_BUFFERED = -3; + private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3; private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4; private static int MESSAGE_HANDLING_STATUS_DISCARD = -5; private static int MESSAGE_HANDLING_STATUS_LOOPED = -6; @@ -1602,9 +1650,11 @@ public class WifiStateMachine extends StateMachine { //TODO: this is used only to track connection attempts, however the link state and packet per //TODO: second logic should be folded into that - private boolean isScanAllowed() { + private boolean checkOrDeferScanAllowed(Message msg) { long now = System.currentTimeMillis(); if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { + Message dmsg = Message.obtain(msg); + sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttempt)); return false; } return true; @@ -1667,7 +1717,6 @@ public class WifiStateMachine extends StateMachine { mRxTime = stats.rx_time; mRunningBeaconCount = stats.beacon_rx; if (dbg) { - loge("WifiLinkLayerStats:"); loge(stats.toString()); } } @@ -1717,7 +1766,8 @@ public class WifiStateMachine extends StateMachine { loge(ts + " noteScanStart" + workSource.toString() + " uid " + Integer.toString(callingUid)); } else { - loge(ts + " noteScanstart no scan source"); + loge(ts + " noteScanstart no scan source" + + " uid " + Integer.toString(callingUid)); } } startRadioScanStats(); @@ -1742,9 +1792,11 @@ public class WifiStateMachine extends StateMachine { if (DBG) { String ts = String.format("[%,d ms]", now); if (mScanWorkSource != null) - loge(ts + " noteScanEnd " + mScanWorkSource.toString()); + loge(ts + " noteScanEnd " + mScanWorkSource.toString() + + " onTime=" + mOnTimeThisScan); else - loge(ts + " noteScanEnd no scan source"); + loge(ts + " noteScanEnd no scan source" + + " onTime=" + mOnTimeThisScan); } if (mScanWorkSource != null) { try { @@ -2019,6 +2071,12 @@ public class WifiStateMachine extends StateMachine { } } + public void disableEphemeralNetwork(String SSID) { + if (SSID != null) { + sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID); + } + } + /** * Get unsynchronized pointer to scan result list * Can be called only from AutoJoinController which runs in the WifiStateMachine context @@ -2412,6 +2470,7 @@ public class WifiStateMachine extends StateMachine { WifiConfiguration config; Long now; String report; + String key; StringBuilder sb = new StringBuilder(); if (mScreenOn) { sb.append("!"); @@ -2448,6 +2507,7 @@ public class WifiStateMachine extends StateMachine { if (lastScanDuration != 0) { sb.append(" dur:").append(lastScanDuration); } + sb.append(" cnt=").append(mDelayedScanCounter); sb.append(" rssi=").append(mWifiInfo.getRssi()); sb.append(" f=").append(mWifiInfo.getFrequency()); sb.append(" sc=").append(mWifiInfo.score); @@ -2568,6 +2628,11 @@ public class WifiStateMachine extends StateMachine { sb.append(",").append(mRxTime); } sb.append(String.format(" bcn=%d", mRunningBeaconCount)); + sb.append(String.format(" con=%d", mConnectionRequests)); + key = mWifiConfigStore.getLastSelectedConfiguration(); + if (key != null) { + sb.append(" last=").append(key); + } break; case WifiMonitor.NETWORK_CONNECTION_EVENT: sb.append(" "); @@ -2581,6 +2646,10 @@ public class WifiStateMachine extends StateMachine { sb.append(" ").append(config.configKey()); } sb.append(printTime()); + key = mWifiConfigStore.getLastSelectedConfiguration(); + if (key != null) { + sb.append(" last=").append(key); + } break; case CMD_TARGET_BSSID: case CMD_ASSOCIATED_BSSID: @@ -2764,7 +2833,7 @@ public class WifiStateMachine extends StateMachine { sb.append(Integer.toString(msg.arg1)); sb.append(" "); sb.append(Integer.toString(msg.arg2)); - String key = mWifiConfigStore.getLastSelectedConfiguration(); + key = mWifiConfigStore.getLastSelectedConfiguration(); if (key != null) { sb.append(" last=").append(key); } @@ -2934,7 +3003,6 @@ public class WifiStateMachine extends StateMachine { mScreenOn = screenOn; if (PDBG) { loge(" handleScreenStateChanged Enter: screenOn=" + screenOn - + " mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt + " state " + getCurrentState().getName() + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); @@ -2955,38 +3023,41 @@ public class WifiStateMachine extends StateMachine { getWifiLinkLayerStats(false); mOnTimeScreenStateChange = mOnTime; lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate; + mEnableBackgroundScan = false; + cancelDelayedScan(); if (screenOn) { + setScanAlarm(false); clearBlacklist(); fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Start the scan alarm so as to enable autojoin + // In either Disconnectedstate or ConnectedState, + // start the scan alarm so as to enable autojoin if (getCurrentState() == mConnectedState && mWifiConfigStore.enableAutoJoinScanWhenAssociated) { - mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Scan after 200ms - setScanAlarm(true, 200); + // Scan after 500ms + startDelayedScan(500, null, null); } else if (getCurrentState() == mDisconnectedState) { - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; // Scan after 200ms - setScanAlarm(true, 200); + startDelayedScan(200, null, null); + } + } else if (startBackgroundScanIfNeeded) { + // Screen Off and Disconnected and chipset doesn't support scan offload + // => start scan alarm + // Screen Off and Disconnected and chipset does support scan offload + // => will use scan offload (i.e. background scan) + if (!mBackgroundScanSupported) { + setScanAlarm(true); + } else { + mEnableBackgroundScan = true; } - } else { - setScanAlarm(false, 0); } - - if (mBackgroundScanSupported) { - mEnableBackgroundScan = (screenOn == false); - } - if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded); - if (startBackgroundScanIfNeeded) { // to scan for them in background, we need all networks enabled enableBackgroundScan(mEnableBackgroundScan); } - if (DBG) log("handleScreenStateChanged Exit: " + screenOn); } @@ -3381,16 +3452,21 @@ public class WifiStateMachine extends StateMachine { attemptAutoJoin = false; } if (DBG) { + String selection = mWifiConfigStore.getLastSelectedConfiguration(); + if (selection == null) { + selection = "<none>"; + } loge("wifi setScanResults state" + getCurrentState() + " sup_state=" + state + " debouncing=" + linkDebouncing - + " mConnectionRequests=" + mConnectionRequests); + + " mConnectionRequests=" + mConnectionRequests + + " selection=" + selection); } if (attemptAutoJoin) { messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED; } - // Loose last selected configuration if we have been disconnected for 30 minutes - if (getDisconnectedTimeMilli() > 1000 * 60 * 30) { + // Loose last selected configuration if we have been disconnected for 5 minutes + if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) { mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); } @@ -4220,7 +4296,14 @@ public class WifiStateMachine extends StateMachine { linkDebouncing = false; /* Reset roaming parameters */ mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; - fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval + + /** + * fullBandConnectedTimeIntervalMilli: + * - start scans at mWifiConfigStore.associatedPartialScanPeriodMilli seconds interval + * - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli + * Initialize to sane value = 20 seconds + */ + fullBandConnectedTimeIntervalMilli = 20 * 1000; setNetworkDetailedState(DetailedState.DISCONNECTED); if (mNetworkAgent != null) { @@ -4713,6 +4796,7 @@ public class WifiStateMachine extends StateMachine { case CMD_UNWANTED_NETWORK: case CMD_DISCONNECTING_WATCHDOG_TIMER: case CMD_ROAM_WATCHDOG_TIMER: + case CMD_DISABLE_EPHEMERAL_NETWORK: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; break; case DhcpStateMachine.CMD_ON_QUIT: @@ -5057,6 +5141,8 @@ public class WifiStateMachine extends StateMachine { break; case CMD_SET_OPERATIONAL_MODE: mOperationalMode = message.arg1; + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); break; case CMD_TARGET_BSSID: // Trying to associate to this BSSID @@ -5227,7 +5313,7 @@ public class WifiStateMachine extends StateMachine { public void enter() { if (PDBG) { - loge("Driverstarted State enter"); + loge("DriverStartedState enter"); } mIsRunning = true; mInDelayedStop = false; @@ -5643,6 +5729,10 @@ public class WifiStateMachine extends StateMachine { startScan(ENABLE_WIFI, 0, null, null); } + // Loose last selection choice since user toggled WiFi + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); + mOperationalMode = CONNECT_MODE; transitionTo(mDisconnectedState); } else { @@ -5691,6 +5781,9 @@ public class WifiStateMachine extends StateMachine { case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; break; + case CMD_DISABLE_EPHEMERAL_NETWORK: + s = "CMD_DISABLE_EPHEMERAL_NETWORK"; + break; case CMD_START_DRIVER: s = "CMD_START_DRIVER"; break; @@ -6025,6 +6118,10 @@ public class WifiStateMachine extends StateMachine { WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); if (config != null) { config.lastDisconnected = System.currentTimeMillis(); + if (config.ephemeral) { + // Remove ephemeral WifiConfigurations from file + mWifiConfigStore.forgetNetwork(mLastNetworkId); + } } } } @@ -6240,6 +6337,15 @@ public class WifiStateMachine extends StateMachine { WifiManager.ERROR); } break; + case CMD_DISABLE_EPHEMERAL_NETWORK: + config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj); + if (config != null) { + if (config.networkId == mLastNetworkId) { + // Disconnect and let autojoin reselect a new network + sendMessage(CMD_DISCONNECT); + } + } + break; case CMD_BLACKLIST_NETWORK: mWifiNative.addToBlacklist((String) message.obj); break; @@ -6877,6 +6983,8 @@ public class WifiStateMachine extends StateMachine { if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) { noteWifiDisabledWhileAssociated(); } + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); } break; case CMD_SET_COUNTRY_CODE: @@ -6892,6 +7000,20 @@ public class WifiStateMachine extends StateMachine { + " RSSI=" + mWifiInfo.getRssi()); //} if (message.arg1 == SCAN_ALARM_SOURCE) { + // Check if the CMD_START_SCAN message is obsolete (and thus if it should + // not be processed) and restart the scan if needed + boolean shouldScan = + mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated; + if (!checkAndRestartDelayedScan(message.arg2, + shouldScan, + mWifiConfigStore.associatedPartialScanPeriodMilli, null, null)) { + messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; + loge("WifiStateMachine L2Connected CMD_START_SCAN source " + + message.arg1 + + " " + message.arg2 + ", " + mDelayedScanCounter + + " -> obsolete"); + return HANDLED; + } boolean tryFullBandScan = false; boolean restrictChannelList = false; long now_ms = System.currentTimeMillis(); @@ -6997,13 +7119,14 @@ public class WifiStateMachine extends StateMachine { WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); } } + } else { loge("CMD_START_SCAN : connected mode and no configuration"); messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; } } else { // Not scan alarm source - handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + return NOT_HANDLED; } break; /* Ignore connection to same network */ @@ -7147,6 +7270,8 @@ public class WifiStateMachine extends StateMachine { } obtainingIpWatchdogCount++; loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); + // Get Link layer stats so as we get fresh tx packet counters + getWifiLinkLayerStats(true); sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); } else { @@ -7283,7 +7408,7 @@ public class WifiStateMachine extends StateMachine { log("RoamingState Enter" + " mScreenOn=" + mScreenOn ); } - setScanAlarm(false, 0); + setScanAlarm(false); // Make sure we disconnect if roaming fails roamWatchdogCount++; @@ -7414,11 +7539,8 @@ public class WifiStateMachine extends StateMachine { } if (mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated) { - mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Scan after 200ms - setScanAlarm(true, 200); - } else { - mCurrentScanAlarmMs = 0; + // restart scan alarm + startDelayedScan(mWifiConfigStore.associatedPartialScanPeriodMilli, null, null); } registerConnected(); lastConnectAttempt = 0; @@ -7619,7 +7741,7 @@ public class WifiStateMachine extends StateMachine { @Override public void exit() { loge("WifiStateMachine: Leaving Connected state"); - setScanAlarm(false, 0); + setScanAlarm(false); mLastDriverRoamAttempt = 0; } } @@ -7628,7 +7750,6 @@ public class WifiStateMachine extends StateMachine { @Override public void enter() { - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; if (PDBG) { loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs @@ -7658,7 +7779,7 @@ public class WifiStateMachine extends StateMachine { } break; case CMD_START_SCAN: - // Ignore scans while disconnecting + deferMessage(message); return HANDLED; case CMD_DISCONNECTING_WATCHDOG_TIMER: if (disconnectingWatchdogCount == message.arg1) { @@ -7682,11 +7803,6 @@ public class WifiStateMachine extends StateMachine { } return HANDLED; } - - @Override - public void exit() { - mCurrentScanAlarmMs = 0; - } } class DisconnectedState extends State { @@ -7699,17 +7815,10 @@ public class WifiStateMachine extends StateMachine { return; } - // Loose the last selection choice - // mWifiAutoJoinController.setLastSelectedConfiguration - // (WifiConfiguration.INVALID_NETWORK_ID); - mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, mDefaultFrameworkScanIntervalMs); - if (mScreenOn) - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; - if (PDBG) { loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs + " mEnableBackgroundScan= " + mEnableBackgroundScan @@ -7720,23 +7829,28 @@ public class WifiStateMachine extends StateMachine { /** clear the roaming state, if we were roaming, we failed */ mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; - /** - * - screen dark and PNO supported => scan alarm disabled - * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period - */ - if ((mScreenOn == false) && 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 (mScreenOn) { + /** + * screen lit and => delayed timer */ - if (!mIsScanOngoing) { - enableBackgroundScan(true); - } + startDelayedScan(mDisconnectedScanPeriodMs, null, null); } else { - setScanAlarm(true, 200); + /** + * screen dark and PNO supported => scan alarm disabled + */ + 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 (!mIsScanOngoing) { + enableBackgroundScan(true); + } + } else { + setScanAlarm(true); + } } /** @@ -7805,16 +7919,32 @@ public class WifiStateMachine extends StateMachine { ret = NOT_HANDLED; break; case CMD_START_SCAN: - if (!isScanAllowed()) { - // Ignore the scan request + if (!checkOrDeferScanAllowed(message)) { + // The scan request was rescheduled + messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; return HANDLED; } /* Disable background scan temporarily during a regular scan */ if (mEnableBackgroundScan) { enableBackgroundScan(false); } - /* Handled in parent state */ - ret = NOT_HANDLED; + if (message.arg1 == SCAN_ALARM_SOURCE) { + // Check if the CMD_START_SCAN message is obsolete (and thus if it should + // not be processed) and restart the scan + if (!checkAndRestartDelayedScan(message.arg2, + true, mDisconnectedScanPeriodMs, null, null)) { + messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; + loge("WifiStateMachine Disconnected CMD_START_SCAN source " + + message.arg1 + + " " + message.arg2 + ", " + mDelayedScanCounter + + " -> obsolete"); + return HANDLED; + } + handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + ret = HANDLED; + } else { + ret = NOT_HANDLED; + } break; case WifiMonitor.SCAN_RESULTS_EVENT: /* Re-enable background scan when a pending scan result is received */ @@ -7866,8 +7996,7 @@ public class WifiStateMachine extends StateMachine { if (mEnableBackgroundScan) { enableBackgroundScan(false); } - mCurrentScanAlarmMs = 0; - setScanAlarm(false, 0); + setScanAlarm(false); } } |