diff options
6 files changed, 138 insertions, 9 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index a4eb8eaf1..42fa19155 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -2792,6 +2792,12 @@ public class ClientModeImpl extends StateMachine { + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); } + WifiConfiguration wifiConfig = getCurrentWifiConfiguration(); + if (wifiConfig != null) { + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromWifiConfiguration(wifiConfig); + mWifiInjector.getWakeupController().setLastDisconnectInfo(matchInfo); + } + stopRssiMonitoringOffload(); clearTargetBssid("handleNetworkDisconnect"); diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java index c911e96eb..5c81a3bb0 100644 --- a/service/java/com/android/server/wifi/WakeupController.java +++ b/service/java/com/android/server/wifi/WakeupController.java @@ -62,6 +62,7 @@ public class WakeupController { private final WifiInjector mWifiInjector; private final WakeupConfigStoreData mWakeupConfigStoreData; private final WifiWakeMetrics mWifiWakeMetrics; + private final Clock mClock; private final WifiScanner.ScanListener mScanListener = new WifiScanner.ScanListener() { @Override @@ -104,6 +105,20 @@ public class WakeupController { /** Whether Wifi verbose logging is enabled. */ private boolean mVerboseLoggingEnabled; + /** + * The timestamp of when the Wifi network was last disconnected (either device disconnected + * from the network or Wifi was turned off entirely). + * Note: mLastDisconnectTimestampMillis and mLastDisconnectInfo must always be updated together. + */ + private long mLastDisconnectTimestampMillis; + + /** + * The SSID of the last Wifi network the device was connected to (either device disconnected + * from the network or Wifi was turned off entirely). + * Note: mLastDisconnectTimestampMillis and mLastDisconnectInfo must always be updated together. + */ + private ScanResultMatchInfo mLastDisconnectInfo; + public WakeupController( Context context, Looper looper, @@ -114,7 +129,8 @@ public class WakeupController { WifiConfigStore wifiConfigStore, WifiWakeMetrics wifiWakeMetrics, WifiInjector wifiInjector, - FrameworkFacade frameworkFacade) { + FrameworkFacade frameworkFacade, + Clock clock) { mContext = context; mHandler = new Handler(looper); mWakeupLock = wakeupLock; @@ -143,6 +159,9 @@ public class WakeupController { mWakeupOnboarding.getNotificationsDataSource(), mWakeupLock.getDataSource()); wifiConfigStore.registerStoreData(mWakeupConfigStoreData); + mClock = clock; + mLastDisconnectTimestampMillis = 0; + mLastDisconnectInfo = null; } private void readWifiWakeupEnabledFromSettings() { @@ -160,6 +179,39 @@ public class WakeupController { } /** + * Saves the SSID of the last Wifi network that was disconnected. Should only be called before + * WakeupController is active. + */ + public void setLastDisconnectInfo(ScanResultMatchInfo scanResultMatchInfo) { + if (mIsActive) { + Log.e(TAG, "Unexpected setLastDisconnectInfo when WakeupController is active!"); + return; + } + if (scanResultMatchInfo == null) { + Log.e(TAG, "Unexpected setLastDisconnectInfo(null)"); + return; + } + mLastDisconnectTimestampMillis = mClock.getElapsedSinceBootMillis(); + mLastDisconnectInfo = scanResultMatchInfo; + if (mVerboseLoggingEnabled) { + Log.d(TAG, "mLastDisconnectInfo set to " + scanResultMatchInfo); + } + } + + /** + * If Wifi was disabled within LAST_DISCONNECT_TIMEOUT_MILLIS of losing a Wifi connection, + * add that Wifi connection to the Wakeup Lock as if Wifi was disabled while connected to that + * connection. + * Often times, networks with poor signal intermittently connect and disconnect, causing the + * user to manually turn off Wifi. If the Wifi was turned off during the disconnected phase of + * the intermittent connection, then that connection normally would not be added to the Wakeup + * Lock. This constant defines the timeout after disconnecting, in milliseconds, within which + * if Wifi was disabled, the network would still be added to the wakeup lock. + */ + @VisibleForTesting + static final long LAST_DISCONNECT_TIMEOUT_MILLIS = 5 * 1000; + + /** * Starts listening for incoming scans. * * <p>Should only be called upon entering ScanMode. WakeupController registers its listener with @@ -186,6 +238,18 @@ public class WakeupController { Set<ScanResultMatchInfo> matchInfos = toMatchInfos(scanResults); matchInfos.retainAll(getGoodSavedNetworks()); + // ensure that the last disconnected network is added to the wakeup lock, since we don't + // want to automatically reconnect to the same network that the user manually + // disconnected from + long now = mClock.getElapsedSinceBootMillis(); + if (mLastDisconnectInfo != null && ((now - mLastDisconnectTimestampMillis) + <= LAST_DISCONNECT_TIMEOUT_MILLIS)) { + matchInfos.add(mLastDisconnectInfo); + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Added last connected network to lock: " + mLastDisconnectInfo); + } + } + if (mVerboseLoggingEnabled) { Log.d(TAG, "Saved networks in most recent scan:" + matchInfos); } @@ -204,6 +268,8 @@ public class WakeupController { */ public void stop() { Log.d(TAG, "stop()"); + mLastDisconnectTimestampMillis = 0; + mLastDisconnectInfo = null; mWifiInjector.getWifiScanner().deregisterScanListener(mScanListener); mWakeupOnboarding.onStop(); } diff --git a/service/java/com/android/server/wifi/WakeupLock.java b/service/java/com/android/server/wifi/WakeupLock.java index c6a8f5a34..3a1d097fc 100644 --- a/service/java/com/android/server/wifi/WakeupLock.java +++ b/service/java/com/android/server/wifi/WakeupLock.java @@ -39,7 +39,7 @@ public class WakeupLock { private static final String TAG = WakeupLock.class.getSimpleName(); @VisibleForTesting - static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 3; + static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 5; @VisibleForTesting static final long MAX_LOCK_TIME_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS; diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 24e125a29..5d54fa7e7 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -280,7 +280,8 @@ public class WifiInjector { mWifiCoreHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager, mWifiMetrics.getWakeupMetrics(), mClock), WakeupEvaluator.fromContext(mContext), wakeupOnboarding, mWifiConfigManager, - mWifiConfigStore, mWifiMetrics.getWakeupMetrics(), this, mFrameworkFacade); + mWifiConfigStore, mWifiMetrics.getWakeupMetrics(), this, mFrameworkFacade, + mClock); mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService()); mWifiController = new WifiController(mContext, mClientModeImpl, clientModeImplLooper, mSettingsStore, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade, diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java index 3734ba786..dcea61a48 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java @@ -75,6 +75,7 @@ public class WakeupControllerTest { @Mock private WifiWakeMetrics mWifiWakeMetrics; @Mock private WifiController mWifiController; @Mock private WifiNative mWifiNative; + @Mock private Clock mClock; private TestLooper mLooper; private WakeupController mWakeupController; @@ -129,7 +130,8 @@ public class WakeupControllerTest { mWifiConfigStore, mWifiWakeMetrics, mWifiInjector, - mFrameworkFacade); + mFrameworkFacade, + mClock); ArgumentCaptor<WakeupConfigStoreData> captor = ArgumentCaptor.forClass(WakeupConfigStoreData.class); @@ -563,4 +565,57 @@ public class WakeupControllerTest { contentObserver.onChange(false /* selfChange */); verify(mWakeupOnboarding).setOnboarded(); } + + /** + * When Wifi disconnects from a network, and within LAST_DISCONNECT_TIMEOUT_MILLIS Wifi is + * disabled, then the last connected Wifi network should be added to the wakeup lock. + * + * This simulates when a Wifi network sporadically connects and disconnects. During the + * disconnected phase, the user forcibly disables Wifi to stop this intermittent behavior. Then, + * we should add the network to the wake lock to ensure Wifi Wake does not automatically + * reconnect to this network. + * + * Also verifies that after the above flow, when Wifi is re-enabled, then disabled again, the + * last connected network should be reset and no networks should be added to the wakeup lock. + */ + @Test + public void lastConnectedNetworkAddedToLock() { + when(mClock.getElapsedSinceBootMillis()).thenReturn(0L, + (long) (0.8 * WakeupController.LAST_DISCONNECT_TIMEOUT_MILLIS)); + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(mTestScanResult); + when(mWifiConfigManager.getSavedNetworks()).thenReturn(Collections.emptyList()); + when(mWifiScanner.getSingleScanResults()).thenReturn(Collections.emptyList()); + initializeWakeupController(true); + + mWakeupController.setLastDisconnectInfo(matchInfo); + mWakeupController.start(); + + verify(mWakeupLock).setLock(eq(Collections.singleton(matchInfo))); + + mWakeupController.stop(); + mWakeupController.reset(); + mWakeupController.start(); + + verify(mWakeupLock).setLock(eq(Collections.emptySet())); + } + + /** + * When Wifi disconnects from a network, and Wifi is disabled after more than + * LAST_DISCONNECT_TIMEOUT_MILLIS, the last connected Wifi network should not be added to the + * wakeup lock. + */ + @Test + public void expiredLastConnectedNetworkNotAddedToLock() { + when(mClock.getElapsedSinceBootMillis()).thenReturn(0L, + (long) (1.2 * WakeupController.LAST_DISCONNECT_TIMEOUT_MILLIS)); + ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(mTestScanResult); + when(mWifiConfigManager.getSavedNetworks()).thenReturn(Collections.emptyList()); + when(mWifiScanner.getSingleScanResults()).thenReturn(Collections.emptyList()); + initializeWakeupController(true); + + mWakeupController.setLastDisconnectInfo(matchInfo); + mWakeupController.start(); + + verify(mWakeupLock).setLock(eq(Collections.emptySet())); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java index 43605f484..8bd38e156 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java @@ -105,10 +105,10 @@ public class WakeupLockTest { mWakeupLock.setLock(networks); assertFalse(mWakeupLock.isInitialized()); - mWakeupLock.update(networks); - assertFalse(mWakeupLock.isInitialized()); - mWakeupLock.update(networks); - assertFalse(mWakeupLock.isInitialized()); + for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT - 1; i++) { + mWakeupLock.update(networks); + assertFalse(mWakeupLock.isInitialized()); + } mWakeupLock.update(networks); assertTrue(mWakeupLock.isInitialized()); } @@ -283,7 +283,8 @@ public class WakeupLockTest { for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) { mWakeupLock.update(Collections.emptyList()); } - verify(mWifiWakeMetrics).recordUnlockEvent(3 /* numScans */); + verify(mWifiWakeMetrics).recordUnlockEvent( + WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT /* numScans */); } private void setLockAndInitializeByTimeout(Collection<ScanResultMatchInfo> networks) { |