diff options
author | Dan Pasanen <invisiblek@cyanogenmod.org> | 2016-12-05 20:50:00 -0600 |
---|---|---|
committer | Dan Pasanen <invisiblek@cyanogenmod.org> | 2016-12-05 20:50:00 -0600 |
commit | 7e4f2af516a1f603411cd02336dfa58d1b7a8bfe (patch) | |
tree | f29cca780378fa43a2d778e289d2dfca54b431eb | |
parent | ad493b0bff4a913f728464da462d5f6083f85299 (diff) | |
parent | 4da98e32a7c53663b1af4d979b27df214a3d3b46 (diff) | |
download | android_frameworks_opt_net_wifi-cm-14.1_prerebase.tar.gz android_frameworks_opt_net_wifi-cm-14.1_prerebase.tar.bz2 android_frameworks_opt_net_wifi-cm-14.1_prerebase.zip |
Merge tag 'android-7.1.1_r4' into cm-14.1cm-14.1_prerebase
Android 7.1.1 release 4
Change-Id: If876f7e629a09a1a82dcaea05381c0af2408cefb
31 files changed, 1195 insertions, 199 deletions
diff --git a/service/Android.mk b/service/Android.mk index c1ba4a886..cdee104a4 100644 --- a/service/Android.mk +++ b/service/Android.mk @@ -145,6 +145,12 @@ LOCAL_MODULE_TAGS := LOCAL_MODULE := wifi-service LOCAL_PROTOC_OPTIMIZE_TYPE := nano +ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true) +LOCAL_EMMA_INSTRUMENT := true +endif + +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.server.wifi.* + include $(BUILD_JAVA_LIBRARY) endif diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 7f3a8eebd..24409aebb 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -190,7 +190,7 @@ public class WifiConfigManager { */ private static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = { -1, // threshold for NETWORK_SELECTION_ENABLE - 1, // threshold for DISABLED_BAD_LINK + 1, // threshold for DISABLED_BAD_LINK (deprecated) 5, // threshold for DISABLED_ASSOCIATION_REJECTION 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 5, // threshold for DISABLED_DHCP_FAILURE @@ -206,7 +206,7 @@ public class WifiConfigManager { */ private static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT = { Integer.MAX_VALUE, // threshold for NETWORK_SELECTION_ENABLE - 15, // threshold for DISABLED_BAD_LINK + 15, // threshold for DISABLED_BAD_LINK (deprecated) 5, // threshold for DISABLED_ASSOCIATION_REJECTION 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 5, // threshold for DISABLED_DHCP_FAILURE @@ -243,11 +243,6 @@ public class WifiConfigManager { public AtomicInteger mBandAward5Ghz = new AtomicInteger(); /** - * If Connectivity Service has triggered an unwanted network disconnect - */ - public long mLastUnwantedNetworkDisconnectTimestamp = 0; - - /** * 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. @@ -1669,6 +1664,7 @@ public class WifiConfigManager { // 2) mConfiguredNetworks caches a Passpoint network's FQDN the moment the network is added. // Thus, we had to load the FQDNs first. mConfiguredNetworks.clear(); + mScanDetailCaches.clear(); for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) { final String configKey = entry.getKey(); final WifiConfiguration config = entry.getValue(); @@ -2472,20 +2468,8 @@ public class WifiConfigManager { } private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) { + // Nothing to do if no Hotspot 2.0 provider is configured. if (!mMOManager.isConfigured()) { - if (mEnableOsuQueries) { - NetworkDetail networkDetail = scanDetail.getNetworkDetail(); - List<Constants.ANQPElementType> querySet = - ANQPFactory.buildQueryList(networkDetail, false, true); - - if (networkDetail.queriable(querySet)) { - querySet = mAnqpCache.initiate(networkDetail, querySet); - if (querySet != null) { - mSupplicantBridge.startANQP(scanDetail, querySet); - } - updateAnqpCache(scanDetail, networkDetail.getANQPElements()); - } - } return null; } NetworkDetail networkDetail = scanDetail.getNetworkDetail(); @@ -3233,29 +3217,6 @@ public class WifiConfigManager { } } - /** called when CS ask WiFistateMachine to disconnect the current network - * because the score is bad. - */ - void handleBadNetworkDisconnectReport(int netId, WifiInfo info) { - /* TODO verify the bad network is current */ - WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); - if (config != null) { - if ((info.is24GHz() && info.getRssi() - <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND) - || (info.is5GHz() && info.getRssi() - <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND)) { - // We do not block due to bad RSSI since network selection should not select bad - // RSSI candidate - } else { - // We got disabled but RSSI is good, so disable hard - updateNetworkSelectionStatus(config, - WifiConfiguration.NetworkSelectionStatus.DISABLED_BAD_LINK); - } - } - // Record last time Connectivity Service switched us away from WiFi and onto Cell - mLastUnwantedNetworkDisconnectTimestamp = mClock.currentTimeMillis(); - } - int getMaxDhcpRetries() { return mFacade.getIntegerSetting(mContext, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index bdd931e4e..1cdfb692a 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -150,6 +150,7 @@ public class WifiConnectivityManager { private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP; private boolean mPnoScanStarted = false; private boolean mPeriodicScanTimerSet = false; + private boolean mWaitForFullBandScanResults = false; // PNO settings private int mMin5GHzRssi; @@ -229,6 +230,7 @@ public class WifiConnectivityManager { mStateMachine.isSupplicantTransientState()); mWifiLastResortWatchdog.updateAvailableNetworks( mQualifiedNetworkSelector.getFilteredScanDetails()); + mWifiMetrics.countScanResults(scanDetails); if (candidate != null) { localLog(listenerName + ": QNS candidate-" + candidate.SSID); connectToNetwork(candidate); @@ -327,9 +329,21 @@ public class WifiConnectivityManager { public void onResults(WifiScanner.ScanData[] results) { if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { clearScanDetails(); + mWaitForFullBandScanResults = false; return; } + // Full band scan results only. + if (mWaitForFullBandScanResults) { + if (!results[0].isAllChannelsScanned()) { + localLog("AllSingleScanListener waiting for full band scan results."); + clearScanDetails(); + return; + } else { + mWaitForFullBandScanResults = false; + } + } + boolean wasConnectAttempted = handleScanResults(mScanDetails, "AllSingleScanListener"); clearScanDetails(); @@ -513,7 +527,7 @@ public class WifiConnectivityManager { public WifiConnectivityManager(Context context, WifiStateMachine stateMachine, WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, WifiQualifiedNetworkSelector qualifiedNetworkSelector, - WifiInjector wifiInjector, Looper looper) { + WifiInjector wifiInjector, Looper looper, boolean enable) { mStateMachine = stateMachine; mScanner = scanner; mConfigManager = configManager; @@ -548,7 +562,10 @@ public class WifiConnectivityManager { // Register for all single scan results mScanner.registerScanListener(mAllSingleScanListener); - Log.i(TAG, "ConnectivityScanManager initialized "); + mWifiConnectivityManagerEnabled = enable; + + Log.i(TAG, "ConnectivityScanManager initialized and " + + (enable ? "enabled" : "disabled")); } /** @@ -1077,7 +1094,8 @@ public class WifiConnectivityManager { public void forceConnectivityScan() { Log.i(TAG, "forceConnectivityScan"); - startConnectivityScan(SCAN_IMMEDIATELY); + mWaitForFullBandScanResults = true; + startSingleScan(true); } /** @@ -1121,6 +1139,9 @@ public class WifiConnectivityManager { stopConnectivityScan(); resetLastPeriodicSingleScanTimeStamp(); mLastConnectionAttemptBssid = null; + mWaitForFullBandScanResults = false; + } else if (mWifiConnectivityManagerEnabled) { + startConnectivityScan(SCAN_IMMEDIATELY); } } @@ -1136,6 +1157,9 @@ public class WifiConnectivityManager { stopConnectivityScan(); resetLastPeriodicSingleScanTimeStamp(); mLastConnectionAttemptBssid = null; + mWaitForFullBandScanResults = false; + } else if (mWifiEnabled) { + startConnectivityScan(SCAN_IMMEDIATELY); } } diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java index 558b50ef1..0885e46fd 100644 --- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java +++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java @@ -209,6 +209,12 @@ public class WifiLastResortWatchdog { public void connectedStateTransition(boolean isEntering) { if (VDBG) Log.v(TAG, "connectedStateTransition: isEntering = " + isEntering); mWifiIsConnected = isEntering; + + if (!mWatchdogAllowedToTrigger) { + // WiFi has connected after a Watchdog trigger, without any new networks becoming + // available, log a Watchdog success in wifi metrics + mWifiMetrics.incrementNumLastResortWatchdogSuccesses(); + } if (isEntering) { // We connected to something! Reset failure counts for everything clearAllFailureCounts(); diff --git a/service/java/com/android/server/wifi/WifiLoggerHal.java b/service/java/com/android/server/wifi/WifiLoggerHal.java index 8a0276480..0294e9bf7 100644 --- a/service/java/com/android/server/wifi/WifiLoggerHal.java +++ b/service/java/com/android/server/wifi/WifiLoggerHal.java @@ -46,4 +46,9 @@ public class WifiLoggerHal { public static final byte RX_PKT_FATE_DRV_DROP_INVALID = 8; public static final byte RX_PKT_FATE_DRV_DROP_NOBUFS = 9; public static final byte RX_PKT_FATE_DRV_DROP_OTHER = 10; + + /** These aren't formally part of the HAL. But they probably should be, eventually. */ + public static final byte WIFI_ALERT_REASON_RESERVED = 0; + public static final byte WIFI_ALERT_REASON_MIN = 0; + public static final byte WIFI_ALERT_REASON_MAX = 64; } diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 4ef29f6f8..fcb6301b6 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.net.NetworkAgent; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.util.Base64; @@ -47,6 +48,8 @@ public class WifiMetrics { */ private static final int MAX_RSSI_POLL = 0; private static final int MIN_RSSI_POLL = -127; + private static final int MIN_WIFI_SCORE = 0; + private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE; private final Object mLock = new Object(); private static final int MAX_CONNECTION_EVENTS = 256; private Clock mClock; @@ -76,13 +79,17 @@ public class WifiMetrics { * combination. Indexed by WifiLog.WifiState * (1 + screenOn) */ private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray(); + /** Mapping of RSSI values to counts. */ + private final SparseIntArray mRssiPollCounts = new SparseIntArray(); + /** Mapping of alert reason to the respective alert count. */ + private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray(); /** * Records the elapsedRealtime (in seconds) that represents the beginning of data * capture for for this WifiMetricsProto */ - private final SparseIntArray mRssiPollCounts = new SparseIntArray(); private long mRecordStartTimeSec; - + /** Mapping of Wifi Scores to counts */ + private final SparseIntArray mWifiScoreCounts = new SparseIntArray(); class RouterFingerPrint { private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; RouterFingerPrint() { @@ -127,6 +134,8 @@ public class WifiMetrics { mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; } + mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto + .passpoint = config.isPasspoint(); // If there's a ScanResult candidate associated with this config already, get it and // log (more accurate) metrics from it ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); @@ -512,6 +521,18 @@ public class WifiMetrics { } } + void setNumHiddenNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numHiddenNetworks = num; + } + } + + void setNumPasspointNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numPasspointNetworks = num; + } + } + void setNumNetworksAddedByUser(int num) { synchronized (mLock) { mWifiLogProto.numNetworksAddedByUser = num; @@ -806,10 +827,105 @@ public class WifiMetrics { } } + /** + * Increment count of Watchdog successes. + */ + public void incrementNumLastResortWatchdogSuccesses() { + synchronized (mLock) { + mWifiLogProto.numLastResortWatchdogSuccesses++; + } + } + + /** + * Increments the count of alerts by alert reason. + * + * @param reason The cause of the alert. The reason values are driver-specific. + */ + public void incrementAlertReasonCount(int reason) { + if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX + || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) { + reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED; + } + synchronized (mLock) { + int alertCount = mWifiAlertReasonCounts.get(reason); + mWifiAlertReasonCounts.put(reason, alertCount + 1); + } + } + + /** + * Counts all the different types of networks seen in a set of scan results + */ + public void countScanResults(List<ScanDetail> scanDetails) { + if (scanDetails == null) { + return; + } + int totalResults = 0; + int openNetworks = 0; + int personalNetworks = 0; + int enterpriseNetworks = 0; + int hiddenNetworks = 0; + int hotspot2r1Networks = 0; + int hotspot2r2Networks = 0; + for (ScanDetail scanDetail : scanDetails) { + NetworkDetail networkDetail = scanDetail.getNetworkDetail(); + ScanResult scanResult = scanDetail.getScanResult(); + totalResults++; + if (networkDetail != null) { + if (networkDetail.isHiddenBeaconFrame()) { + hiddenNetworks++; + } + if (networkDetail.getHSRelease() != null) { + if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { + hotspot2r1Networks++; + } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { + hotspot2r2Networks++; + } + } + } + if (scanResult != null && scanResult.capabilities != null) { + if (scanResult.capabilities.contains("EAP")) { + enterpriseNetworks++; + } else if (scanResult.capabilities.contains("PSK") + || scanResult.capabilities.contains("WEP")) { + personalNetworks++; + } else { + openNetworks++; + } + } + } + synchronized (mLock) { + mWifiLogProto.numTotalScanResults += totalResults; + mWifiLogProto.numOpenNetworkScanResults += openNetworks; + mWifiLogProto.numPersonalNetworkScanResults += personalNetworks; + mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks; + mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks; + mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks; + mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks; + mWifiLogProto.numScans++; + } + } + + /** + * Increments occurence of a particular wifi score calculated + * in WifiScoreReport by current connected network. Scores are bounded + * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray + */ + public void incrementWifiScoreCount(int score) { + if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) { + return; + } + synchronized (mLock) { + int count = mWifiScoreCounts.get(score); + mWifiScoreCounts.put(score, count + 1); + } + } + public static final String PROTO_DUMP_ARG = "wifiMetricsProto"; + public static final String CLEAN_DUMP_ARG = "clean"; + /** * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager - * at this time + * at this time. * * @param fd unused * @param pw PrintWriter for writing dump to @@ -817,9 +933,8 @@ public class WifiMetrics { */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (mLock) { - pw.println("WifiMetrics:"); if ((args != null) && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) { - //Dump serialized WifiLog proto + // Dump serialized WifiLog proto consolidateProto(true); for (ConnectionEvent event : mConnectionEventList) { if (mCurrentConnectionEvent != event) { @@ -830,10 +945,18 @@ public class WifiMetrics { } byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); - pw.println(metricsProtoDump); - pw.println("EndWifiMetrics"); + if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) { + // Output metrics proto bytes (base64) and nothing else + pw.print(metricsProtoDump); + } else { + // Tag the start and end of the metrics proto bytes + pw.println("WifiMetrics:"); + pw.println(metricsProtoDump); + pw.println("EndWifiMetrics"); + } clear(); } else { + pw.println("WifiMetrics:"); pw.println("mConnectionEvents:"); for (ConnectionEvent event : mConnectionEventList) { String eventLine = event.toString(); @@ -848,6 +971,9 @@ public class WifiMetrics { + mWifiLogProto.numPersonalNetworks); pw.println("mWifiLogProto.numEnterpriseNetworks=" + mWifiLogProto.numEnterpriseNetworks); + pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks); + pw.println("mWifiLogProto.numPasspointNetworks=" + + mWifiLogProto.numPasspointNetworks); pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); pw.println("mWifiLogProto.isScanningAlwaysEnabled=" + mWifiLogProto.isScanningAlwaysEnabled); @@ -921,6 +1047,8 @@ public class WifiMetrics { + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp); pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther=" + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther); + pw.println("mWifiLogProto.numLastResortWatchdogSuccesses=" + + mWifiLogProto.numLastResortWatchdogSuccesses); pw.println("mWifiLogProto.recordDurationSec=" + ((mClock.elapsedRealtime() / 1000) - mRecordStartTimeSec)); pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL @@ -930,6 +1058,42 @@ public class WifiMetrics { sb.append(mRssiPollCounts.get(i) + " "); } pw.println(" " + sb.toString()); + pw.print("mWifiLogProto.alertReasonCounts="); + sb.setLength(0); + for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN; + i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) { + int count = mWifiAlertReasonCounts.get(i); + if (count > 0) { + sb.append("(" + i + "," + count + "),"); + } + } + if (sb.length() > 1) { + sb.setLength(sb.length() - 1); // strip trailing comma + pw.println(sb.toString()); + } else { + pw.println("()"); + } + pw.println("mWifiLogProto.numTotalScanResults=" + + mWifiLogProto.numTotalScanResults); + pw.println("mWifiLogProto.numOpenNetworkScanResults=" + + mWifiLogProto.numOpenNetworkScanResults); + pw.println("mWifiLogProto.numPersonalNetworkScanResults=" + + mWifiLogProto.numPersonalNetworkScanResults); + pw.println("mWifiLogProto.numEnterpriseNetworkScanResults=" + + mWifiLogProto.numEnterpriseNetworkScanResults); + pw.println("mWifiLogProto.numHiddenNetworkScanResults=" + + mWifiLogProto.numHiddenNetworkScanResults); + pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults=" + + mWifiLogProto.numHotspot2R1NetworkScanResults); + pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults=" + + mWifiLogProto.numHotspot2R2NetworkScanResults); + pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans); + pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", " + + MAX_WIFI_SCORE + "]"); + for (int i = 0; i <= MAX_WIFI_SCORE; i++) { + pw.print(mWifiScoreCounts.get(i) + " "); + } + pw.print("\n"); } } } @@ -943,6 +1107,8 @@ public class WifiMetrics { private void consolidateProto(boolean incremental) { List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>(); List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>(); + List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>(); + List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>(); synchronized (mLock) { for (ConnectionEvent event : mConnectionEventList) { // If this is not incremental, dump full ConnectionEvent list @@ -1000,6 +1166,29 @@ public class WifiMetrics { rssis.add(keyVal); } mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount); + + /** + * Convert the SparseIntArray of alert reasons and counts to the proto's repeated + * IntKeyVal array. + */ + for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) { + WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount(); + keyVal.reason = mWifiAlertReasonCounts.keyAt(i); + keyVal.count = mWifiAlertReasonCounts.valueAt(i); + alertReasons.add(keyVal); + } + mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount); + /** + * Convert the SparseIntArray of Wifi Score and counts to proto's repeated + * IntKeyVal array. + */ + for (int score = 0; score < mWifiScoreCounts.size(); score++) { + WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount(); + keyVal.score = mWifiScoreCounts.keyAt(score); + keyVal.count = mWifiScoreCounts.valueAt(score); + scores.add(keyVal); + } + mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount); } } @@ -1016,6 +1205,8 @@ public class WifiMetrics { mWifiSystemStateEntries.clear(); mRecordStartTimeSec = mClock.elapsedRealtime() / 1000; mRssiPollCounts.clear(); + mWifiAlertReasonCounts.clear(); + mWifiScoreCounts.clear(); mWifiLogProto.clear(); } } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 7ed0409f9..f6931c1fe 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -78,6 +78,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TimeZone; @@ -1716,6 +1717,19 @@ public class WifiNative { public int priority; public byte flags; public byte auth_bit_field; + + @Override + public boolean equals(Object otherObj) { + if (this == otherObj) { + return true; + } else if (otherObj == null || getClass() != otherObj.getClass()) { + return false; + } + PnoNetwork other = (PnoNetwork) otherObj; + return ((Objects.equals(ssid, other.ssid)) && (networkId == other.networkId) + && (priority == other.priority) && (flags == other.flags) + && (auth_bit_field == other.auth_bit_field)); + } } /** @@ -2193,13 +2207,12 @@ public class WifiNative { synchronized (sLock) { if (isHalStarted()) { if (sRttCmdId != 0) { - Log.v("TAG", "Last one is still under measurement!"); + Log.w(TAG, "Last one is still under measurement!"); return false; } else { sRttCmdId = getNewCmdIdLocked(); } sRttEventHandler = handler; - Log.v(TAG, "native issue RTT request"); return requestRangeNative(sWlan0Index, sRttCmdId, params); } else { return false; @@ -2218,7 +2231,6 @@ public class WifiNative { if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) { sRttEventHandler = null; - Log.v(TAG, "RTT cancel Request Successfully"); return true; } else { Log.e(TAG, "RTT cancel Request failed"); diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java index 7ad44c875..00fffdb4b 100644 --- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java +++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java @@ -626,9 +626,9 @@ public class WifiQualifiedNetworkSelector { mWifiConfigManager.getWifiConfiguration(mWifiInfo.getNetworkId()); } - if (mCurrentBssid == null) { - mCurrentBssid = mWifiInfo.getBSSID(); - } + // Always get the current BSSID from WifiInfo in case that firmware initiated roaming + // happened. + mCurrentBssid = mWifiInfo.getBSSID(); if (!forceSelectNetwork && !needQualifiedNetworkSelection(isLinkDebouncing, isConnected, isDisconnected, isSupplicantTransient)) { diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java index 50e28bf28..d32c72299 100644 --- a/service/java/com/android/server/wifi/WifiScoreReport.java +++ b/service/java/com/android/server/wifi/WifiScoreReport.java @@ -97,7 +97,8 @@ public class WifiScoreReport { WifiConfigManager wifiConfigManager, NetworkAgent networkAgent, WifiScoreReport lastReport, - int aggressiveHandover) { + int aggressiveHandover, + WifiMetrics wifiMetrics) { boolean debugLogging = false; if (wifiConfigManager.mEnableVerboseLogging.get() > 0) { debugLogging = true; @@ -370,6 +371,7 @@ public class WifiScoreReport { networkAgent.sendNetworkScore(score); } } + wifiMetrics.incrementWifiScoreCount(score); return new WifiScoreReport(sb.toString(), badLinkspeedcount); } } diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 180fd82f8..e34385352 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -98,6 +98,7 @@ import android.util.SparseArray; import android.os.SystemProperties; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.util.AsyncChannel; @@ -551,10 +552,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss private WifiScanner mWifiScanner; - private int mConnectionRequests = 0; + @GuardedBy("mWifiReqCountLock") + private int mConnectionReqCount = 0; private WifiNetworkFactory mNetworkFactory; + @GuardedBy("mWifiReqCountLock") + private int mUntrustedReqCount = 0; private UntrustedWifiNetworkFactory mUntrustedNetworkFactory; private WifiNetworkAgent mNetworkAgent; + private final Object mWifiReqCountLock = new Object(); private String[] mWhiteListedSsids = null; @@ -2372,6 +2377,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0]) + && WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) { + // Dump only wifi metrics serialized proto bytes (base64) + updateWifiMetrics(); + mWifiMetrics.dump(fd, pw, args); + return; + } super.dump(fd, pw, args); mSupplicantStateTracker.dump(fd, pw, args); pw.println("mLinkProperties " + mLinkProperties); @@ -2620,7 +2632,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss sb.append(" known=").append(mNumScanResultsKnown); sb.append(" got=").append(mNumScanResultsReturned); sb.append(String.format(" bcn=%d", mRunningBeaconCount)); - sb.append(String.format(" con=%d", mConnectionRequests)); + sb.append(String.format(" con=%d", mConnectionReqCount)); + sb.append(String.format(" untrustedcn=%d", mUntrustedReqCount)); key = mWifiConfigManager.getLastSelectedConfiguration(); if (key != null) { sb.append(" last=").append(key); @@ -3989,23 +4002,33 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss @Override protected void needNetworkFor(NetworkRequest networkRequest, int score) { - ++mConnectionRequests; + synchronized (mWifiReqCountLock) { + if (++mConnectionReqCount == 1) { + if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) { + mWifiConnectivityManager.enable(true); + } + } + } } @Override protected void releaseNetworkFor(NetworkRequest networkRequest) { - --mConnectionRequests; + synchronized (mWifiReqCountLock) { + if (--mConnectionReqCount == 0) { + if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) { + mWifiConnectivityManager.enable(false); + } + } + } } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("mConnectionRequests " + mConnectionRequests); + pw.println("mConnectionReqCount " + mConnectionReqCount); } } private class UntrustedWifiNetworkFactory extends NetworkFactory { - private int mUntrustedReqCount; - public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) { super(l, c, tag, f); } @@ -4014,9 +4037,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss protected void needNetworkFor(NetworkRequest networkRequest, int score) { if (!networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { - if (++mUntrustedReqCount == 1) { - if (mWifiConnectivityManager != null) { - mWifiConnectivityManager.setUntrustedConnectionAllowed(true); + synchronized (mWifiReqCountLock) { + if (++mUntrustedReqCount == 1) { + if (mWifiConnectivityManager != null) { + if (mConnectionReqCount == 0) { + mWifiConnectivityManager.enable(true); + } + mWifiConnectivityManager.setUntrustedConnectionAllowed(true); + } } } } @@ -4026,9 +4054,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss protected void releaseNetworkFor(NetworkRequest networkRequest) { if (!networkRequest.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { - if (--mUntrustedReqCount == 0) { - if (mWifiConnectivityManager != null) { - mWifiConnectivityManager.setUntrustedConnectionAllowed(false); + synchronized (mWifiReqCountLock) { + if (--mUntrustedReqCount == 0) { + if (mWifiConnectivityManager != null) { + mWifiConnectivityManager.setUntrustedConnectionAllowed(false); + if (mConnectionReqCount == 0) { + mWifiConnectivityManager.enable(false); + } + } } } } @@ -4234,7 +4267,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss case CMD_FIRMWARE_ALERT: if (mWifiLogger != null) { byte[] buffer = (byte[])message.obj; - mWifiLogger.captureAlertData(message.arg1, buffer); + int alertReason = message.arg1; + mWifiLogger.captureAlertData(alertReason, buffer); + mWifiMetrics.incrementAlertReasonCount(alertReason); } break; case CMD_GET_LINK_LAYER_STATS: @@ -4779,10 +4814,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss if (mWifiScanner == null) { mWifiScanner = mFacade.makeWifiScanner(mContext, getHandler().getLooper()); - mWifiConnectivityManager = new WifiConnectivityManager(mContext, - WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo, - mWifiQualifiedNetworkSelector, mWifiInjector, - getHandler().getLooper()); + synchronized (mWifiReqCountLock) { + mWifiConnectivityManager = new WifiConnectivityManager(mContext, + WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo, + mWifiQualifiedNetworkSelector, mWifiInjector, + getHandler().getLooper(), hasConnectionRequests()); + mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0); + } } mWifiLogger.startLogging(DBG); @@ -5671,8 +5709,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss config, disableOthers, message.sendingUid); if (!ok) { messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; - } else if (disableOthers) { - mTargetNetworkId = netId; + } else { + if (disableOthers) { + mTargetNetworkId = netId; + } + mWifiConnectivityManager.forceConnectivityScan(); } replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); @@ -6756,7 +6797,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mWifiConfigManager, mNetworkAgent, mWifiScoreReport, - mAggressiveHandover); + mAggressiveHandover, + mWifiMetrics); } sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); @@ -7223,8 +7265,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss break; case CMD_UNWANTED_NETWORK: if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) { - mWifiConfigManager.handleBadNetworkDisconnectReport( - mLastNetworkId, mWifiInfo); mWifiNative.disconnect(); transitionTo(mDisconnectingState); } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN || @@ -7369,18 +7409,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss config = mWifiConfigManager.getWifiConfiguration(netId); } + setTargetBssid(config, bssid); + mTargetNetworkId = netId; + logd("CMD_AUTO_ROAM sup state " + mSupplicantStateTracker.getSupplicantStateName() + " my state " + getCurrentState().getName() + " nid=" + Integer.toString(netId) + " config " + config.configKey() - + " roam=" + Integer.toString(message.arg2) - + " to " + bssid + " targetRoamBSSID " + mTargetRoamBSSID); - setTargetBssid(config, bssid); - mTargetNetworkId = netId; - /* Determine if this is a regular roam (between BSSIDs sharing the same SSID), or a DBDC roam (between 2.4 & 5GHz networks on different SSID's, but with matching 16 byte BSSID prefixes): @@ -8251,7 +8289,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss * @param bssid BSSID of the network */ public void autoConnectToNetwork(int networkId, String bssid) { - sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid); + synchronized (mWifiReqCountLock) { + if (hasConnectionRequests()) { + sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid); + } + } } /** @@ -8302,6 +8344,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss int numEnterpriseNetworks = 0; int numNetworksAddedByUser = 0; int numNetworksAddedByApps = 0; + int numHiddenNetworks = 0; + int numPasspoint = 0; for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) { if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) { numOpenNetworks++; @@ -8315,6 +8359,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } else { numNetworksAddedByApps++; } + if (config.hiddenSSID) { + numHiddenNetworks++; + } + if (config.isPasspoint()) { + numPasspoint++; + } } mWifiMetrics.setNumSavedNetworks(numSavedNetworks); mWifiMetrics.setNumOpenNetworks(numOpenNetworks); @@ -8322,17 +8372,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks); mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser); mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps); - - /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually - mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt( - mContext.getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) - != Settings.Secure.LOCATION_MODE_OFF); - */ - - /* <TODO> decide how statemachine will access WifiSettingsStore - mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable()); - */ + mWifiMetrics.setNumHiddenNetworks(numHiddenNetworks); + mWifiMetrics.setNumPasspointNetworks(numPasspoint); } private static String getLinkPropertiesSummary(LinkProperties lp) { @@ -8431,4 +8472,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } } } + + /** + * Check if there is any connection request for WiFi network. + * Note, caller of this helper function must acquire mWifiReqCountLock. + */ + private boolean hasConnectionRequests() { + return mConnectionReqCount > 0 || mUntrustedReqCount > 0; + } } diff --git a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java index 402c0a869..321254c72 100644 --- a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java +++ b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java @@ -59,6 +59,8 @@ public class NetworkDetail { private final String mSSID; private final long mHESSID; private final long mBSSID; + // True if the SSID is potentially from a hidden network + private final boolean mIsHiddenSsid; // BSS Load element: private final int mStationCount; @@ -131,6 +133,7 @@ public class NetworkDetail { mBSSID = Utils.parseMac(bssid); String ssid = null; + boolean isHiddenSsid = false; byte[] ssidOctets = null; InformationElementUtil.BssLoad bssLoad = new InformationElementUtil.BssLoad(); @@ -236,10 +239,18 @@ public class NetworkDetail { ssid = new String(ssidOctets, StandardCharsets.ISO_8859_1); } } + isHiddenSsid = true; + for (byte byteVal : ssidOctets) { + if (byteVal != 0) { + isHiddenSsid = false; + break; + } + } } mSSID = ssid; mHESSID = interworking.hessid; + mIsHiddenSsid = isHiddenSsid; mStationCount = bssLoad.stationCount; mChannelUtilization = bssLoad.channelUtilization; mCapacity = bssLoad.capacity; @@ -268,7 +279,9 @@ public class NetworkDetail { } // If trafficIndicationMap is not valid, mDtimPeriod will be negative - mDtimInterval = trafficIndicationMap.mDtimPeriod; + if (trafficIndicationMap.isValid()) { + mDtimInterval = trafficIndicationMap.mDtimPeriod; + } int maxRateA = 0; int maxRateB = 0; @@ -318,6 +331,7 @@ public class NetworkDetail { private NetworkDetail(NetworkDetail base, Map<Constants.ANQPElementType, ANQPElement> anqpElements) { mSSID = base.mSSID; + mIsHiddenSsid = base.mIsHiddenSsid; mBSSID = base.mBSSID; mHESSID = base.mHESSID; mStationCount = base.mStationCount; @@ -515,6 +529,28 @@ public class NetworkDetail { return toMACString(mBSSID); } + /** + * Evaluates the ScanResult this NetworkDetail is built from + * returns true if built from a Beacon Frame + * returns false if built from a Probe Response + */ + public boolean isBeaconFrame() { + // Beacon frames have a 'Traffic Indication Map' Information element + // Probe Responses do not. This is indicated by a DTIM period > 0 + return mDtimInterval > 0; + } + + /** + * Evaluates the ScanResult this NetworkDetail is built from + * returns true if built from a hidden Beacon Frame + * returns false if not hidden or not a Beacon + */ + public boolean isHiddenBeaconFrame() { + // Hidden networks are not 80211 standard, but it is common for a hidden network beacon + // frame to either send zero-value bytes as the SSID, or to send no bytes at all. + return isBeaconFrame() && mIsHiddenSsid; + } + public static String toMACString(long mac) { StringBuilder sb = new StringBuilder(); boolean first = true; @@ -528,5 +564,4 @@ public class NetworkDetail { } return sb.toString(); } - } diff --git a/service/java/com/android/server/wifi/scanner/ChannelHelper.java b/service/java/com/android/server/wifi/scanner/ChannelHelper.java index d4168123d..acb0ac820 100644 --- a/service/java/com/android/server/wifi/scanner/ChannelHelper.java +++ b/service/java/com/android/server/wifi/scanner/ChannelHelper.java @@ -100,6 +100,10 @@ public abstract class ChannelHelper { */ public abstract boolean isEmpty(); /** + * @return true if the collection contains all available channels + */ + public abstract boolean isAllChannels(); + /** * Remove all channels from the collection */ public abstract void clear(); diff --git a/service/java/com/android/server/wifi/scanner/KnownBandsChannelHelper.java b/service/java/com/android/server/wifi/scanner/KnownBandsChannelHelper.java index b180da71d..acddc26c6 100644 --- a/service/java/com/android/server/wifi/scanner/KnownBandsChannelHelper.java +++ b/service/java/com/android/server/wifi/scanner/KnownBandsChannelHelper.java @@ -198,6 +198,12 @@ public class KnownBandsChannelHelper extends ChannelHelper { } @Override + public boolean isAllChannels() { + return getAvailableScanChannels(WifiScanner.WIFI_BAND_BOTH_WITH_DFS).length == + mChannels.size(); + } + + @Override public void clear() { mAllBands = 0; mExactBands = 0; diff --git a/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java b/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java index 7b1602008..4f8373b30 100644 --- a/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java +++ b/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java @@ -112,6 +112,11 @@ public class NoBandChannelHelper extends ChannelHelper { } @Override + public boolean isAllChannels() { + return mAllChannels; + } + + @Override public void clear() { mAllChannels = false; mChannels.clear(); diff --git a/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java index ab013b1e0..ac5db5a4f 100644 --- a/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java +++ b/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java @@ -330,6 +330,11 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle processPendingScans(); } + private boolean isDifferentPnoScanSettings(LastScanSettings newScanSettings) { + return (mLastScanSettings == null || !Arrays.equals( + newScanSettings.pnoNetworkList, mLastScanSettings.pnoNetworkList)); + } + private void processPendingScans() { synchronized (mSettingsLock) { // Wait for the active scan result to come back to reschedule other scans, @@ -460,8 +465,16 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle // TODO(b/27769665) background scans should be failed too if scans fail enough } } else if (isHwPnoScanRequired()) { - newScanSettings.setHwPnoScan(mPnoEventHandler); - if (startHwPnoScan()) { + newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler); + boolean status; + // If the PNO network list has changed from the previous request, ensure that + // we bypass the debounce logic and restart PNO scan. + if (isDifferentPnoScanSettings(newScanSettings)) { + status = restartHwPnoScan(); + } else { + status = startHwPnoScan(); + } + if (status) { mLastScanSettings = newScanSettings; } else { Log.e(TAG, "Failed to start PNO scan"); @@ -625,7 +638,8 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle } } Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR); - mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0, + mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0, 0, + mLastScanSettings.singleScanFreqs.isAllChannels(), singleScanResults.toArray(new ScanResult[singleScanResults.size()])); mLastScanSettings.singleScanEventHandler .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); @@ -695,6 +709,11 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle mHwPnoDebouncer.forceStopPnoScan(); } + private boolean restartHwPnoScan() { + mHwPnoDebouncer.forceStopPnoScan(); + return mHwPnoDebouncer.startPnoScan(mHwPnoDebouncerListener); + } + /** * Hw Pno Scan is required only for disconnected PNO when the device supports it. * @param isConnectedPno Whether this is connected PNO vs disconnected PNO. @@ -826,10 +845,14 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle } public boolean hwPnoScanActive = false; + public WifiNative.PnoNetwork[] pnoNetworkList; public WifiNative.PnoEventHandler pnoScanEventHandler; - public void setHwPnoScan(WifiNative.PnoEventHandler pnoScanEventHandler) { + public void setHwPnoScan( + WifiNative.PnoNetwork[] pnoNetworkList, + WifiNative.PnoEventHandler pnoScanEventHandler) { hwPnoScanActive = true; + this.pnoNetworkList = pnoNetworkList; this.pnoScanEventHandler = pnoScanEventHandler; } } @@ -1050,7 +1073,6 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle if (DBG) Log.d(TAG, "PNO state is already " + enable); return true; } - mLastPnoChangeTimeStamp = mClock.elapsedRealtime(); if (mWifiNative.setPnoScan(enable)) { Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to " + enable); @@ -1058,6 +1080,7 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle return true; } else { Log.e(TAG, "PNO state change to " + enable + " failed"); + mCurrentPnoState = false; return false; } } @@ -1125,15 +1148,13 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle * scan immediately. */ public void forceStopPnoScan() { - if (mCurrentPnoState) { - if (DBG) Log.d(TAG, "Force stopping Pno scan"); - // Cancel the debounce timer and stop PNO scan. - if (mWaitForTimer) { - mAlarmManager.cancel(mAlarmListener); - mWaitForTimer = false; - } - updatePnoState(false); + if (DBG) Log.d(TAG, "Force stopping Pno scan"); + // Cancel the debounce timer and stop PNO scan. + if (mWaitForTimer) { + mAlarmManager.cancel(mAlarmListener); + mWaitForTimer = false; } + updatePnoState(false); } } } diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java index 6ae223717..9f8fb2f58 100644 --- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java +++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java @@ -164,7 +164,9 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); - if (client != null) { + if (client != null && msg.arg1 != AsyncChannel.STATUS_SEND_UNSUCCESSFUL + && msg.arg1 + != AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED) { localLog("client disconnected: " + client + ", reason: " + msg.arg1); client.cleanup(); } diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java index 6e6dfcc77..d3e2fea90 100644 --- a/service/java/com/android/server/wifi/util/InformationElementUtil.java +++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java @@ -600,7 +600,7 @@ public class InformationElementUtil { } catch (BufferUnderflowException e) { return; } - if (mLength <= MAX_TIM_LENGTH) { + if (mLength <= MAX_TIM_LENGTH && mDtimPeriod > 0) { mValid = true; } } diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp index e33512f11..7e70d95a7 100644 --- a/service/jni/com_android_server_wifi_WifiNative.cpp +++ b/service/jni/com_android_server_wifi_WifiNative.cpp @@ -854,6 +854,13 @@ static jboolean android_net_wifi_setHotlist( return false; } + if (params.num_bssid > + static_cast<int>(sizeof(params.ap) / sizeof(params.ap[0]))) { + ALOGE("setHotlist array length is too long"); + android_errorWriteLog(0x534e4554, "31856351"); + return false; + } + for (int i = 0; i < params.num_bssid; i++) { JNIObject<jobject> objAp = helper.getObjectArrayElement(array, i); @@ -1180,7 +1187,7 @@ static void onRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_resu JNIHelper helper(mVM); - ALOGD("onRttResults called, vm = %p, obj = %p", mVM, mCls); + if (DBG) ALOGD("onRttResults called, vm = %p, obj = %p", mVM, mCls); JNIObject<jobjectArray> rttResults = helper.newObjectArray( num_results, "android/net/wifi/RttManager$RttResult", NULL); @@ -1227,14 +1234,12 @@ static void onRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_resu JNIObject<jobject> LCI = helper.createObject( "android/net/wifi/RttManager$WifiInformationElement"); if (result->LCI != NULL && result->LCI->len > 0) { - ALOGD("Add LCI in result"); helper.setByteField(LCI, "id", result->LCI->id); JNIObject<jbyteArray> elements = helper.newByteArray(result->LCI->len); jbyte *bytes = (jbyte *)&(result->LCI->data[0]); helper.setByteArrayRegion(elements, 0, result->LCI->len, bytes); helper.setObjectField(LCI, "data", "[B", elements); } else { - ALOGD("No LCI in result"); helper.setByteField(LCI, "id", (byte)(0xff)); } helper.setObjectField(rttResult, "LCI", @@ -1243,14 +1248,12 @@ static void onRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_resu JNIObject<jobject> LCR = helper.createObject( "android/net/wifi/RttManager$WifiInformationElement"); if (result->LCR != NULL && result->LCR->len > 0) { - ALOGD("Add LCR in result"); helper.setByteField(LCR, "id", result->LCR->id); JNIObject<jbyteArray> elements = helper.newByteArray(result->LCI->len); jbyte *bytes = (jbyte *)&(result->LCR->data[0]); helper.setByteArrayRegion(elements, 0, result->LCI->len, bytes); helper.setObjectField(LCR, "data", "[B", elements); } else { - ALOGD("No LCR in result"); helper.setByteField(LCR, "id", (byte)(0xff)); } helper.setObjectField(rttResult, "LCR", @@ -1271,7 +1274,7 @@ static jboolean android_net_wifi_requestRange( JNIHelper helper(env); wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); - ALOGD("sending rtt request [%d] = %p", id, handle); + if (DBG) ALOGD("sending rtt request [%d] = %p", id, handle); if (params == NULL) { ALOGE("ranging params are empty"); return false; @@ -1289,7 +1292,7 @@ static jboolean android_net_wifi_requestRange( JNIObject<jobject> param = helper.getObjectArrayElement((jobjectArray)params, i); if (param == NULL) { - ALOGD("could not get element %d", i); + ALOGW("could not get element %d", i); continue; } @@ -1314,18 +1317,6 @@ static jboolean android_net_wifi_requestRange( config.burst_duration = (unsigned) helper.getIntField(param, "burstTimeout"); config.preamble = (wifi_rtt_preamble) helper.getIntField(param, "preamble"); config.bw = (wifi_rtt_bw) helper.getIntField(param, "bandwidth"); - - ALOGD("RTT request destination %d: type is %d, peer is %d, bw is %d, center_freq is %d ", i, - config.type,config.peer, config.channel.width, config.channel.center_freq); - ALOGD("center_freq0 is %d, center_freq1 is %d, num_burst is %d,interval is %d", - config.channel.center_freq0, config.channel.center_freq1, config.num_burst, - config.burst_period); - ALOGD("frames_per_burst is %d, retries of measurement frame is %d, retries_per_ftmr is %d", - config.num_frames_per_burst, config.num_retries_per_rtt_frame, - config.num_retries_per_ftmr); - ALOGD("LCI_requestis %d, LCR_request is %d, burst_timeout is %d, preamble is %d, bw is %d", - config.LCI_request, config.LCR_request, config.burst_duration, config.preamble, - config.bw); } wifi_rtt_event_handler handler; @@ -1339,7 +1330,7 @@ static jboolean android_net_wifi_cancelRange( JNIHelper helper(env); wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); - ALOGD("cancelling rtt request [%d] = %p", id, handle); + if (DBG) ALOGD("cancelling rtt request [%d] = %p", id, handle); if (params == NULL) { ALOGE("ranging params are empty"); @@ -1358,7 +1349,7 @@ static jboolean android_net_wifi_cancelRange( JNIObject<jobject> param = helper.getObjectArrayElement(params, i); if (param == NULL) { - ALOGD("could not get element %d", i); + ALOGW("could not get element %d", i); continue; } diff --git a/service/proto/wifi.proto b/service/proto/wifi.proto index 3b0e8544b..8128ec115 100644 --- a/service/proto/wifi.proto +++ b/service/proto/wifi.proto @@ -189,6 +189,46 @@ message WifiLog { // Counts the occurrences of each individual RSSI poll level repeated RssiPollCount rssi_poll_rssi_count = 35; + + // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger, + // without new networks becoming available. + optional int32 num_last_resort_watchdog_successes = 36; + + // Counts the occurrences of each alert reason. + repeated AlertReasonCount alert_reason_count = 47; + + // Total number of saved hidden networks + optional int32 num_hidden_networks = 37; + + // Total number of saved passpoint / hotspot 2.0 networks + optional int32 num_passpoint_networks = 38; + + // Total number of scan results + optional int32 num_total_scan_results = 39; + + // Total number of scan results for open networks + optional int32 num_open_network_scan_results = 40; + + // Total number of scan results for personal networks + optional int32 num_personal_network_scan_results = 41; + + // Total number of scan results for enterprise networks + optional int32 num_enterprise_network_scan_results = 42; + + // Total number of scan results for hidden networks + optional int32 num_hidden_network_scan_results = 43; + + // Total number of scan results for hotspot 2.0 r1 networks + optional int32 num_hotspot2_r1_network_scan_results = 44; + + // Total number of scan results for hotspot 2.0 r2 networks + optional int32 num_hotspot2_r2_network_scan_results = 45; + + // Total number of scans handled by framework (oneshot or otherwise) + optional int32 num_scans = 46; + + // Counts the occurrences of each Wifi score + repeated WifiScoreCount wifi_score_count = 48; } // Information that gets logged for every WiFi connection. @@ -260,7 +300,7 @@ message RouterFingerPrint { // Authentication scheme of the router. optional Auth authentication = 4; - // If the router is hidded. + // If the router is hidden. optional bool hidden = 5; // Channel information. @@ -268,6 +308,9 @@ message RouterFingerPrint { // whether ipv6 is supported. optional bool supports_ipv6 = 7; + + // If the router is a passpoint / hotspot 2.0 network + optional bool passpoint = 8; } message ConnectionEvent { @@ -349,3 +392,21 @@ message RssiPollCount { // Number of RSSI polls with 'rssi' optional int32 count = 2; } + +// Number of occurrences of a specific alert reason value +message AlertReasonCount { + // Alert reason + optional int32 reason = 1; + + // Number of alerts with |reason|. + optional int32 count = 2; +} + +// Counts the number of instances of a specific Wifi Score calculated by WifiScoreReport +message WifiScoreCount { + // Wifi Score + optional int32 score = 1; + + // Number of Wifi score reports with this score + optional int32 count = 2; +} diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResults.java b/tests/wifitests/src/com/android/server/wifi/ScanResults.java index 160902081..fc532701f 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanResults.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanResults.java @@ -138,21 +138,29 @@ public class ScanResults { * @see #generateNativeResults for more details on how results are generated */ public static ScanResults create(int id, int... freqs) { - return new ScanResults(id, -1, generateNativeResults(id, freqs)); + return create(id, generateNativeResults(id, freqs)); + } + public static ScanResults create(int id, boolean allChannelsScanned, int... freqs) { + return create(id, allChannelsScanned, generateNativeResults(id, freqs)); } /** * Create a ScanResults with no IE information. */ public static ScanResults createWithNoIE(int id, int... freqs) { - return new ScanResults(id, -1, generateNativeResults(false, id, freqs)); + return create(id, generateNativeResults(false, id, freqs)); } /** * Create a ScanResults with the given ScanDetails */ public static ScanResults create(int id, ScanDetail... nativeResults) { - return new ScanResults(id, -1, nativeResults); + return new ScanResults(id, false, -1, nativeResults); + } + + public static ScanResults create(int id, boolean allChannelsScanned, + ScanDetail... nativeResults) { + return new ScanResults(id, allChannelsScanned, -1, nativeResults); } /** @@ -162,10 +170,11 @@ public class ScanResults { */ public static ScanResults createOverflowing(int id, int maxResults, ScanDetail... nativeResults) { - return new ScanResults(id, maxResults, nativeResults); + return new ScanResults(id, false, maxResults, nativeResults); } - private ScanResults(int id, int maxResults, ScanDetail... nativeResults) { + private ScanResults(int id, boolean allChannelsScanned, int maxResults, + ScanDetail... nativeResults) { mScanResults = new ScanResult[nativeResults.length]; for (int i = 0; i < nativeResults.length; ++i) { mScanDetails.add(nativeResults[i]); @@ -173,13 +182,13 @@ public class ScanResults { } ScanResult[] sortedScanResults = Arrays.copyOf(mScanResults, mScanResults.length); Arrays.sort(sortedScanResults, SCAN_RESULT_RSSI_COMPARATOR); - mRawScanData = new ScanData(id, 0, sortedScanResults); + mRawScanData = new ScanData(id, 0, 0, allChannelsScanned, sortedScanResults); if (maxResults == -1) { mScanData = mRawScanData; } else { ScanResult[] reducedScanResults = Arrays.copyOf(sortedScanResults, Math.min(sortedScanResults.length, maxResults)); - mScanData = new ScanData(id, 0, reducedScanResults); + mScanData = new ScanData(id, 0, 0, allChannelsScanned, reducedScanResults); } } diff --git a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java index 8228118d8..7a1bdd20b 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java @@ -217,7 +217,7 @@ public class ScanTestUtil { for (int i = 0; i < freqs.length; ++i) { results[i] = createScanResult(freqs[i]); } - return new ScanData(0, 0, bucketsScanned, results); + return new ScanData(0, 0, bucketsScanned, false, results); } public static ScanData[] createScanDatas(int[][] freqs, int[] bucketsScanned) { @@ -272,6 +272,8 @@ public class ScanTestUtil { assertNotNull(prefix + "actual ScanData was null", actual); assertEquals(prefix + "id", expected.getId(), actual.getId()); assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags()); + assertEquals(prefix + "all channels", expected.isAllChannelsScanned(), + actual.isAllChannelsScanned()); assertScanResultsEquals(prefix, expected.getResults(), actual.getResults()); } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java index 022997d67..281ffa163 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java @@ -33,6 +33,7 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; import android.net.wifi.WifiScanner.PnoScanListener; import android.net.wifi.WifiScanner.PnoSettings; +import android.net.wifi.WifiScanner.ScanData; import android.net.wifi.WifiScanner.ScanListener; import android.net.wifi.WifiScanner.ScanSettings; import android.net.wifi.WifiSsid; @@ -71,11 +72,12 @@ public class WifiConnectivityManagerTest { mWifiStateMachine = mockWifiStateMachine(); mWifiConfigManager = mockWifiConfigManager(); mWifiInfo = getWifiInfo(); + mScanData = mockScanData(); mWifiScanner = mockWifiScanner(); mWifiQNS = mockWifiQualifiedNetworkSelector(); mWifiConnectivityManager = new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner, mWifiConfigManager, mWifiInfo, mWifiQNS, mWifiInjector, - mLooper.getLooper()); + mLooper.getLooper(), true); mWifiConnectivityManager.setWifiEnabled(true); when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime()); } @@ -96,6 +98,7 @@ public class WifiConnectivityManagerTest { private WifiQualifiedNetworkSelector mWifiQNS; private WifiStateMachine mWifiStateMachine; private WifiScanner mWifiScanner; + private ScanData mScanData; private WifiConfigManager mWifiConfigManager; private WifiInfo mWifiInfo; private Clock mClock = mock(Clock.class); @@ -128,6 +131,14 @@ public class WifiConnectivityManagerTest { return context; } + ScanData mockScanData() { + ScanData scanData = mock(ScanData.class); + + when(scanData.isAllChannelsScanned()).thenReturn(true); + + return scanData; + } + WifiScanner mockWifiScanner() { WifiScanner scanner = mock(WifiScanner.class); ArgumentCaptor<ScanListener> allSingleScanListenerCaptor = @@ -135,9 +146,8 @@ public class WifiConnectivityManagerTest { doNothing().when(scanner).registerScanListener(allSingleScanListenerCaptor.capture()); - // dummy scan results. QNS PeriodicScanListener bulids scanDetails from - // the fullScanResult and doesn't really use results - final WifiScanner.ScanData[] scanDatas = new WifiScanner.ScanData[1]; + ScanData[] scanDatas = new ScanData[1]; + scanDatas[0] = mScanData; // do a synchronous answer for the ScanListener callbacks doAnswer(new AnswerWithArguments() { @@ -756,8 +766,9 @@ public class WifiConnectivityManagerTest { currentTimeStamp += 2000; when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp); - // Force a connectivity scan - mWifiConnectivityManager.forceConnectivityScan(); + // Allow untrusted networks so WifiConnectivityManager starts a periodic scan + // immediately. + mWifiConnectivityManager.setUntrustedConnectionAllowed(true); // Get the second periodic scan actual time stamp. Note, this scan is not // started from the AlarmManager. @@ -944,4 +955,41 @@ public class WifiConnectivityManagerTest { verify(mWifiStateMachine).autoConnectToNetwork( CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); } + + /** + * Verify that a forced connectivity scan waits for full band scan + * results. + * + * Expected behavior: WifiConnectivityManager doesn't invoke + * WifiStateMachine.autoConnectToNetwork() when full band scan + * results are not available. + */ + @Test + public void waitForFullBandScanResults() { + // Set WiFi to connected state. + mWifiConnectivityManager.handleConnectionStateChanged( + WifiConnectivityManager.WIFI_STATE_CONNECTED); + + // Set up as partial scan results. + when(mScanData.isAllChannelsScanned()).thenReturn(false); + + // Force a connectivity scan which enables WifiConnectivityManager + // to wait for full band scan results. + mWifiConnectivityManager.forceConnectivityScan(); + + // No roaming because no full band scan results. + verify(mWifiStateMachine, times(0)).autoConnectToNetwork( + CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); + + // Set up as full band scan results. + when(mScanData.isAllChannelsScanned()).thenReturn(true); + + // Force a connectivity scan which enables WifiConnectivityManager + // to wait for full band scan results. + mWifiConnectivityManager.forceConnectivityScan(); + + // Roaming attempt because full band scan results are available. + verify(mWifiStateMachine).autoConnectToNetwork( + CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java index 237fc666d..08163e7f2 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java @@ -1440,7 +1440,7 @@ public class WifiLastResortWatchdogTest { int[] levels = {-60, -86, -50, -62, -60}; boolean[] isEphemeral = {false, false, false, false, false}; boolean[] hasEverConnected = {true, false, false, false, false}; - // Buffer potential candidates 1,2,3 & 4 + // Buffer potential candidates 1,2,3,4 & 5 List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, bssids, frequencies, caps, levels, isEphemeral, hasEverConnected); mLastResortWatchdog.updateAvailableNetworks(candidates); @@ -1450,7 +1450,7 @@ public class WifiLastResortWatchdogTest { assertFailureCountEquals(bssids[i], 0, 0, 0); } - //Increment failure count for the first test network ssid & bssid + //Increment failure counts for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) { mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( ssids[1], bssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); @@ -1478,6 +1478,58 @@ public class WifiLastResortWatchdogTest { verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadAssociation(); verify(mWifiMetrics, times(1)).addCountToNumLastResortWatchdogBadDhcpNetworksTotal(3); verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadDhcp(); + + // Simulate wifi connecting after triggering + mLastResortWatchdog.connectedStateTransition(true); + + // Verify that WifiMetrics counted this as a Watchdog success + verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses(); + + // Simulate wifi disconnecting + mLastResortWatchdog.connectedStateTransition(false); + + // Verify that WifiMetrics has still only counted one success + verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses(); + + // Remove the fifth network from candidates + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 4), + Arrays.copyOfRange(mBssids, 0, 4), + Arrays.copyOfRange(mFrequencies, 0, 4), + Arrays.copyOfRange(mCaps, 0, 4), + Arrays.copyOfRange(mLevels, 0, 4), + Arrays.copyOfRange(mIsEphemeral, 0, 4)); + + // Age out the fifth network + for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) { + mLastResortWatchdog.updateAvailableNetworks(candidates); + } + + //Increment failure counts + for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[1], bssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[2], bssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[3], bssids[3], WifiLastResortWatchdog.FAILURE_CODE_DHCP); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + + // Add network #5 back into the candidates + candidates = createFilteredQnsCandidates(ssids, + bssids, frequencies, caps, levels, isEphemeral, hasEverConnected); + + // LastResortWatchdog should reactivate because there is a new network (#5) available, + // Not because it was successful + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Simulate wifi connecting + mLastResortWatchdog.connectedStateTransition(true); + + // Verify that WifiMetrics did not count another success, as the connection could be due + // to the newly available network #5 + verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses(); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index 011682b81..15a5327d6 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; +import android.net.NetworkAgent; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.test.suitebuilder.annotation.SmallTest; @@ -33,6 +34,8 @@ import org.mockito.MockitoAnnotations; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -104,15 +107,51 @@ public class WifiMetricsTest { mDeserializedWifiMetrics = WifiMetricsProto.WifiLog.parseFrom(protoBytes); } - @Test - public void dumpHumanReadable() throws Exception { + /** + * Gets the 'clean dump' proto bytes from mWifiMetrics & deserializes it into + * mDeserializedWifiMetrics + */ + public void cleanDumpProtoAndDeserialize() throws Exception { ByteArrayOutputStream stream = new ByteArrayOutputStream(); PrintWriter writer = new PrintWriter(stream); String[] args = new String[0]; + + when(mClock.elapsedRealtime()).thenReturn(TEST_RECORD_DURATION_MILLIS); + //Test proto dump, by passing in proto arg option + args = new String[]{WifiMetrics.PROTO_DUMP_ARG, WifiMetrics.CLEAN_DUMP_ARG}; mWifiMetrics.dump(null, writer, args); writer.flush(); - assertTrue("stream.toString().contains(\"WifiMetrics\")", - stream.toString().contains("WifiMetrics")); + String protoByteString = stream.toString(); + byte[] protoBytes = Base64.decode(protoByteString, Base64.DEFAULT); + mDeserializedWifiMetrics = WifiMetricsProto.WifiLog.parseFrom(protoBytes); + } + + /** Verifies that dump() includes the expected header */ + @Test + public void stateDumpIncludesHeader() throws Exception { + assertStringContains(getStateDump(), "WifiMetrics"); + } + + /** Verifies that dump() includes correct alert count when there are no alerts. */ + @Test + public void stateDumpAlertCountIsCorrectWithNoAlerts() throws Exception { + assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=()"); + } + + /** Verifies that dump() includes correct alert count when there is one alert. */ + @Test + public void stateDumpAlertCountIsCorrectWithOneAlert() throws Exception { + mWifiMetrics.incrementAlertReasonCount(1); + assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,1)"); + } + + /** Verifies that dump() includes correct alert count when there are multiple alerts. */ + @Test + public void stateDumpAlertCountIsCorrectWithMultipleAlerts() throws Exception { + mWifiMetrics.incrementAlertReasonCount(1); + mWifiMetrics.incrementAlertReasonCount(1); + mWifiMetrics.incrementAlertReasonCount(16); + assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,2),(16,1)"); } @Test @@ -126,6 +165,8 @@ public class WifiMetricsTest { private static final int NUM_OPEN_NETWORKS = 2; private static final int NUM_PERSONAL_NETWORKS = 3; private static final int NUM_ENTERPRISE_NETWORKS = 5; + private static final int NUM_HIDDEN_NETWORKS = 3; + private static final int NUM_PASSPOINT_NETWORKS = 4; private static final boolean TEST_VAL_IS_LOCATION_ENABLED = true; private static final boolean IS_SCANNING_ALWAYS_ENABLED = true; private static final int NUM_NEWTORKS_ADDED_BY_USER = 13; @@ -154,8 +195,53 @@ public class WifiMetricsTest { private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_AUTHENTICATION = 8; private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_DHCP = 9; private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER = 10; + private static final int NUM_LAST_RESORT_WATCHDOG_SUCCESSES = 5; private static final int NUM_RSSI_LEVELS_TO_INCREMENT = 20; private static final int FIRST_RSSI_LEVEL = -80; + private static final int NUM_OPEN_NETWORK_SCAN_RESULTS = 1; + private static final int NUM_PERSONAL_NETWORK_SCAN_RESULTS = 4; + private static final int NUM_ENTERPRISE_NETWORK_SCAN_RESULTS = 3; + private static final int NUM_HIDDEN_NETWORK_SCAN_RESULTS = 1; + private static final int NUM_HOTSPOT2_R1_NETWORK_SCAN_RESULTS = 1; + private static final int NUM_HOTSPOT2_R2_NETWORK_SCAN_RESULTS = 2; + private static final int NUM_SCANS = 5; + private static final int NUM_TOTAL_SCAN_RESULTS = 8; + private static final int MIN_RSSI_LEVEL = -127; + private static final int MAX_RSSI_LEVEL = 0; + private static final int WIFI_SCORE_RANGE_MIN = 0; + private static final int NUM_WIFI_SCORES_TO_INCREMENT = 20; + private static final int WIFI_SCORE_RANGE_MAX = 60; + private static final int NUM_OUT_OF_BOUND_ENTRIES = 10; + + private ScanDetail buildMockScanDetail(boolean hidden, NetworkDetail.HSRelease hSRelease, + String capabilities) { + ScanDetail mockScanDetail = mock(ScanDetail.class); + NetworkDetail mockNetworkDetail = mock(NetworkDetail.class); + ScanResult mockScanResult = mock(ScanResult.class); + when(mockScanDetail.getNetworkDetail()).thenReturn(mockNetworkDetail); + when(mockScanDetail.getScanResult()).thenReturn(mockScanResult); + when(mockNetworkDetail.isHiddenBeaconFrame()).thenReturn(hidden); + when(mockNetworkDetail.getHSRelease()).thenReturn(hSRelease); + mockScanResult.capabilities = capabilities; + return mockScanDetail; + } + + private List<ScanDetail> buildMockScanDetailList() { + List<ScanDetail> mockScanDetails = new ArrayList<ScanDetail>(); + mockScanDetails.add(buildMockScanDetail(true, null, "[ESS]")); + mockScanDetails.add(buildMockScanDetail(false, null, "[WPA2-PSK-CCMP][ESS]")); + mockScanDetails.add(buildMockScanDetail(false, null, "[WPA-PSK-CCMP]")); + mockScanDetails.add(buildMockScanDetail(false, null, "[WPA-PSK-CCMP]")); + mockScanDetails.add(buildMockScanDetail(false, null, "[WEP]")); + mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R2, + "[WPA-EAP-CCMP]")); + mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R2, + "[WPA2-EAP+FT/EAP-CCMP]")); + mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R1, + "[WPA-EAP-CCMP]")); + return mockScanDetails; + } + /** * Set simple metrics, increment others */ @@ -164,6 +250,8 @@ public class WifiMetricsTest { mWifiMetrics.setNumOpenNetworks(NUM_OPEN_NETWORKS); mWifiMetrics.setNumPersonalNetworks(NUM_PERSONAL_NETWORKS); mWifiMetrics.setNumEnterpriseNetworks(NUM_ENTERPRISE_NETWORKS); + mWifiMetrics.setNumHiddenNetworks(NUM_HIDDEN_NETWORKS); + mWifiMetrics.setNumPasspointNetworks(NUM_PASSPOINT_NETWORKS); mWifiMetrics.setNumNetworksAddedByUser(NUM_NEWTORKS_ADDED_BY_USER); mWifiMetrics.setNumNetworksAddedByApps(NUM_NEWTORKS_ADDED_BY_APPS); mWifiMetrics.setIsLocationEnabled(TEST_VAL_IS_LOCATION_ENABLED); @@ -238,11 +326,43 @@ public class WifiMetricsTest { for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER; i++) { mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadOther(); } + for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_SUCCESSES; i++) { + mWifiMetrics.incrementNumLastResortWatchdogSuccesses(); + } for (int i = 0; i < NUM_RSSI_LEVELS_TO_INCREMENT; i++) { for (int j = 0; j <= i; j++) { - mWifiMetrics.incrementRssiPollRssiCount(FIRST_RSSI_LEVEL + i); + mWifiMetrics.incrementRssiPollRssiCount(MIN_RSSI_LEVEL + i); } } + for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) { + mWifiMetrics.incrementRssiPollRssiCount(MIN_RSSI_LEVEL - i); + } + for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) { + mWifiMetrics.incrementRssiPollRssiCount(MAX_RSSI_LEVEL + i); + } + // Test alert-reason clamping. + mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MIN - 1); + mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MAX + 1); + // Simple cases for alert reason. + mWifiMetrics.incrementAlertReasonCount(1); + mWifiMetrics.incrementAlertReasonCount(1); + mWifiMetrics.incrementAlertReasonCount(1); + mWifiMetrics.incrementAlertReasonCount(2); + List<ScanDetail> mockScanDetails = buildMockScanDetailList(); + for (int i = 0; i < NUM_SCANS; i++) { + mWifiMetrics.countScanResults(mockScanDetails); + } + for (int score = WIFI_SCORE_RANGE_MIN; score < NUM_WIFI_SCORES_TO_INCREMENT; score++) { + for (int offset = 0; offset <= score; offset++) { + mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MIN + score); + } + } + for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) { + mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MIN - i); + } + for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) { + mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MAX + i); + } } /** @@ -261,6 +381,8 @@ public class WifiMetricsTest { assertEquals("mDeserializedWifiMetrics.numNetworksAddedByUser " + "== NUM_NEWTORKS_ADDED_BY_USER", mDeserializedWifiMetrics.numNetworksAddedByUser, NUM_NEWTORKS_ADDED_BY_USER); + assertEquals(NUM_HIDDEN_NETWORKS, mDeserializedWifiMetrics.numHiddenNetworks); + assertEquals(NUM_PASSPOINT_NETWORKS, mDeserializedWifiMetrics.numPasspointNetworks); assertEquals("mDeserializedWifiMetrics.numNetworksAddedByApps " + "== NUM_NEWTORKS_ADDED_BY_APPS", mDeserializedWifiMetrics.numNetworksAddedByApps, NUM_NEWTORKS_ADDED_BY_APPS); @@ -318,12 +440,53 @@ public class WifiMetricsTest { mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadDhcp); assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER, mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadOther); + assertEquals(NUM_LAST_RESORT_WATCHDOG_SUCCESSES, + mDeserializedWifiMetrics.numLastResortWatchdogSuccesses); assertEquals(TEST_RECORD_DURATION_SEC, mDeserializedWifiMetrics.recordDurationSec); for (int i = 0; i < NUM_RSSI_LEVELS_TO_INCREMENT; i++) { - assertEquals(FIRST_RSSI_LEVEL + i, mDeserializedWifiMetrics.rssiPollRssiCount[i].rssi); + assertEquals(MIN_RSSI_LEVEL + i, mDeserializedWifiMetrics.rssiPollRssiCount[i].rssi); assertEquals(i + 1, mDeserializedWifiMetrics.rssiPollRssiCount[i].count); } + StringBuilder sb_rssi = new StringBuilder(); + sb_rssi.append("Number of RSSIs = " + mDeserializedWifiMetrics.rssiPollRssiCount.length); + assertTrue(sb_rssi.toString(), (mDeserializedWifiMetrics.rssiPollRssiCount.length + <= (MAX_RSSI_LEVEL - MIN_RSSI_LEVEL + 1))); + assertEquals(2, mDeserializedWifiMetrics.alertReasonCount[0].count); // Clamped reasons. + assertEquals(3, mDeserializedWifiMetrics.alertReasonCount[1].count); + assertEquals(1, mDeserializedWifiMetrics.alertReasonCount[2].count); + assertEquals(3, mDeserializedWifiMetrics.alertReasonCount.length); + assertEquals(NUM_TOTAL_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numTotalScanResults); + assertEquals(NUM_OPEN_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numOpenNetworkScanResults); + assertEquals(NUM_PERSONAL_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numPersonalNetworkScanResults); + assertEquals(NUM_ENTERPRISE_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numEnterpriseNetworkScanResults); + assertEquals(NUM_HIDDEN_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numHiddenNetworkScanResults); + assertEquals(NUM_HOTSPOT2_R1_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numHotspot2R1NetworkScanResults); + assertEquals(NUM_HOTSPOT2_R2_NETWORK_SCAN_RESULTS * NUM_SCANS, + mDeserializedWifiMetrics.numHotspot2R2NetworkScanResults); + assertEquals(NUM_SCANS, + mDeserializedWifiMetrics.numScans); + for (int score_index = 0; score_index < NUM_WIFI_SCORES_TO_INCREMENT; score_index++) { + assertEquals(WIFI_SCORE_RANGE_MIN + score_index, + mDeserializedWifiMetrics.wifiScoreCount[score_index].score); + assertEquals(score_index + 1, + mDeserializedWifiMetrics.wifiScoreCount[score_index].count); + } + StringBuilder sb_wifi_score = new StringBuilder(); + sb_wifi_score.append("Number of wifi_scores = " + + mDeserializedWifiMetrics.wifiScoreCount.length); + assertTrue(sb_wifi_score.toString(), (mDeserializedWifiMetrics.wifiScoreCount.length + <= (WIFI_SCORE_RANGE_MAX - WIFI_SCORE_RANGE_MIN + 1))); + StringBuilder sb_wifi_limits = new StringBuilder(); + sb_wifi_limits.append("Wifi Score limit is " + NetworkAgent.WIFI_BASE_SCORE + + ">= " + WIFI_SCORE_RANGE_MAX); + assertTrue(sb_wifi_limits.toString(), NetworkAgent.WIFI_BASE_SCORE <= WIFI_SCORE_RANGE_MAX); } /** @@ -461,6 +624,8 @@ public class WifiMetricsTest { dumpProtoAndDeserialize(); //Check there are only 3 connection events assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 4); + assertEquals(mDeserializedWifiMetrics.rssiPollRssiCount.length, 0); + assertEquals(mDeserializedWifiMetrics.alertReasonCount.length, 0); // Create 2 ConnectionEvents mWifiMetrics.startConnectionEvent(null, "BLUE", @@ -479,4 +644,35 @@ public class WifiMetricsTest { //Check there are only 2 connection events assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 2); } + + /** + * Tests that after setting metrics values they can be serialized and deserialized with the + * $ adb shell dumpsys wifi wifiMetricsProto clean + */ + @Test + public void testClearMetricsDump() throws Exception { + setAndIncrementMetrics(); + startAndEndConnectionEventSucceeds(); + cleanDumpProtoAndDeserialize(); + assertDeserializedMetricsCorrect(); + assertEquals("mDeserializedWifiMetrics.connectionEvent.length", + 2, mDeserializedWifiMetrics.connectionEvent.length); + } + + private void assertStringContains( + String actualString, String expectedSubstring) { + assertTrue("Expected text not found in: " + actualString, + actualString.contains(expectedSubstring)); + } + + private String getStateDump() { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + PrintWriter writer = new PrintWriter(stream); + String[] args = new String[0]; + mWifiMetrics.dump(null, writer, args); + writer.flush(); + return stream.toString(); + } } + + diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java index 92de7d48b..1726e7d32 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java @@ -2270,4 +2270,59 @@ public class WifiQualifiedNetworkSelectorTest { verifySelectedResult(chosenScanResult, candidate); } + + /** + * Case #47 Choose the currently connected BSSID after a firmware initiated roaming. + * + * In this test. we simulate following scenario: + * Two APs are found in scan results + * BSSID1 is @ 2.4GHz with RSSI -78 + * BSSID2 is @ 2.4Ghz with RSSI -77 + * BSSID2 is chosen because of stronger RSSI. Then firmware initiates + * a roaming to BSSID1. QNS now selects BSSID1 because of the bonus for currently + * connected network even if BSSID 2 has slightly stronger signal strengh. + * + * expect BSSID2 to be chosen after firmware roaming + */ + @Test + public void chooseCurrentlyConnectedBssid() { + String[] ssids = {"\"test1\"", "\"test1\""}; + String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"}; + int[] frequencies = {2437, 2437}; + String[] caps = {"[ESS]", "[ESS]"}; + int[] levels = {-78, -77}; + int[] security = {SECURITY_NONE, SECURITY_NONE}; + + List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels); + WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security); + prepareConfigStore(savedConfigs); + + final List<WifiConfiguration> savedNetwork = Arrays.asList(savedConfigs); + when(mWifiConfigManager.getSavedNetworks()).thenReturn(savedNetwork); + scanResultLinkConfiguration(savedConfigs, scanDetails); + + // Choose BSSID2 as it has stronger RSSI + ScanResult chosenScanResult = scanDetails.get(1).getScanResult(); + WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, + false, scanDetails, false, false, true, false); + verifySelectedResult(chosenScanResult, candidate); + when(mWifiInfo.getBSSID()).thenReturn(bssids[1]); + when(mWifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(true); + + // Choose BSSID2 as it has stronger RSSI and it is the currently connected BSSID + chosenScanResult = scanDetails.get(1).getScanResult(); + candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true, + false, scanDetails, false, true, false, false); + verifySelectedResult(chosenScanResult, candidate); + + // Pretend firmware roamed the device to BSSID1 + when(mWifiInfo.getBSSID()).thenReturn(bssids[0]); + + // Choose BSSID1 as it is the currently connected BSSID even if BSSID2 has slightly + // higher RSSI value. + chosenScanResult = scanDetails.get(0).getScanResult(); + candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true, + false, scanDetails, false, true, false, false); + verifySelectedResult(chosenScanResult, candidate); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index 53d8f46aa..a881d8f04 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; import android.app.ActivityManager; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; @@ -41,6 +42,7 @@ import android.net.wifi.WifiSsid; import android.net.wifi.p2p.IWifiP2pManager; import android.os.BatteryStats; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -56,6 +58,8 @@ import android.os.UserManager; import android.provider.Settings; import android.security.KeyStore; import android.telephony.TelephonyManager; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.SmallTest; import android.util.Base64; import android.util.Log; @@ -218,13 +222,19 @@ public class WifiStateMachineTest { Context context = mock(Context.class); when(context.getPackageManager()).thenReturn(pkgMgr); - when(context.getContentResolver()).thenReturn(mock(ContentResolver.class)); MockResources resources = new com.android.server.wifi.MockResources(); when(context.getResources()).thenReturn(resources); - ContentResolver cr = mock(ContentResolver.class); - when(context.getContentResolver()).thenReturn(cr); + MockContentResolver mockContentResolver = new MockContentResolver(); + mockContentResolver.addProvider(Settings.AUTHORITY, + new MockContentProvider(context) { + @Override + public Bundle call(String method, String arg, Bundle extras) { + return new Bundle(); + } + }); + when(context.getContentResolver()).thenReturn(mockContentResolver); when(context.getSystemService(Context.POWER_SERVICE)).thenReturn( new PowerManager(context, mock(IPowerManager.class), new Handler())); diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/BaseWifiScannerImplTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/BaseWifiScannerImplTest.java index 1355961c1..767cddfea 100644 --- a/tests/wifitests/src/com/android/server/wifi/scanner/BaseWifiScannerImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/scanner/BaseWifiScannerImplTest.java @@ -89,6 +89,12 @@ public abstract class BaseWifiScannerImplTest { when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime()); } + protected boolean isAllChannelsScanned(int band) { + ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection(); + collection.addBand(band); + return collection.isAllChannels(); + } + protected Set<Integer> expectedBandScanFreqs(int band) { ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection(); collection.addBand(band); @@ -115,7 +121,8 @@ public abstract class BaseWifiScannerImplTest { doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(), - ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), false); + ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ), + 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), false); } @Test @@ -144,7 +151,8 @@ public abstract class BaseWifiScannerImplTest { doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(), - ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), true); + ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ), + 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), true); } /** @@ -346,7 +354,7 @@ public abstract class BaseWifiScannerImplTest { .withBasePeriod(10000) .withMaxApPerScan(10) .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, - WifiScanner.WIFI_BAND_5_GHZ) + WifiScanner.WIFI_BAND_BOTH_WITH_DFS) .build(); WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); @@ -361,15 +369,17 @@ public abstract class BaseWifiScannerImplTest { expectSuccessfulSingleScan(order, eventHandler, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(), - ScanResults.create(0, 2400, 2450, 2450), false); + ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ), + 2400, 2450, 2450), false); // start second scan assertTrue(mScanner.startSingleScan(settings2, eventHandler)); expectSuccessfulSingleScan(order, eventHandler, - expectedBandScanFreqs(WifiScanner.WIFI_BAND_5_GHZ), + expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH_WITH_DFS), new HashSet<Integer>(), - ScanResults.create(0, 5150, 5175), false); + ScanResults.create(0, true, + 5150, 5175), false); verifyNoMoreInteractions(eventHandler); } @@ -412,7 +422,8 @@ public abstract class BaseWifiScannerImplTest { } ArrayList<ScanResult> scanDataResults = new ArrayList<>(fullResults); Collections.sort(scanDataResults, ScanResults.SCAN_RESULT_RSSI_COMPARATOR); - ScanData scanData = new ScanData(0, 0, + ScanData scanData = new ScanData(0, 0, 0, + isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ), scanDataResults.toArray(new ScanResult[scanDataResults.size()])); Set<Integer> expectedScan = expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ); diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/KnownBandsChannelHelperTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/KnownBandsChannelHelperTest.java index ed466835d..3e482a9fe 100644 --- a/tests/wifitests/src/com/android/server/wifi/scanner/KnownBandsChannelHelperTest.java +++ b/tests/wifitests/src/com/android/server/wifi/scanner/KnownBandsChannelHelperTest.java @@ -290,6 +290,7 @@ public class KnownBandsChannelHelperTest { assertTrue(mChannelCollection.isEmpty()); assertFalse(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -310,6 +311,7 @@ public class KnownBandsChannelHelperTest { assertTrue(mChannelCollection.isEmpty()); assertFalse(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -329,6 +331,7 @@ public class KnownBandsChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -348,6 +351,7 @@ public class KnownBandsChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -368,6 +372,7 @@ public class KnownBandsChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -388,6 +393,7 @@ public class KnownBandsChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -408,6 +414,7 @@ public class KnownBandsChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -428,6 +435,7 @@ public class KnownBandsChannelHelperTest { assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); assertTrue(mChannelCollection.containsChannel(5600)); + assertTrue(mChannelCollection.isAllChannels()); } /** @@ -442,6 +450,7 @@ public class KnownBandsChannelHelperTest { WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); mChannelCollection.fillBucketSettings(bucketSettings, 2); assertThat(bucketSettings, bandIs(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -456,6 +465,27 @@ public class KnownBandsChannelHelperTest { WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); mChannelCollection.fillBucketSettings(bucketSettings, 2); assertThat(bucketSettings, bandIs(WifiScanner.WIFI_BAND_BOTH)); + assertFalse(mChannelCollection.isAllChannels()); + } + + + /** + * Add enough channels across all bands that the max channels is exceeded + */ + @Test + public void addChannel_addAllAvailableChannels() { + mChannelCollection.addChannel(2400); + mChannelCollection.addChannel(2450); + mChannelCollection.addChannel(5150); + mChannelCollection.addChannel(5175); + mChannelCollection.addChannel(5600); + mChannelCollection.addChannel(5650); + mChannelCollection.addChannel(5660); + + WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); + mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE); + assertThat(bucketSettings, channelsAre(2400, 2450, 5150, 5175, 5600, 5650, 5660)); + assertTrue(mChannelCollection.isAllChannels()); } } } diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java index cbf6fe5d1..2863b9f90 100644 --- a/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java +++ b/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java @@ -199,7 +199,7 @@ public class NoBandChannelHelperTest { * {@link com.android.server.wifi.scanner.NoBandChannelHelper.NoBandChannelCollection}. */ @SmallTest - public static class KnownBandsChannelCollectionTest { + public static class NoBandsChannelCollectionTest { ChannelHelper.ChannelCollection mChannelCollection; /** @@ -225,6 +225,7 @@ public class NoBandChannelHelperTest { assertTrue(mChannelCollection.isEmpty()); assertFalse(mChannelCollection.containsChannel(2400)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -244,6 +245,7 @@ public class NoBandChannelHelperTest { assertTrue(mChannelCollection.isEmpty()); assertFalse(mChannelCollection.containsChannel(2400)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -262,6 +264,7 @@ public class NoBandChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); + assertTrue(mChannelCollection.isAllChannels()); } /** @@ -281,6 +284,7 @@ public class NoBandChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -301,6 +305,7 @@ public class NoBandChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertFalse(mChannelCollection.containsChannel(5150)); + assertFalse(mChannelCollection.isAllChannels()); } /** @@ -320,6 +325,7 @@ public class NoBandChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); + assertTrue(mChannelCollection.isAllChannels()); } /** @@ -339,6 +345,7 @@ public class NoBandChannelHelperTest { assertFalse(mChannelCollection.isEmpty()); assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); + assertTrue(mChannelCollection.isAllChannels()); } /** @@ -359,6 +366,7 @@ public class NoBandChannelHelperTest { assertTrue(mChannelCollection.containsChannel(2400)); assertTrue(mChannelCollection.containsChannel(5150)); assertTrue(mChannelCollection.containsChannel(5600)); + assertTrue(mChannelCollection.isAllChannels()); } /** @@ -373,6 +381,7 @@ public class NoBandChannelHelperTest { WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); mChannelCollection.fillBucketSettings(bucketSettings, 2); assertThat(bucketSettings, bandIs(ALL_BANDS)); + assertFalse(mChannelCollection.isAllChannels()); // can't determine from just channels } /** @@ -387,6 +396,7 @@ public class NoBandChannelHelperTest { WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); mChannelCollection.fillBucketSettings(bucketSettings, 2); assertThat(bucketSettings, bandIs(ALL_BANDS)); + assertFalse(mChannelCollection.isAllChannels()); // can't determine from just channels } } } diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/SupplicantPnoScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/SupplicantPnoScannerTest.java index 39709f84d..560710f79 100644 --- a/tests/wifitests/src/com/android/server/wifi/scanner/SupplicantPnoScannerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/scanner/SupplicantPnoScannerTest.java @@ -45,6 +45,7 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -90,7 +91,7 @@ public class SupplicantPnoScannerTest { WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); - ScanResults scanResults = createDummyScanResults(); + ScanResults scanResults = createDummyScanResults(false); InOrder order = inOrder(pnoEventHandler, mWifiNative); // Start PNO scan @@ -111,7 +112,7 @@ public class SupplicantPnoScannerTest { WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); WifiNative.ScanSettings settings = createDummyScanSettings(); - ScanResults scanResults = createDummyScanResults(); + ScanResults scanResults = createDummyScanResults(true); InOrder order = inOrder(eventHandler, mWifiNative); // Start PNO scan @@ -181,7 +182,7 @@ public class SupplicantPnoScannerTest { WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); WifiNative.ScanSettings settings = createDummyScanSettings(); - ScanResults scanResults = createDummyScanResults(); + ScanResults scanResults = createDummyScanResults(true); InOrder order = inOrder(eventHandler, mWifiNative); // Start PNO scan @@ -214,12 +215,126 @@ public class SupplicantPnoScannerTest { verifyNoMoreInteractions(pnoEventHandler); } + /** + * Verify that the HW PNO scan stop failure still resets the PNO scan state. + * 1. Start Hw PNO. + * 2. Stop Hw PNO scan which raises a stop command to WifiNative which is failed. + * 3. Now restart a new PNO scan to ensure that the failure was cleanly handled. + */ + @Test + public void ignoreHwDisconnectedPnoScanStopFailure() { + createScannerWithHwPnoScanSupport(); + + WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); + WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); + + // Start PNO scan + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + + // Fail the PNO stop. + when(mWifiNative.setPnoScan(false)).thenReturn(false); + assertTrue(mScanner.resetHwPnoList()); + assertTrue("dispatch pno monitor alarm", + mAlarmManager.dispatch( + SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); + mLooper.dispatchAll(); + verify(mWifiNative).setPnoScan(false); + + // Add a new PNO scan request and ensure it runs successfully. + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + assertTrue("dispatch pno monitor alarm", + mAlarmManager.dispatch( + SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); + mLooper.dispatchAll(); + InOrder order = inOrder(pnoEventHandler, mWifiNative); + ScanResults scanResults = createDummyScanResults(false); + expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); + verifyNoMoreInteractions(pnoEventHandler); + } + + /** + * Verify that the HW PNO scan is forcefully stopped (bypass debounce logic) and restarted when + * settings change. + * 1. Start Hw PNO. + * 2. Stop Hw PNO . + * 3. Now restart a new PNO scan with different settings. + * 4. Ensure that the stop was issued before we start again. + */ + @Test + public void forceRestartHwDisconnectedPnoScanWhenSettingsChange() { + createScannerWithHwPnoScanSupport(); + + WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); + WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); + InOrder order = inOrder(pnoEventHandler, mWifiNative); + + // Start PNO scan + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + expectHwDisconnectedPnoScanStart(order, pnoSettings); + + // Stop PNO now. This should trigger the debounce timer and not stop PNO. + assertTrue(mScanner.resetHwPnoList()); + assertTrue(mAlarmManager.isPending( + SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); + order.verify(mWifiNative, never()).setPnoScan(false); + + // Now restart PNO scan with an extra network in settings. + pnoSettings.networkList = + Arrays.copyOf(pnoSettings.networkList, pnoSettings.networkList.length + 1); + pnoSettings.networkList[pnoSettings.networkList.length - 1] = + createDummyPnoNetwork("ssid_pno_new", 6, 6); + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + + // This should bypass the debounce timer and stop PNO scan immediately and then start + // a new debounce timer for the start. + order.verify(mWifiNative).setPnoScan(false); + + // Trigger the debounce timer and ensure we start PNO scan again. + mAlarmManager.dispatch(SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG); + mLooper.dispatchAll(); + order.verify(mWifiNative).setPnoScan(true); + } + + /** + * Verify that the HW PNO scan is not forcefully stopped (bypass debounce logic) when + * settings don't change. + * 1. Start Hw PNO. + * 2. Stop Hw PNO . + * 3. Now restart a new PNO scan with same settings. + * 4. Ensure that the stop was never issued. + */ + @Test + public void noForceRestartHwDisconnectedPnoScanWhenNoSettingsChange() { + createScannerWithHwPnoScanSupport(); + + WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); + WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); + InOrder order = inOrder(pnoEventHandler, mWifiNative); + + // Start PNO scan + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + expectHwDisconnectedPnoScanStart(order, pnoSettings); + + // Stop PNO now. This should trigger the debounce timer and not stop PNO. + assertTrue(mScanner.resetHwPnoList()); + assertTrue(mAlarmManager.isPending( + SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); + order.verify(mWifiNative, never()).setPnoScan(false); + + // Now restart PNO scan with the same settings. + startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); + + // Trigger the debounce timer and ensure that we neither stop/start. + mLooper.dispatchAll(); + order.verify(mWifiNative, never()).setPnoScan(anyBoolean()); + } + private void doSuccessfulSwPnoScanTest(boolean isConnectedPno) { WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(isConnectedPno); WifiNative.ScanEventHandler scanEventHandler = mock(WifiNative.ScanEventHandler.class); WifiNative.ScanSettings scanSettings = createDummyScanSettings(); - ScanResults scanResults = createDummyScanResults(); + ScanResults scanResults = createDummyScanResults(false); InOrder order = inOrder(scanEventHandler, mWifiNative); @@ -243,18 +358,20 @@ public class SupplicantPnoScannerTest { new SupplicantWifiScannerImpl(mContext, mWifiNative, mLooper.getLooper(), mClock); } + private WifiNative.PnoNetwork createDummyPnoNetwork(String ssid, int networkId, int priority) { + WifiNative.PnoNetwork pnoNetwork = new WifiNative.PnoNetwork(); + pnoNetwork.ssid = ssid; + pnoNetwork.networkId = networkId; + pnoNetwork.priority = priority; + return pnoNetwork; + } + private WifiNative.PnoSettings createDummyPnoSettings(boolean isConnected) { WifiNative.PnoSettings pnoSettings = new WifiNative.PnoSettings(); pnoSettings.isConnected = isConnected; pnoSettings.networkList = new WifiNative.PnoNetwork[2]; - pnoSettings.networkList[0] = new WifiNative.PnoNetwork(); - pnoSettings.networkList[0].ssid = "ssid_pno_1"; - pnoSettings.networkList[0].networkId = 1; - pnoSettings.networkList[0].priority = 1; - pnoSettings.networkList[1] = new WifiNative.PnoNetwork(); - pnoSettings.networkList[1].ssid = "ssid_pno_2"; - pnoSettings.networkList[1].networkId = 2; - pnoSettings.networkList[1].priority = 2; + pnoSettings.networkList[0] = createDummyPnoNetwork("ssid_pno_1", 1, 1); + pnoSettings.networkList[1] = createDummyPnoNetwork("ssid_pno_2", 2, 2); return pnoSettings; } @@ -268,13 +385,15 @@ public class SupplicantPnoScannerTest { return settings; } - private ScanResults createDummyScanResults() { - return ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450); + private ScanResults createDummyScanResults(boolean allChannelsScanned) { + return ScanResults.create(0, allChannelsScanned, 2400, 2450, 2450, 2400, 2450, 2450, 2400, + 2450, 2450); } private void startSuccessfulPnoScan(WifiNative.ScanSettings scanSettings, WifiNative.PnoSettings pnoSettings, WifiNative.ScanEventHandler scanEventHandler, WifiNative.PnoEventHandler pnoEventHandler) { + reset(mWifiNative); when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true); when(mWifiNative.enableNetworkWithoutConnect(anyInt())).thenReturn(true); // Scans succeed @@ -300,9 +419,8 @@ public class SupplicantPnoScannerTest { /** * Verify that the PNO scan was successfully started. */ - private void expectSuccessfulHwDisconnectedPnoScan(InOrder order, - WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler, - ScanResults scanResults) { + private void expectHwDisconnectedPnoScanStart(InOrder order, + WifiNative.PnoSettings pnoSettings) { for (int i = 0; i < pnoSettings.networkList.length; i++) { WifiNative.PnoNetwork network = pnoSettings.networkList[i]; order.verify(mWifiNative).setNetworkVariable(network.networkId, @@ -311,6 +429,17 @@ public class SupplicantPnoScannerTest { } // Verify HW PNO scan started order.verify(mWifiNative).setPnoScan(true); + } + + /** + * + * 1. Verify that the PNO scan was successfully started. + * 2. Send scan results and ensure that the |onPnoNetworkFound| callback was called. + */ + private void expectSuccessfulHwDisconnectedPnoScan(InOrder order, + WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler, + ScanResults scanResults) { + expectHwDisconnectedPnoScanStart(order, pnoSettings); // Setup scan results when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList()); diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java index 03a11dceb..3498b53fc 100644 --- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java +++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -371,7 +371,7 @@ public class WifiScanningServiceTest { assertTrue("dump did not contain log with type=" + type + ", id=" + id + ": " + serviceDump + "\n", logLineRegex.matcher(serviceDump).find()); - } + } private void assertDumpContainsCallbackLog(String callback, int id, String extra) { String serviceDump = dumpService(); @@ -382,7 +382,7 @@ public class WifiScanningServiceTest { assertTrue("dump did not contain callback log with callback=" + callback + ", id=" + id + ", extra=" + extra + ": " + serviceDump + "\n", logLineRegex.matcher(serviceDump).find()); - } + } @Test public void construct() throws Exception { @@ -507,10 +507,10 @@ public class WifiScanningServiceTest { */ @Test public void sendSingleScanBandRequest() throws Exception { - WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, - 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); + WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, + 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), - ScanResults.create(0, 2400, 5150, 5175)); + ScanResults.create(0, true, 2400, 5150, 5175)); } /** @@ -518,13 +518,25 @@ public class WifiScanningServiceTest { */ @Test public void sendSingleScanChannelsRequest() throws Exception { - WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, - 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); + WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400, 5150, 5175), + 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), ScanResults.create(0, 2400, 5150, 5175)); } /** + * Do a single scan for a list of all channels and verify that it is successful. + */ + @Test + public void sendSingleScanAllChannelsRequest() throws Exception { + WifiScanner.ScanSettings requestSettings = createRequest( + channelsToSpec(2400, 2450, 5150, 5175, 5600, 5650, 5660), + 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); + doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), + ScanResults.create(0, true, 2400, 5150, 5175)); + } + + /** * Do a single scan with no results and verify that it is successful. */ @Test @@ -1655,8 +1667,8 @@ public class WifiScanningServiceTest { sendSingleScanRequest(controlChannel, requestId, requestSettings, null); // Can't call |disconnect| here because that sends |CMD_CHANNEL_DISCONNECT| followed by // |CMD_CHANNEL_DISCONNECTED|. - controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED, 0, - 0, null)); + controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED, + AsyncChannel.STATUS_REMOTE_DISCONNECTION, 0, null)); // Now process the above 2 actions. This should result in first processing the single scan // request (which forwards the request to SingleScanStateMachine) and then processing the @@ -1671,4 +1683,55 @@ public class WifiScanningServiceTest { logLineRegex.matcher(serviceDump).find()); } + /** + * Tries to simulate the race scenario where a client is disconnected immediately after single + * scan request is sent to |SingleScanStateMachine|. + */ + @Test + public void sendScanRequestAfterUnsuccessfulSend() throws Exception { + WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, + 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); + int requestId = 9; + + startServiceAndLoadDriver(); + Handler handler = mock(Handler.class); + BidirectionalAsyncChannel controlChannel = connectChannel(handler); + mLooper.dispatchAll(); + + when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class), + any(WifiNative.ScanEventHandler.class))).thenReturn(true); + ScanResults results = ScanResults.create(0, 2400); + when(mWifiScannerImpl.getLatestSingleScanResults()) + .thenReturn(results.getRawScanData()); + + InOrder order = inOrder(mWifiScannerImpl, handler); + + sendSingleScanRequest(controlChannel, requestId, requestSettings, null); + mLooper.dispatchAll(); + WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order, + computeSingleScanNativeSettings(requestSettings)); + verifySuccessfulResponse(order, handler, requestId); + + eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); + mLooper.dispatchAll(); + verifyScanResultsRecieved(order, handler, requestId, results.getScanData()); + verifySingleScanCompletedRecieved(order, handler, requestId); + verifyNoMoreInteractions(handler); + + controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED, + AsyncChannel.STATUS_SEND_UNSUCCESSFUL, 0, null)); + mLooper.dispatchAll(); + + sendSingleScanRequest(controlChannel, requestId, requestSettings, null); + mLooper.dispatchAll(); + WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order, + computeSingleScanNativeSettings(requestSettings)); + verifySuccessfulResponse(order, handler, requestId); + + eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); + mLooper.dispatchAll(); + verifyScanResultsRecieved(order, handler, requestId, results.getScanData()); + verifySingleScanCompletedRecieved(order, handler, requestId); + verifyNoMoreInteractions(handler); + } } |