summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com>2016-12-09 14:23:11 +0530
committerAnjaneedevi Kapparapu <akappa@codeaurora.org>2016-12-09 14:32:38 +0530
commit3ce645f274856faa76d263fbe6ddd32bda36f54a (patch)
tree2211f3742f423259c27a3d85c84896404051cc85
parent7370404484797419d889ef09bd5a7b7a0db1d1f0 (diff)
parent173bf91cfe966d84dc42e3444140c692975278c6 (diff)
downloadandroid_frameworks_opt_net_wifi-3ce645f274856faa76d263fbe6ddd32bda36f54a.tar.gz
android_frameworks_opt_net_wifi-3ce645f274856faa76d263fbe6ddd32bda36f54a.tar.bz2
android_frameworks_opt_net_wifi-3ce645f274856faa76d263fbe6ddd32bda36f54a.zip
To Backport the N-Mr1 Changes
To Backport the N-Mr1 Changes Merge remote-tracking branch 'origin/wlan-aosp.lnx.2.0.c1-rel' into wlan-aosp.lnx.2.0.c1-dev Change-Id: I7ff8442f627deb70400ad84a8712c27dffdbcda1 CRs-Fixed: 1099457
-rw-r--r--service/Android.mk6
-rw-r--r--service/java/com/android/server/wifi/FrameworkFacade.java7
-rw-r--r--service/java/com/android/server/wifi/ScanDetail.java3
-rw-r--r--service/java/com/android/server/wifi/ScanDetailCache.java5
-rw-r--r--service/java/com/android/server/wifi/SoftApManager.java265
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java84
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java51
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java213
-rw-r--r--service/java/com/android/server/wifi/WifiController.java100
-rw-r--r--service/java/com/android/server/wifi/WifiCountryCode.java32
-rw-r--r--service/java/com/android/server/wifi/WifiLastResortWatchdog.java32
-rw-r--r--service/java/com/android/server/wifi/WifiLockManager.java329
-rw-r--r--service/java/com/android/server/wifi/WifiLogger.java26
-rw-r--r--service/java/com/android/server/wifi/WifiLoggerHal.java9
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java253
-rw-r--r--service/java/com/android/server/wifi/WifiMonitor.java7
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java21
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkHistory.java9
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java14
-rw-r--r--service/java/com/android/server/wifi/WifiScoreReport.java4
-rwxr-xr-xservice/java/com/android/server/wifi/WifiServiceImpl.java344
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java269
-rw-r--r--service/java/com/android/server/wifi/configparse/ConfigBuilder.java50
-rw-r--r--service/java/com/android/server/wifi/hotspot2/NetworkDetail.java39
-rw-r--r--service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java16
-rw-r--r--service/java/com/android/server/wifi/scanner/ChannelHelper.java4
-rw-r--r--service/java/com/android/server/wifi/scanner/KnownBandsChannelHelper.java6
-rw-r--r--service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java5
-rw-r--r--service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java47
-rw-r--r--service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java189
-rw-r--r--service/java/com/android/server/wifi/util/InformationElementUtil.java2
-rw-r--r--service/java/com/android/server/wifi/util/TelephonyUtil.java115
-rw-r--r--service/jni/com_android_server_wifi_WifiNative.cpp33
-rw-r--r--service/proto/wifi.proto75
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanResults.java23
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java4
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java73
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java6
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java150
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java189
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java28
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java66
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java320
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiLoggerTest.java56
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java215
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java92
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java85
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/BaseWifiScannerImplTest.java25
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/KnownBandsChannelHelperTest.java30
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java12
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/SupplicantPnoScannerTest.java163
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java693
52 files changed, 3724 insertions, 1170 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/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index c2579e089..cb03f7a2b 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -49,8 +49,9 @@ public class FrameworkFacade {
}
public BaseWifiLogger makeRealLogger(
- WifiStateMachine stateMachine, WifiNative wifiNative, BuildProperties buildProperties) {
- return new WifiLogger(stateMachine, wifiNative, buildProperties);
+ Context context, WifiStateMachine stateMachine, WifiNative wifiNative,
+ BuildProperties buildProperties) {
+ return new WifiLogger(context, stateMachine, wifiNative, buildProperties);
}
public boolean setIntegerSetting(Context context, String name, int def) {
@@ -144,7 +145,7 @@ public class FrameworkFacade {
String countryCode, ArrayList<Integer> allowed2GChannels,
SoftApManager.Listener listener) {
return new SoftApManager(
- context, looper, wifiNative, nmService, cm, countryCode,
+ looper, wifiNative, nmService, countryCode,
allowed2GChannels, listener);
}
diff --git a/service/java/com/android/server/wifi/ScanDetail.java b/service/java/com/android/server/wifi/ScanDetail.java
index 1a5a923c0..dc87a5bd1 100644
--- a/service/java/com/android/server/wifi/ScanDetail.java
+++ b/service/java/com/android/server/wifi/ScanDetail.java
@@ -59,6 +59,9 @@ public class ScanDetail {
if (networkDetail.is80211McResponderSupport()) {
mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
}
+ if (networkDetail.isInterworking()) {
+ mScanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
+ }
mMatches = null;
}
diff --git a/service/java/com/android/server/wifi/ScanDetailCache.java b/service/java/com/android/server/wifi/ScanDetailCache.java
index e3f31920e..cb44e2af9 100644
--- a/service/java/com/android/server/wifi/ScanDetailCache.java
+++ b/service/java/com/android/server/wifi/ScanDetailCache.java
@@ -85,11 +85,6 @@ public class ScanDetailCache {
return size() == 0;
}
- ScanDetail getFirst() {
- Iterator<ScanDetail> it = mMap.values().iterator();
- return it.hasNext() ? it.next() : null;
- }
-
Collection<String> keySet() {
return mMap.keySet();
}
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 4fdc6bfb0..98dad2bec 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -20,14 +20,8 @@ import static com.android.server.wifi.util.ApConfigUtil.ERROR_GENERIC;
import static com.android.server.wifi.util.ApConfigUtil.ERROR_NO_CHANNEL;
import static com.android.server.wifi.util.ApConfigUtil.SUCCESS;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.net.InterfaceConfiguration;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
@@ -41,6 +35,7 @@ import com.android.server.wifi.util.ApConfigUtil;
import java.util.ArrayList;
import java.util.Locale;
+import android.os.UserHandle;
/**
* Manage WiFi in AP mode.
@@ -48,12 +43,9 @@ import java.util.Locale;
*/
public class SoftApManager {
private static final String TAG = "SoftApManager";
- private boolean restartSap = false;
- private final Context mContext;
private final INetworkManagementService mNmService;
private final WifiNative mWifiNative;
- private final ConnectivityManager mConnectivityManager;
private final ArrayList<Integer> mAllowed2GChannels;
private final String mCountryCode;
@@ -67,16 +59,6 @@ public class SoftApManager {
private final Listener mListener;
- private static class TetherStateChange {
- public ArrayList<String> available;
- public ArrayList<String> active;
-
- TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
- available = av;
- active = ac;
- }
- }
-
/**
* Listener for soft AP state changes.
*/
@@ -89,40 +71,21 @@ public class SoftApManager {
void onStateChanged(int state, int failureReason);
}
- public SoftApManager(Context context,
- Looper looper,
+ public SoftApManager(Looper looper,
WifiNative wifiNative,
INetworkManagementService nmService,
- ConnectivityManager connectivityManager,
String countryCode,
ArrayList<Integer> allowed2GChannels,
Listener listener) {
mStateMachine = new SoftApStateMachine(looper);
- mContext = context;
mNmService = nmService;
mWifiNative = wifiNative;
- mConnectivityManager = connectivityManager;
mCountryCode = countryCode;
mAllowed2GChannels = allowed2GChannels;
mListener = listener;
mInterfaceName = mWifiNative.getInterfaceName();
-
- /* Register receiver for tether state changes. */
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- ArrayList<String> available = intent.getStringArrayListExtra(
- ConnectivityManager.EXTRA_AVAILABLE_TETHER);
- ArrayList<String> active = intent.getStringArrayListExtra(
- ConnectivityManager.EXTRA_ACTIVE_TETHER);
- mStateMachine.sendMessage(
- SoftApStateMachine.CMD_TETHER_STATE_CHANGE,
- new TetherStateChange(available, active));
- }
- }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
}
/**
@@ -239,116 +202,19 @@ public class SoftApManager {
Log.d(TAG, "Soft AP is stopped");
}
- private boolean startTethering(ArrayList<String> available) {
- String[] wifiRegexs = mConnectivityManager.getTetherableWifiRegexs();
-
- for (String intf : available) {
- for (String regex : wifiRegexs) {
- if (intf.matches(regex)) {
- if (mCreateNewInterface) {
- /**
- * If we turn on SoftAp follwed by Wifi, sometimes TetherState
- * Machine still advertise the list of interface as Up. But in
- * concurrency case our interfcae for softap is softap0,
- * hence start tethering only on softap0.
- */
- if (!intf.matches(mInterfaceName)) {
- Log.e(TAG,"For STA + SoftAp concurrency skip tethering on " + intf);
- continue;
- }
- }
- try {
- InterfaceConfiguration ifcg =
- mNmService.getInterfaceConfig(intf);
- if (ifcg != null) {
- /* IP/netmask: 192.168.43.1/255.255.255.0 */
- ifcg.setLinkAddress(new LinkAddress(
- NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
- ifcg.setInterfaceUp();
-
- mNmService.setInterfaceConfig(intf, ifcg);
- }
- } catch (Exception e) {
- Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
- return false;
- }
-
- if (mConnectivityManager.tether(intf)
- != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
- Log.e(TAG, "Error tethering on " + intf);
- return false;
- }
- mTetherInterfaceName = intf;
- return true;
- }
- }
- }
- /* We found no interfaces to tether. */
- return false;
- }
-
- private void stopTethering() {
- try {
- /* Clear the interface address. */
- InterfaceConfiguration ifcg =
- mNmService.getInterfaceConfig(mTetherInterfaceName);
- if (ifcg != null) {
- ifcg.setLinkAddress(
- new LinkAddress(
- NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
- mNmService.setInterfaceConfig(mTetherInterfaceName, ifcg);
- }
- } catch (Exception e) {
- Log.e(TAG, "Error resetting interface " + mTetherInterfaceName + ", :" + e);
- }
-
- if (mConnectivityManager.untether(mTetherInterfaceName)
- != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
- Log.e(TAG, "Untether initiate failed!");
- }
- }
-
- private boolean isWifiTethered(ArrayList<String> active) {
- String[] wifiRegexs = mConnectivityManager.getTetherableWifiRegexs();
- for (String intf : active) {
- for (String regex : wifiRegexs) {
- if (intf.matches(regex)) {
- return true;
- }
- }
- }
- /* No tethered interface. */
- return false;
- }
-
private class SoftApStateMachine extends StateMachine {
/* Commands for the state machine. */
public static final int CMD_START = 0;
public static final int CMD_STOP = 1;
- public static final int CMD_TETHER_STATE_CHANGE = 2;
- public static final int CMD_TETHER_NOTIFICATION_TIMEOUT = 3;
-
- private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
-
- /* Sequence number used to track tether notification timeout. */
- private int mTetherToken = 0;
private final State mIdleState = new IdleState();
private final State mStartedState = new StartedState();
- private final State mTetheringState = new TetheringState();
- private final State mTetheredState = new TetheredState();
- private final State mUntetheringState = new UntetheringState();
SoftApStateMachine(Looper looper) {
super(TAG, looper);
- // CHECKSTYLE:OFF IndentationCheck
addState(mIdleState);
- addState(mStartedState, mIdleState);
- addState(mTetheringState, mStartedState);
- addState(mTetheredState, mStartedState);
- addState(mUntetheringState, mStartedState);
- // CHECKSTYLE:ON IndentationCheck
+ addState(mStartedState, mIdleState);
setInitialState(mIdleState);
start();
@@ -388,62 +254,11 @@ public class SoftApManager {
/* Already started, ignore this command. */
break;
case CMD_STOP:
- if (restartSap) {
- stopSoftAp();
- updateApState(WifiManager.WIFI_AP_STATE_RESTART, 0);
- restartSap = false;
- } else {
- updateApState(WifiManager.WIFI_AP_STATE_DISABLING, 0);
- stopSoftAp();
- updateApState(WifiManager.WIFI_AP_STATE_DISABLED, 0);
- }
+ updateApState(WifiManager.WIFI_AP_STATE_DISABLING, 0);
+ stopSoftAp();
+ updateApState(WifiManager.WIFI_AP_STATE_DISABLED, 0);
transitionTo(mIdleState);
break;
- case CMD_TETHER_STATE_CHANGE:
- TetherStateChange stateChange = (TetherStateChange) message.obj;
- if (startTethering(stateChange.available)) {
- transitionTo(mTetheringState);
- }
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- /**
- * This is a transient state. We will transition out of this state when
- * we receive a notification that WiFi is tethered (TetheredState) or
- * we timed out waiting for that notification (StartedState).
- */
- private class TetheringState extends State {
- @Override
- public void enter() {
- /* Send a delayed message to terminate if tethering fails to notify. */
- sendMessageDelayed(
- obtainMessage(CMD_TETHER_NOTIFICATION_TIMEOUT, ++mTetherToken),
- TETHER_NOTIFICATION_TIME_OUT_MSECS);
- }
-
- @Override
- public boolean processMessage(Message message) {
- switch (message.what) {
- case CMD_TETHER_STATE_CHANGE:
- TetherStateChange stateChange = (TetherStateChange) message.obj;
- if (isWifiTethered(stateChange.active)) {
- transitionTo(mTetheredState);
- }
- break;
- case CMD_TETHER_NOTIFICATION_TIMEOUT:
- if (message.arg1 == mTetherToken) {
- Log.e(TAG, "Failed to get tether update, "
- + "shutdown soft access point");
- transitionTo(mStartedState);
- /* Needs to be first thing handled. */
- sendMessageAtFrontOfQueue(CMD_STOP);
- }
- break;
default:
return NOT_HANDLED;
}
@@ -451,73 +266,5 @@ public class SoftApManager {
}
}
- private class TetheredState extends State {
- @Override
- public boolean processMessage(Message message) {
- switch (message.what) {
- case CMD_TETHER_STATE_CHANGE:
- TetherStateChange stateChange = (TetherStateChange) message.obj;
- if (!isWifiTethered(stateChange.active)) {
- Log.e(TAG, "Tether State Change : Restart (Stop and Start) Soft AP");
- restartSap = true;
- sendMessage(CMD_STOP);
- }
- break;
- case CMD_STOP:
- Log.d(TAG, "Untethering before stopping AP");
- stopTethering();
- transitionTo(mUntetheringState);
- break;
-
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- /**
- * This is a transient state, will transition out of this state to StartedState
- * when we receive a notification that WiFi is untethered or we timed out waiting
- * for that notification.
- */
- private class UntetheringState extends State {
- @Override
- public void enter() {
- /* Send a delayed message to terminate if tethering fails to notify. */
- sendMessageDelayed(
- obtainMessage(CMD_TETHER_NOTIFICATION_TIMEOUT, ++mTetherToken),
- TETHER_NOTIFICATION_TIME_OUT_MSECS);
- }
-
- @Override
- public boolean processMessage(Message message) {
- switch (message.what) {
- case CMD_TETHER_STATE_CHANGE:
- TetherStateChange stateChange = (TetherStateChange) message.obj;
- /* Transition back to StartedState when WiFi is untethered. */
- if (!isWifiTethered(stateChange.active)) {
- transitionTo(mStartedState);
- /* Needs to be first thing handled */
- sendMessageAtFrontOfQueue(CMD_STOP);
- }
- break;
- case CMD_TETHER_NOTIFICATION_TIMEOUT:
- if (message.arg1 == mTetherToken) {
- Log.e(TAG, "Failed to get tether update, "
- + "force stop access point");
- transitionTo(mStartedState);
- /* Needs to be first thing handled. */
- sendMessageAtFrontOfQueue(CMD_STOP);
- }
- break;
- default:
- /* Defer handling of this message until untethering is completed. */
- deferMessage(message);
- break;
- }
- return HANDLED;
- }
- }
}
}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index cdcf583b4..5a248bee9 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.
@@ -408,7 +403,7 @@ public class WifiConfigManager {
mIpconfigStore = new IpConfigStore(mWriter);
mWifiNetworkHistory = new WifiNetworkHistory(context, mLocalLog, mWriter);
mWifiConfigStore =
- new WifiConfigStore(wifiNative, mKeyStore, mLocalLog, mShowNetworks, true);
+ new WifiConfigStore(context, wifiNative, mKeyStore, mLocalLog, mShowNetworks, true);
}
public void trimANQPCache(boolean all) {
@@ -740,19 +735,13 @@ public class WifiConfigManager {
}
if (config.isPasspoint()) {
- /* need to slap on the SSID of selected bssid to work */
- if (getScanDetailCache(config).size() != 0) {
- ScanDetail result = getScanDetailCache(config).getFirst();
- if (result == null) {
- loge("Could not find scan result for " + config.BSSID);
- } else {
- logd("Setting SSID for " + config.networkId + " to" + result.getSSID());
- setSSIDNative(config, result.getSSID());
- }
-
- } else {
- loge("Could not find bssid for " + config);
- }
+ // Set the SSID for the underlying WPA supplicant network entry corresponding to this
+ // Passpoint profile to the SSID of the BSS selected by QNS. |config.SSID| is set by
+ // selectQualifiedNetwork.selectQualifiedNetwork(), when the qualified network selected
+ // is a Passpoint network.
+ logd("Setting SSID for WPA supplicant network " + config.networkId + " to "
+ + config.SSID);
+ setSSIDNative(config, config.SSID);
}
mWifiConfigStore.enableHS20(config.isPasspoint());
@@ -1692,6 +1681,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();
@@ -2495,20 +2485,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();
@@ -3009,11 +2987,7 @@ public class WifiConfigManager {
pw.println(s);
}
}
- if (mLocalLog != null) {
- pw.println("WifiConfigManager - Log Begin ----");
- mLocalLog.dump(fd, pw, args);
- pw.println("WifiConfigManager - Log End ----");
- }
+
if (mMOManager.isConfigured()) {
pw.println("Begin dump of ANQP Cache");
mAnqpCache.dump(pw);
@@ -3147,15 +3121,6 @@ public class WifiConfigManager {
}
/**
- * Checks if the network is a sim config.
- * @param config Config corresponding to the network.
- * @return true if it is a sim config, false otherwise.
- */
- public boolean isSimConfig(WifiConfiguration config) {
- return mWifiConfigStore.isSimConfig(config);
- }
-
- /**
* Resets all sim networks from the network list.
*/
public void resetSimNetworks() {
@@ -3269,29 +3234,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/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index b32d0af25..908487152 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.content.Context;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.wifi.WifiConfiguration;
@@ -36,6 +37,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.server.wifi.hotspot2.Utils;
+import com.android.server.wifi.util.TelephonyUtil;
import org.json.JSONException;
import org.json.JSONObject;
@@ -92,6 +94,7 @@ public class WifiConfigStore {
private final LocalLog mLocalLog;
private final WpaConfigFileObserver mFileObserver;
+ private final Context mContext;
private final WifiNative mWifiNative;
private final KeyStore mKeyStore;
private final boolean mShowNetworks;
@@ -99,8 +102,9 @@ public class WifiConfigStore {
private final BackupManagerProxy mBackupManagerProxy;
- WifiConfigStore(WifiNative wifiNative, KeyStore keyStore, LocalLog localLog,
+ WifiConfigStore(Context context, WifiNative wifiNative, KeyStore keyStore, LocalLog localLog,
boolean showNetworks, boolean verboseDebug) {
+ mContext = context;
mWifiNative = wifiNative;
mKeyStore = keyStore;
mShowNetworks = showNetworks;
@@ -1095,27 +1099,6 @@ public class WifiConfigStore {
}
/**
- * Checks if the network is a sim config.
- *
- * @param config Config corresponding to the network.
- * @return true if it is a sim config, false otherwise.
- */
- public boolean isSimConfig(WifiConfiguration config) {
- if (config == null) {
- return false;
- }
-
- if (config.enterpriseConfig == null) {
- return false;
- }
-
- int method = config.enterpriseConfig.getEapMethod();
- return (method == WifiEnterpriseConfig.Eap.SIM
- || method == WifiEnterpriseConfig.Eap.AKA
- || method == WifiEnterpriseConfig.Eap.AKA_PRIME);
- }
-
- /**
* Resets all sim networks from the provided network list.
*
* @param configs List of all the networks.
@@ -1123,10 +1106,26 @@ public class WifiConfigStore {
public void resetSimNetworks(Collection<WifiConfiguration> configs) {
if (VDBG) localLog("resetSimNetworks");
for (WifiConfiguration config : configs) {
- if (isSimConfig(config)) {
- /* This configuration may have cached Pseudonym IDs; lets remove them */
- mWifiNative.setNetworkVariable(config.networkId, "identity", "NULL");
- mWifiNative.setNetworkVariable(config.networkId, "anonymous_identity", "NULL");
+ if (TelephonyUtil.isSimConfig(config)) {
+ String currentIdentity = TelephonyUtil.getSimIdentity(mContext,
+ config.enterpriseConfig.getEapMethod());
+ String supplicantIdentity =
+ mWifiNative.getNetworkVariable(config.networkId, "identity");
+ if(supplicantIdentity != null) {
+ supplicantIdentity = removeDoubleQuotes(supplicantIdentity);
+ }
+ if (currentIdentity == null || !currentIdentity.equals(supplicantIdentity)) {
+ // Identity differs so update the identity
+ mWifiNative.setNetworkVariable(config.networkId,
+ WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.EMPTY_VALUE);
+ // This configuration may have cached Pseudonym IDs; lets remove them
+ mWifiNative.setNetworkVariable(config.networkId,
+ WifiEnterpriseConfig.ANON_IDENTITY_KEY,
+ WifiEnterpriseConfig.EMPTY_VALUE);
+ }
+ // Update the loaded config
+ config.enterpriseConfig.setIdentity(currentIdentity);
+ config.enterpriseConfig.setAnonymousIdentity("");
}
}
}
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 7c0483669..1ca2608cb 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -90,7 +90,8 @@ public class WifiConnectivityManager {
private static final int LOW_RSSI_NETWORK_RETRY_START_DELAY_MS = 20 * 1000; // 20 seconds
private static final int LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS = 80 * 1000; // 80 seconds
// Maximum number of retries when starting a scan failed
- private static final int MAX_SCAN_RESTART_ALLOWED = 5;
+ @VisibleForTesting
+ public static final int MAX_SCAN_RESTART_ALLOWED = 5;
// Number of milli-seconds to delay before retry starting
// a previously failed scan
private static final int RESTART_SCAN_DELAY_MS = 2 * 1000; // 2 seconds
@@ -132,7 +133,7 @@ public class WifiConnectivityManager {
private final Handler mEventHandler;
private final Clock mClock;
private final LocalLog mLocalLog =
- new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 256 : 1024);
+ new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 128 : 256);
private final LinkedList<Long> mConnectionAttemptTimeStamps;
private boolean mDbg = false;
@@ -147,6 +148,9 @@ public class WifiConnectivityManager {
private String mLastConnectionAttemptBssid = null;
private int mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP;
+ private boolean mPnoScanStarted = false;
+ private boolean mPeriodicScanTimerSet = false;
+ private boolean mWaitForFullBandScanResults = false;
// PNO settings
private int mMin5GHzRssi;
@@ -178,11 +182,9 @@ public class WifiConnectivityManager {
// A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
// if the start scan command failed. An timer is used here to make it a deferred retry.
private class RestartSingleScanListener implements AlarmManager.OnAlarmListener {
- private final boolean mIsWatchdogTriggered;
private boolean mIsFullBandScan;
- RestartSingleScanListener(boolean isWatchdogTriggered, boolean isFullBandScan) {
- mIsWatchdogTriggered = isWatchdogTriggered;
+ RestartSingleScanListener(boolean isFullBandScan) {
mIsFullBandScan = isFullBandScan;
}
@@ -191,7 +193,7 @@ public class WifiConnectivityManager {
if (mStateMachine.getScanCount() < mStateMachine.getMaxConfiguredScanCount()) {
mIsFullBandScan = false;
}
- startSingleScan(mIsWatchdogTriggered, mIsFullBandScan);
+ startSingleScan(mIsFullBandScan);
}
}
@@ -231,6 +233,7 @@ public class WifiConnectivityManager {
mStateMachine.isSupplicantTransientState());
mWifiLastResortWatchdog.updateAvailableNetworks(
mQualifiedNetworkSelector.getFilteredScanDetails());
+ mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
localLog(listenerName + ": QNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
@@ -252,9 +255,6 @@ public class WifiConnectivityManager {
@Override
public void onSuccess() {
localLog("PeriodicScanListener onSuccess");
-
- // reset the count
- mScanRestartCount = 0;
}
@Override
@@ -283,6 +283,7 @@ public class WifiConnectivityManager {
public void onResults(WifiScanner.ScanData[] results) {
handleScanResults(mScanDetails, "PeriodicScanListener");
clearScanDetails();
+ mScanRestartCount = 0;
}
@Override
@@ -299,23 +300,101 @@ public class WifiConnectivityManager {
private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener();
+ // All single scan results listener.
+ //
+ // Note: This is the listener for all the available single scan results,
+ // including the ones initiated by WifiConnectivityManager and
+ // other modules.
+ private class AllSingleScanListener implements WifiScanner.ScanListener {
+ private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
+
+ public void clearScanDetails() {
+ mScanDetails.clear();
+ }
+
+ @Override
+ public void onSuccess() {
+ localLog("registerScanListener onSuccess");
+ }
+
+ @Override
+ public void onFailure(int reason, String description) {
+ Log.e(TAG, "registerScanListener onFailure:"
+ + " reason: " + reason
+ + " description: " + description);
+ }
+
+ @Override
+ public void onPeriodChanged(int periodInMs) {
+ }
+
+ @Override
+ 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();
+
+ // Update metrics to see if a single scan detected a valid network
+ // while PNO scan didn't.
+ // Note: We don't update the background scan metrics any more as it is
+ // not in use.
+ if (mPnoScanStarted) {
+ if (wasConnectAttempted) {
+ mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
+ } else {
+ mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
+ }
+ }
+ }
+
+ @Override
+ public void onFullResult(ScanResult fullScanResult) {
+ if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
+ return;
+ }
+
+ if (mDbg) {
+ localLog("AllSingleScanListener onFullResult: "
+ + fullScanResult.SSID + " capabilities "
+ + fullScanResult.capabilities);
+ }
+
+ mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
+ }
+ }
+
+ private final AllSingleScanListener mAllSingleScanListener = new AllSingleScanListener();
+
// Single scan results listener. A single scan is initiated when
// Disconnected/ConnectedPNO scan found a valid network and woke up
- // the system, or by the watchdog timer.
+ // the system, or by the watchdog timer, or to form the timer based
+ // periodic scan.
+ //
+ // Note: This is the listener for the single scans initiated by the
+ // WifiConnectivityManager.
private class SingleScanListener implements WifiScanner.ScanListener {
- private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
- private final boolean mIsWatchdogTriggered;
private final boolean mIsFullBandScan;
- SingleScanListener(boolean isWatchdogTriggered, boolean isFullBandScan) {
- mIsWatchdogTriggered = isWatchdogTriggered;
+ SingleScanListener(boolean isFullBandScan) {
mIsFullBandScan = isFullBandScan;
}
- public void clearScanDetails() {
- mScanDetails.clear();
- }
-
@Override
public void onSuccess() {
localLog("SingleScanListener onSuccess");
@@ -340,7 +419,7 @@ public class WifiConnectivityManager {
// reschedule the scan
if (mSingleScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
- scheduleDelayedSingleScan(mIsWatchdogTriggered, mIsFullBandScan);
+ scheduleDelayedSingleScan(mIsFullBandScan);
} else {
mSingleScanRestartCount = 0;
Log.e(TAG, "Failed to successfully start single scan for "
@@ -356,35 +435,10 @@ public class WifiConnectivityManager {
@Override
public void onResults(WifiScanner.ScanData[] results) {
- boolean wasConnectAttempted = handleScanResults(mScanDetails, "SingleScanListener");
- clearScanDetails();
- // update metrics if this was a watchdog triggered single scan
- if (mIsWatchdogTriggered) {
- if (wasConnectAttempted) {
- if (mScreenOn) {
- mWifiMetrics.incrementNumConnectivityWatchdogBackgroundBad();
- } else {
- mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
- }
- } else {
- if (mScreenOn) {
- mWifiMetrics.incrementNumConnectivityWatchdogBackgroundGood();
- } else {
- mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
- }
- }
- }
}
@Override
public void onFullResult(ScanResult fullScanResult) {
- if (mDbg) {
- localLog("SingleScanListener onFullResult: "
- + fullScanResult.SSID + " capabilities "
- + fullScanResult.capabilities);
- }
-
- mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult));
}
}
@@ -416,9 +470,6 @@ public class WifiConnectivityManager {
@Override
public void onSuccess() {
localLog("PnoScanListener onSuccess");
-
- // reset the count
- mScanRestartCount = 0;
}
@Override
@@ -465,6 +516,7 @@ public class WifiConnectivityManager {
boolean wasConnectAttempted;
wasConnectAttempted = handleScanResults(mScanDetails, "PnoScanListener");
clearScanDetails();
+ mScanRestartCount = 0;
if (!wasConnectAttempted) {
// The scan results were rejected by QNS due to low RSSI values
@@ -489,7 +541,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;
@@ -521,7 +573,13 @@ public class WifiConnectivityManager {
+ " secureNetworkBonus " + mSecureBonus
+ " initialScoreMax " + mInitialScoreMax);
- Log.i(TAG, "ConnectivityScanManager initialized ");
+ // Register for all single scan results
+ mScanner.registerScanListener(mAllSingleScanListener);
+
+ mWifiConnectivityManagerEnabled = enable;
+
+ Log.i(TAG, "ConnectivityScanManager initialized and "
+ + (enable ? "enabled" : "disabled"));
}
/**
@@ -688,7 +746,7 @@ public class WifiConnectivityManager {
Log.i(TAG, "start a single scan from watchdogHandler");
scheduleWatchdogTimer();
- startSingleScan(true, true);
+ startSingleScan(true);
}
}
@@ -724,7 +782,7 @@ public class WifiConnectivityManager {
if (mStateMachine.getScanCount() < mStateMachine.getMaxConfiguredScanCount()) {
isFullBandScan = false;
}
- startSingleScan(false, isFullBandScan);
+ startSingleScan(isFullBandScan);
schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
// Set up the next scan interval in an exponential backoff fashion.
@@ -751,7 +809,7 @@ public class WifiConnectivityManager {
}
// Start a single scan
- private void startSingleScan(boolean isWatchdogTriggered, boolean isFullBandScan) {
+ private void startSingleScan(boolean isFullBandScan) {
if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
return;
}
@@ -787,7 +845,7 @@ public class WifiConnectivityManager {
// mSingleScanListener.clearScanDetails();
// mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE);
SingleScanListener singleScanListener =
- new SingleScanListener(isWatchdogTriggered, isFullBandScan);
+ new SingleScanListener(isFullBandScan);
mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE);
}
@@ -795,6 +853,12 @@ public class WifiConnectivityManager {
private void startPeriodicScan(boolean scanImmediately) {
mPnoScanListener.resetLowRssiNetworkRetryDelay();
+ // No connectivity scan if auto roaming is disabled.
+ if (mWifiState == WIFI_STATE_CONNECTED
+ && !mConfigManager.getEnableAutoJoinWhenAssociated()) {
+ return;
+ }
+
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
if (!ENABLE_BACKGROUND_SCAN) {
@@ -852,6 +916,7 @@ public class WifiConnectivityManager {
mPnoScanListener.clearScanDetails();
mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
+ mPnoScanStarted = true;
}
// Start a ConnectedPNO scan when screen is off and Wifi is connected
@@ -895,6 +960,16 @@ public class WifiConnectivityManager {
mPnoScanListener.clearScanDetails();
mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
+ mPnoScanStarted = true;
+ }
+
+ // Stop a PNO scan. This includes both DisconnectedPNO and ConnectedPNO scans.
+ private void stopPnoScan() {
+ if (mPnoScanStarted) {
+ mScanner.stopPnoScan(mPnoScanListener);
+ }
+
+ mPnoScanStarted = false;
}
// Set up watchdog timer
@@ -913,14 +988,23 @@ public class WifiConnectivityManager {
mClock.elapsedRealtime() + intervalMs,
PERIODIC_SCAN_TIMER_TAG,
mPeriodicScanTimerListener, mEventHandler);
+ mPeriodicScanTimerSet = true;
+ }
+
+ // Cancel periodic scan timer
+ private void cancelPeriodicScanTimer() {
+ if (mPeriodicScanTimerSet) {
+ mAlarmManager.cancel(mPeriodicScanTimerListener);
+ mPeriodicScanTimerSet = false;
+ }
}
// Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS
- private void scheduleDelayedSingleScan(boolean isWatchdogTriggered, boolean isFullBandScan) {
+ private void scheduleDelayedSingleScan(boolean isFullBandScan) {
localLog("scheduleDelayedSingleScan");
RestartSingleScanListener restartSingleScanListener =
- new RestartSingleScanListener(isWatchdogTriggered, isFullBandScan);
+ new RestartSingleScanListener(isFullBandScan);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mClock.elapsedRealtime() + RESTART_SCAN_DELAY_MS,
RESTART_SINGLE_SCAN_TIMER_TAG,
@@ -977,11 +1061,11 @@ public class WifiConnectivityManager {
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
if (!ENABLE_BACKGROUND_SCAN) {
- mAlarmManager.cancel(mPeriodicScanTimerListener);
+ cancelPeriodicScanTimer();
} else {
mScanner.stopBackgroundScan(mPeriodicScanListener);
}
- mScanner.stopPnoScan(mPnoScanListener);
+ stopPnoScan();
mScanRestartCount = 0;
}
@@ -1004,8 +1088,10 @@ public class WifiConnectivityManager {
mWifiState = state;
- // Kick off the watchdog timer if entering disconnected state
+ // Reset BSSID of last connection attempt and kick off
+ // the watchdog timer if entering disconnected state.
if (mWifiState == WIFI_STATE_DISCONNECTED) {
+ mLastConnectionAttemptBssid = null;
scheduleWatchdogTimer();
}
@@ -1042,7 +1128,8 @@ public class WifiConnectivityManager {
public void forceConnectivityScan() {
Log.i(TAG, "forceConnectivityScan");
- startConnectivityScan(SCAN_IMMEDIATELY);
+ mWaitForFullBandScanResults = true;
+ startSingleScan(true);
}
/**
@@ -1085,6 +1172,10 @@ public class WifiConnectivityManager {
if (!mWifiEnabled) {
stopConnectivityScan();
resetLastPeriodicSingleScanTimeStamp();
+ mLastConnectionAttemptBssid = null;
+ mWaitForFullBandScanResults = false;
+ } else if (mWifiConnectivityManagerEnabled) {
+ startConnectivityScan(SCAN_IMMEDIATELY);
}
}
@@ -1099,6 +1190,10 @@ public class WifiConnectivityManager {
if (!mWifiConnectivityManagerEnabled) {
stopConnectivityScan();
resetLastPeriodicSingleScanTimeStamp();
+ mLastConnectionAttemptBssid = null;
+ mWaitForFullBandScanResults = false;
+ } else if (mWifiEnabled) {
+ startConnectivityScan(SCAN_IMMEDIATELY);
}
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index cad047a6e..b98bf14cd 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -18,6 +18,7 @@ package com.android.server.wifi;
import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF;
+import static android.net.wifi.WifiManager.WIFI_MODE_NO_LOCKS_HELD;
import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY;
import android.app.AlarmManager;
@@ -42,12 +43,15 @@ import android.util.Slog;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import com.android.server.wifi.WifiServiceImpl.LockList;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-class WifiController extends StateMachine {
+/**
+ * WifiController is the class used to manage on/off state of WifiStateMachine for various operating
+ * modes (normal, airplane, wifi hotspot, etc.).
+ */
+public class WifiController extends StateMachine {
private static final String TAG = "WifiController";
private static boolean DBG = false;
private Context mContext;
@@ -93,7 +97,7 @@ class WifiController extends StateMachine {
final WifiStateMachine mWifiStateMachine;
private SoftApStateMachine mSoftApStateMachine = null;
final WifiSettingsStore mSettingsStore;
- final LockList mLocks;
+ private final WifiLockManager mWifiLockManager;
/**
* Temporary for computing UIDS that are responsible for starting WIFI.
@@ -107,22 +111,26 @@ class WifiController extends StateMachine {
private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
- static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
- static final int CMD_SCREEN_ON = BASE + 2;
- static final int CMD_SCREEN_OFF = BASE + 3;
- static final int CMD_BATTERY_CHANGED = BASE + 4;
- static final int CMD_DEVICE_IDLE = BASE + 5;
- static final int CMD_LOCKS_CHANGED = BASE + 6;
- static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
- static final int CMD_WIFI_TOGGLED = BASE + 8;
- static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
- static final int CMD_SET_AP = BASE + 10;
- static final int CMD_DEFERRED_TOGGLE = BASE + 11;
- static final int CMD_USER_PRESENT = BASE + 12;
- static final int CMD_AP_START_FAILURE = BASE + 13;
- static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
- static final int CMD_AP_STOPPED = BASE + 15;
- static final int CMD_STA_START_FAILURE = BASE + 16;
+ static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
+ static final int CMD_SCREEN_ON = BASE + 2;
+ static final int CMD_SCREEN_OFF = BASE + 3;
+ static final int CMD_BATTERY_CHANGED = BASE + 4;
+ static final int CMD_DEVICE_IDLE = BASE + 5;
+ static final int CMD_LOCKS_CHANGED = BASE + 6;
+ static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
+ static final int CMD_WIFI_TOGGLED = BASE + 8;
+ static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
+ static final int CMD_SET_AP = BASE + 10;
+ static final int CMD_DEFERRED_TOGGLE = BASE + 11;
+ static final int CMD_USER_PRESENT = BASE + 12;
+ static final int CMD_AP_START_FAILURE = BASE + 13;
+ static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
+ static final int CMD_AP_STOPPED = BASE + 15;
+ static final int CMD_STA_START_FAILURE = BASE + 16;
+ // Command used to trigger a wifi stack restart when in active mode
+ static final int CMD_RESTART_WIFI = BASE + 17;
+ // Internal command used to complete wifi stack restart
+ private static final int CMD_RESTART_WIFI_CONTINUE = BASE + 18;
private DefaultState mDefaultState = new DefaultState();
private StaEnabledState mStaEnabledState = new StaEnabledState();
@@ -138,14 +146,14 @@ class WifiController extends StateMachine {
private NoLockHeldState mNoLockHeldState = new NoLockHeldState();
private EcmState mEcmState = new EcmState();
- WifiController(Context context, WifiStateMachine wsm,
- WifiSettingsStore wss, LockList locks, Looper looper, FrameworkFacade f) {
+ WifiController(Context context, WifiStateMachine wsm, WifiSettingsStore wss,
+ WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f) {
super(TAG, looper);
mFacade = f;
mContext = context;
mWifiStateMachine = wsm;
mSettingsStore = wss;
- mLocks = locks;
+ mWifiLockManager = wifiLockManager;
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -340,7 +348,7 @@ class WifiController extends StateMachine {
private void updateBatteryWorkSource() {
mTmpWorkSource.clear();
if (mDeviceIdle) {
- mLocks.updateWorkSource(mTmpWorkSource);
+ mTmpWorkSource.add(mWifiLockManager.createMergedWorkSource());
}
mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
}
@@ -422,6 +430,8 @@ class WifiController extends StateMachine {
case CMD_AP_START_FAILURE:
case CMD_AP_STOPPED:
case CMD_STA_START_FAILURE:
+ case CMD_RESTART_WIFI:
+ case CMD_RESTART_WIFI_CONTINUE:
break;
case CMD_USER_PRESENT:
mFirstUserSignOnSeen = true;
@@ -502,6 +512,9 @@ class WifiController extends StateMachine {
log("DEFERRED_TOGGLE handled");
sendMessage((Message)(msg.obj));
break;
+ case CMD_RESTART_WIFI_CONTINUE:
+ transitionTo(mDeviceActiveState);
+ break;
default:
return NOT_HANDLED;
}
@@ -779,7 +792,9 @@ class WifiController extends StateMachine {
*/
private State getNextWifiState() {
if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) {
- return mDeviceActiveState;
+ if (!mStaAndApConcurrency) {
+ return mDeviceActiveState;
+ }
}
if (mSettingsStore.isScanAlwaysAvailable()) {
@@ -951,6 +966,10 @@ class WifiController extends StateMachine {
}
mFirstUserSignOnSeen = true;
return HANDLED;
+ } else if (msg.what == CMD_RESTART_WIFI) {
+ deferMessage(obtainMessage(CMD_RESTART_WIFI_CONTINUE));
+ transitionTo(mApStaDisabledState);
+ return HANDLED;
}
return NOT_HANDLED;
}
@@ -1013,26 +1032,23 @@ class WifiController extends StateMachine {
}
private void checkLocksAndTransitionWhenDeviceIdle() {
- if (mLocks.hasLocks()) {
- switch (mLocks.getStrongestLockMode()) {
- case WIFI_MODE_FULL:
- transitionTo(mFullLockHeldState);
- break;
- case WIFI_MODE_FULL_HIGH_PERF:
- transitionTo(mFullHighPerfLockHeldState);
- break;
- case WIFI_MODE_SCAN_ONLY:
+ switch (mWifiLockManager.getStrongestLockMode()) {
+ case WIFI_MODE_NO_LOCKS_HELD:
+ if (mSettingsStore.isScanAlwaysAvailable()) {
transitionTo(mScanOnlyLockHeldState);
- break;
- default:
- loge("Illegal lock " + mLocks.getStrongestLockMode());
- }
- } else {
- if (mSettingsStore.isScanAlwaysAvailable()) {
+ } else {
+ transitionTo(mNoLockHeldState);
+ }
+ break;
+ case WIFI_MODE_FULL:
+ transitionTo(mFullLockHeldState);
+ break;
+ case WIFI_MODE_FULL_HIGH_PERF:
+ transitionTo(mFullHighPerfLockHeldState);
+ break;
+ case WIFI_MODE_SCAN_ONLY:
transitionTo(mScanOnlyLockHeldState);
- } else {
- transitionTo(mNoLockHeldState);
- }
+ break;
}
}
diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java
index d87b14f05..a6974776b 100644
--- a/service/java/com/android/server/wifi/WifiCountryCode.java
+++ b/service/java/com/android/server/wifi/WifiCountryCode.java
@@ -21,6 +21,9 @@ import android.util.Log;
/**
* Provide functions for making changes to WiFi country code.
+ * This Country Code is from MCC or phone default setting. This class sends Country Code
+ * to driver through wpa_supplicant when WifiStateMachine marks current state as ready
+ * using setReadyForChange(true).
*/
public class WifiCountryCode {
private static final String TAG = "WifiCountryCode";
@@ -149,13 +152,34 @@ public class WifiCountryCode {
}
/**
- * @return Get the current country code, returns null if no country code is set.
+ * Method to get the Country Code that was sent to wpa_supplicant.
+ *
+ * @return Returns the local copy of the Country Code that was sent to the driver upon
+ * setReadyForChange(true).
+ * If wpa_supplicant was never started, this may be null even if a SIM reported a valid
+ * country code.
+ * Returns null if no Country Code was sent to driver.
*/
public synchronized String getCurrentCountryCode() {
mCurrentCountryCode = pickCountryCode();
return mCurrentCountryCode;
}
+ public synchronized String getCountryCodeSentToDriver() {
+ return mCurrentCountryCode;
+ }
+
+ /**
+ * Method to return the currently reported Country Code from the SIM or phone default setting.
+ *
+ * @return The currently reported Country Code from the SIM. If there is no Country Code
+ * reported from SIM, a phone default Country Code will be returned.
+ * Returns null when there is no Country Code available.
+ */
+ public synchronized String getCountryCode() {
+ return pickCountryCode();
+ }
+
private void updateCountryCode() {
if (DBG) Log.d(TAG, "Update country code");
String country = pickCountryCode();
@@ -164,7 +188,7 @@ public class WifiCountryCode {
// 1. Wpa supplicant may silently modify the country code.
// 2. If Wifi restarted therefoere wpa_supplicant also restarted,
// the country code counld be reset to '00' by wpa_supplicant.
- if (country.length() != 0) {
+ if (country != null) {
setCountryCodeNative(country);
}
// We do not set country code if there is no candidate. This is reasonable
@@ -179,8 +203,8 @@ public class WifiCountryCode {
if (mDefaultCountryCode != null) {
return mDefaultCountryCode;
}
- // If there is no candidate country code we will return an empty string.
- return "";
+ // If there is no candidate country code we will return null.
+ return null;
}
private boolean setCountryCodeNative(String country) {
diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
index 896c1c816..0885e46fd 100644
--- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
+++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
@@ -80,6 +80,8 @@ public class WifiLastResortWatchdog {
private WifiMetrics mWifiMetrics;
+ private WifiController mWifiController = null;
+
WifiLastResortWatchdog(WifiMetrics wifiMetrics) {
mWifiMetrics = wifiMetrics;
}
@@ -207,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();
@@ -324,13 +332,21 @@ public class WifiLastResortWatchdog {
}
/**
- * Restart Supplicant, Driver & return WifiStateMachine to InitialState
+ * Trigger a restart of the wifi stack.
*/
private void restartWifiStack() {
if (VDBG) Log.v(TAG, "restartWifiStack.");
- Log.i(TAG, "Triggered.");
+
+ // First verify that we can send the trigger message.
+ if (mWifiController == null) {
+ Log.e(TAG, "WifiLastResortWatchdog unable to trigger: WifiController is null");
+ return;
+ }
+
if (DBG) Log.d(TAG, toString());
- // <TODO>
+
+ mWifiController.sendMessage(WifiController.CMD_RESTART_WIFI);
+ Log.i(TAG, "Triggered WiFi stack restart.");
}
/**
@@ -537,4 +553,14 @@ public class WifiLastResortWatchdog {
+ ", Age: " + age;
}
}
+
+ /**
+ * Method used to set the WifiController for the this watchdog.
+ *
+ * The WifiController is used to send the restart wifi command to carry out the wifi restart.
+ * @param wifiController WifiController instance that will be sent the CMD_RESTART_WIFI message.
+ */
+ public void setWifiController(WifiController wifiController) {
+ mWifiController = wifiController;
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiLockManager.java b/service/java/com/android/server/wifi/WifiLockManager.java
new file mode 100644
index 000000000..fe193f097
--- /dev/null
+++ b/service/java/com/android/server/wifi/WifiLockManager.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.WorkSource;
+import android.util.Slog;
+
+import com.android.internal.app.IBatteryStats;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * WifiLockManager maintains the list of wake locks held by different applications.
+ */
+public class WifiLockManager {
+ private static final String TAG = "WifiLockManager";
+ private boolean mVerboseLoggingEnabled = false;
+
+ private final Context mContext;
+ private final IBatteryStats mBatteryStats;
+
+ private final List<WifiLock> mWifiLocks = new ArrayList<>();
+ // some wifi lock statistics
+ private int mFullHighPerfLocksAcquired;
+ private int mFullHighPerfLocksReleased;
+ private int mFullLocksAcquired;
+ private int mFullLocksReleased;
+ private int mScanLocksAcquired;
+ private int mScanLocksReleased;
+
+ WifiLockManager(Context context, IBatteryStats batteryStats) {
+ mContext = context;
+ mBatteryStats = batteryStats;
+ }
+
+ /**
+ * Method allowing a calling app to acquire a Wifi WakeLock in the supplied mode.
+ *
+ * This method verifies that the caller has permission to make the call and that the lock mode
+ * is a valid WifiLock mode.
+ * @param lockMode int representation of the Wifi WakeLock type.
+ * @param tag String passed to WifiManager.WifiLock
+ * @param binder IBinder for the calling app
+ * @param ws WorkSource of the calling app
+ *
+ * @return true if the lock was successfully acquired, false if the lockMode was invalid.
+ */
+ public boolean acquireWifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+ if (!isValidLockMode(lockMode)) {
+ throw new IllegalArgumentException("lockMode =" + lockMode);
+ }
+ if (ws == null || ws.size() == 0) {
+ ws = new WorkSource(Binder.getCallingUid());
+ } else {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS, null);
+ }
+ return addLock(new WifiLock(lockMode, tag, binder, ws));
+ }
+
+ /**
+ * Method used by applications to release a WiFi Wake lock. This method checks permissions for
+ * the caller and if allowed, releases the underlying WifiLock(s).
+ *
+ * @param binder IBinder for the calling app.
+ * @return true if the lock was released, false if the caller did not hold any locks
+ */
+ public boolean releaseWifiLock(IBinder binder) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+ return releaseLock(binder);
+ }
+
+ /**
+ * Method used to get the strongest lock type currently held by the WifiLockManager.
+ *
+ * If no locks are held, WifiManager.WIFI_MODE_NO_LOCKS_HELD is returned.
+ *
+ * @return int representing the currently held (highest power consumption) lock.
+ */
+ public synchronized int getStrongestLockMode() {
+ if (mWifiLocks.isEmpty()) {
+ return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
+ }
+
+ if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
+ return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
+ }
+
+ if (mFullLocksAcquired > mFullLocksReleased) {
+ return WifiManager.WIFI_MODE_FULL;
+ }
+
+ return WifiManager.WIFI_MODE_SCAN_ONLY;
+ }
+
+ /**
+ * Method to create a WorkSource containing all active WifiLock WorkSources.
+ */
+ public synchronized WorkSource createMergedWorkSource() {
+ WorkSource mergedWS = new WorkSource();
+ for (WifiLock lock : mWifiLocks) {
+ mergedWS.add(lock.getWorkSource());
+ }
+ return mergedWS;
+ }
+
+ /**
+ * Method used to update WifiLocks with a new WorkSouce.
+ *
+ * @param binder IBinder for the calling application.
+ * @param ws WorkSource to add to the existing WifiLock(s).
+ */
+ public synchronized void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
+ // Does the caller have permission to make this call?
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS, null);
+
+ // Now check if there is an active lock
+ WifiLock wl = findLockByBinder(binder);
+ if (wl == null) {
+ throw new IllegalArgumentException("Wifi lock not active");
+ }
+
+ WorkSource newWorkSource;
+ if (ws == null || ws.size() == 0) {
+ newWorkSource = new WorkSource(Binder.getCallingUid());
+ } else {
+ // Make a copy of the WorkSource before adding it to the WakeLock
+ newWorkSource = new WorkSource(ws);
+ }
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteFullWifiLockReleasedFromSource(wl.mWorkSource);
+ wl.mWorkSource = newWorkSource;
+ mBatteryStats.noteFullWifiLockAcquiredFromSource(wl.mWorkSource);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private static boolean isValidLockMode(int lockMode) {
+ if (lockMode != WifiManager.WIFI_MODE_FULL
+ && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY
+ && lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized boolean addLock(WifiLock lock) {
+ if (mVerboseLoggingEnabled) {
+ Slog.d(TAG, "addLock: " + lock);
+ }
+
+ if (findLockByBinder(lock.getBinder()) != null) {
+ if (mVerboseLoggingEnabled) {
+ Slog.d(TAG, "attempted to add a lock when already holding one");
+ }
+ return false;
+ }
+
+ mWifiLocks.add(lock);
+
+ boolean lockAdded = false;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteFullWifiLockAcquiredFromSource(lock.mWorkSource);
+ switch(lock.mMode) {
+ case WifiManager.WIFI_MODE_FULL:
+ ++mFullLocksAcquired;
+ break;
+ case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+ ++mFullHighPerfLocksAcquired;
+ break;
+ case WifiManager.WIFI_MODE_SCAN_ONLY:
+ ++mScanLocksAcquired;
+ break;
+ }
+ lockAdded = true;
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return lockAdded;
+ }
+
+ private synchronized WifiLock removeLock(IBinder binder) {
+ WifiLock lock = findLockByBinder(binder);
+ if (lock != null) {
+ mWifiLocks.remove(lock);
+ lock.unlinkDeathRecipient();
+ }
+ return lock;
+ }
+
+ private synchronized boolean releaseLock(IBinder binder) {
+ WifiLock wifiLock = removeLock(binder);
+ if (wifiLock == null) {
+ // attempting to release a lock that is not active.
+ return false;
+ }
+
+ if (mVerboseLoggingEnabled) {
+ Slog.d(TAG, "releaseLock: " + wifiLock);
+ }
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
+ switch(wifiLock.mMode) {
+ case WifiManager.WIFI_MODE_FULL:
+ ++mFullLocksReleased;
+ break;
+ case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+ ++mFullHighPerfLocksReleased;
+ break;
+ case WifiManager.WIFI_MODE_SCAN_ONLY:
+ ++mScanLocksReleased;
+ break;
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return true;
+ }
+
+
+ private synchronized WifiLock findLockByBinder(IBinder binder) {
+ for (WifiLock lock : mWifiLocks) {
+ if (lock.getBinder() == binder) {
+ return lock;
+ }
+ }
+ return null;
+ }
+
+ protected void dump(PrintWriter pw) {
+ pw.println("Locks acquired: " + mFullLocksAcquired + " full, "
+ + mFullHighPerfLocksAcquired + " full high perf, "
+ + mScanLocksAcquired + " scan");
+ pw.println("Locks released: " + mFullLocksReleased + " full, "
+ + mFullHighPerfLocksReleased + " full high perf, "
+ + mScanLocksReleased + " scan");
+ pw.println();
+ pw.println("Locks held:");
+ for (WifiLock lock : mWifiLocks) {
+ pw.print(" ");
+ pw.println(lock);
+ }
+ }
+
+ protected void enableVerboseLogging(int verbose) {
+ if (verbose > 0) {
+ mVerboseLoggingEnabled = true;
+ } else {
+ mVerboseLoggingEnabled = false;
+ }
+ }
+
+ private class WifiLock implements IBinder.DeathRecipient {
+ String mTag;
+ int mUid;
+ IBinder mBinder;
+ int mMode;
+ WorkSource mWorkSource;
+
+ WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
+ mTag = tag;
+ mBinder = binder;
+ mUid = Binder.getCallingUid();
+ mMode = lockMode;
+ mWorkSource = ws;
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ protected WorkSource getWorkSource() {
+ return mWorkSource;
+ }
+
+ protected int getUid() {
+ return mUid;
+ }
+
+ protected IBinder getBinder() {
+ return mBinder;
+ }
+
+ public void binderDied() {
+ releaseLock(mBinder);
+ }
+
+ public void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public String toString() {
+ return "WifiLock{" + this.mTag + " type=" + this.mMode + " uid=" + mUid + "}";
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiLogger.java b/service/java/com/android/server/wifi/WifiLogger.java
index 4251df457..c15e2a841 100644
--- a/service/java/com/android/server/wifi/WifiLogger.java
+++ b/service/java/com/android/server/wifi/WifiLogger.java
@@ -16,10 +16,12 @@
package com.android.server.wifi;
+import android.content.Context;
import android.util.Base64;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.R;
import com.android.server.wifi.util.ByteArrayRingBuffer;
import com.android.server.wifi.util.StringUtil;
@@ -89,13 +91,13 @@ class WifiLogger extends BaseWifiLogger {
/** minimum buffer size for each of the log levels */
private static final int MinBufferSizes[] = new int[] { 0, 16384, 16384, 65536 };
- @VisibleForTesting public static final int RING_BUFFER_BYTE_LIMIT_SMALL = 32 * 1024;
- @VisibleForTesting public static final int RING_BUFFER_BYTE_LIMIT_LARGE = 1024 * 1024;
@VisibleForTesting public static final String FIRMWARE_DUMP_SECTION_HEADER =
"FW Memory dump";
@VisibleForTesting public static final String DRIVER_DUMP_SECTION_HEADER =
"Driver state dump";
+ private final int RING_BUFFER_BYTE_LIMIT_SMALL;
+ private final int RING_BUFFER_BYTE_LIMIT_LARGE;
private int mLogLevel = VERBOSE_NO_LOG;
private boolean mIsLoggingEventHandlerRegistered;
private WifiNative.RingBufferStatus[] mRingBuffers;
@@ -103,15 +105,20 @@ class WifiLogger extends BaseWifiLogger {
private WifiStateMachine mWifiStateMachine;
private final WifiNative mWifiNative;
private final BuildProperties mBuildProperties;
- private int mMaxRingBufferSizeBytes = RING_BUFFER_BYTE_LIMIT_SMALL;
+ private int mMaxRingBufferSizeBytes;
+
+ public WifiLogger(Context context, WifiStateMachine wifiStateMachine, WifiNative wifiNative,
+ BuildProperties buildProperties) {
+ RING_BUFFER_BYTE_LIMIT_SMALL = context.getResources().getInteger(
+ R.integer.config_wifi_logger_ring_buffer_default_size_limit_kb) * 1024;
+ RING_BUFFER_BYTE_LIMIT_LARGE = context.getResources().getInteger(
+ R.integer.config_wifi_logger_ring_buffer_verbose_size_limit_kb) * 1024;
- public WifiLogger(
- WifiStateMachine wifiStateMachine, WifiNative wifiNative,
- BuildProperties buildProperties) {
mWifiStateMachine = wifiStateMachine;
mWifiNative = wifiNative;
mBuildProperties = buildProperties;
mIsLoggingEventHandlerRegistered = false;
+ mMaxRingBufferSizeBytes = RING_BUFFER_BYTE_LIMIT_SMALL;
}
@Override
@@ -224,8 +231,11 @@ class WifiLogger extends BaseWifiLogger {
}
dumpPacketFates(pw);
-
pw.println("--------------------------------------------------------------------");
+
+ pw.println("WifiNative - Log Begin ----");
+ mWifiNative.getLocalLog().dump(fd, pw, args);
+ pw.println("WifiNative - Log End ----");
}
/* private methods and data */
@@ -536,7 +546,7 @@ class WifiLogger extends BaseWifiLogger {
String result;
//compress
Deflater compressor = new Deflater();
- compressor.setLevel(Deflater.BEST_COMPRESSION);
+ compressor.setLevel(Deflater.BEST_SPEED);
compressor.setInput(input);
compressor.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
diff --git a/service/java/com/android/server/wifi/WifiLoggerHal.java b/service/java/com/android/server/wifi/WifiLoggerHal.java
index ce3640182..0294e9bf7 100644
--- a/service/java/com/android/server/wifi/WifiLoggerHal.java
+++ b/service/java/com/android/server/wifi/WifiLoggerHal.java
@@ -32,8 +32,8 @@ public class WifiLoggerHal {
public static final byte TX_PKT_FATE_FW_DROP_OTHER = 5;
public static final byte TX_PKT_FATE_DRV_QUEUED = 6;
public static final byte TX_PKT_FATE_DRV_DROP_INVALID = 7;
- public static final byte TX_PKT_FATE_DRV_DROP_NOBUFS = 9;
- public static final byte TX_PKT_FATE_DRV_DROP_OTHER = 10;
+ public static final byte TX_PKT_FATE_DRV_DROP_NOBUFS = 8;
+ public static final byte TX_PKT_FATE_DRV_DROP_OTHER = 9;
public static final byte RX_PKT_FATE_SUCCESS = 0;
public static final byte RX_PKT_FATE_FW_QUEUED = 1;
@@ -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 855afa7e0..6cf87fef0 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;
@@ -42,6 +43,13 @@ import java.util.List;
public class WifiMetrics {
private static final String TAG = "WifiMetrics";
private static final boolean DBG = false;
+ /**
+ * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
+ */
+ 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;
@@ -53,11 +61,11 @@ public class WifiMetrics {
* runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
* together at dump-time
*/
- private final WifiMetricsProto.WifiLog mWifiLogProto;
+ private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
/**
* Session information that gets logged for every Wifi connection attempt.
*/
- private final List<ConnectionEvent> mConnectionEventList;
+ private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>();
/**
* The latest started (but un-ended) connection attempt
*/
@@ -65,18 +73,23 @@ public class WifiMetrics {
/**
* Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
*/
- private SparseIntArray mScanReturnEntries;
+ private final SparseIntArray mScanReturnEntries = new SparseIntArray();
/**
* Mapping of system state to the counts of scans requested in that wifi state * screenOn
* combination. Indexed by WifiLog.WifiState * (1 + screenOn)
*/
- private SparseIntArray mWifiSystemStateEntries;
+ 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 long mRecordStartTimeSec;
-
+ /** Mapping of Wifi Scores to counts */
+ private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
class RouterFingerPrint {
private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
RouterFingerPrint() {
@@ -121,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();
@@ -304,10 +319,6 @@ public class WifiMetrics {
public WifiMetrics(Clock clock) {
mClock = clock;
- mWifiLogProto = new WifiMetricsProto.WifiLog();
- mConnectionEventList = new ArrayList<>();
- mScanReturnEntries = new SparseIntArray();
- mWifiSystemStateEntries = new SparseIntArray();
mCurrentConnectionEvent = null;
mScreenOn = true;
mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
@@ -510,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;
@@ -790,10 +813,119 @@ public class WifiMetrics {
}
}
+ /**
+ * Increment occurence count of RSSI level from RSSI poll.
+ * Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
+ */
+ public void incrementRssiPollRssiCount(int rssi) {
+ if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
+ return;
+ }
+ synchronized (mLock) {
+ int count = mRssiPollCounts.get(rssi);
+ mRssiPollCounts.put(rssi, count + 1);
+ }
+ }
+
+ /**
+ * 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
@@ -814,10 +946,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();
@@ -832,6 +972,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);
@@ -905,8 +1048,53 @@ 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
+ + ", " + MAX_RSSI_POLL + "]");
+ StringBuilder sb = new StringBuilder();
+ for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
+ 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");
}
}
}
@@ -919,6 +1107,9 @@ 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
@@ -964,6 +1155,41 @@ public class WifiMetrics {
}
mWifiLogProto.recordDurationSec = (int) ((mClock.elapsedRealtime() / 1000)
- mRecordStartTimeSec);
+
+ /**
+ * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated
+ * IntKeyVal array.
+ */
+ for (int i = 0; i < mRssiPollCounts.size(); i++) {
+ WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
+ keyVal.rssi = mRssiPollCounts.keyAt(i);
+ keyVal.count = mRssiPollCounts.valueAt(i);
+ 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);
}
}
@@ -979,6 +1205,9 @@ public class WifiMetrics {
mScanReturnEntries.clear();
mWifiSystemStateEntries.clear();
mRecordStartTimeSec = mClock.elapsedRealtime() / 1000;
+ mRssiPollCounts.clear();
+ mWifiAlertReasonCounts.clear();
+ mWifiScoreCounts.clear();
mWifiLogProto.clear();
}
}
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 8aad480e7..d9366e766 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -612,7 +612,7 @@ public class WifiMonitor {
while (true) {
if (mWifiNative.connectToSupplicant()) {
mConnected = true;
- new MonitorThread().start();
+ new MonitorThread(mWifiNative.getLocalLog()).start();
return true;
}
if (connectTries++ < 50) {
@@ -741,10 +741,11 @@ public class WifiMonitor {
}
private class MonitorThread extends Thread {
- private final LocalLog mLocalLog = mWifiNative.getLocalLog();
+ private final LocalLog mLocalLog;
- public MonitorThread() {
+ public MonitorThread(LocalLog localLog) {
super("WifiMonitor");
+ mLocalLog = localLog;
}
public void run() {
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 07f3abfa6..f9a1b0173 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -77,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;
@@ -104,7 +106,7 @@ public class WifiNative {
private static final LocalLog sLocalLog = new LocalLog(8192);
- public static LocalLog getLocalLog() {
+ public @NonNull LocalLog getLocalLog() {
return sLocalLog;
}
@@ -1713,6 +1715,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));
+ }
}
/**
@@ -2190,13 +2205,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;
@@ -2215,7 +2229,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/WifiNetworkHistory.java b/service/java/com/android/server/wifi/WifiNetworkHistory.java
index e370a11a9..5b285f5f3 100644
--- a/service/java/com/android/server/wifi/WifiNetworkHistory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkHistory.java
@@ -37,6 +37,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.util.BitSet;
@@ -556,12 +557,14 @@ public class WifiNetworkHistory {
}
}
}
- } catch (NumberFormatException e) {
- Log.e(TAG, "readNetworkHistory: failed to read, revert to default, " + e, e);
} catch (EOFException e) {
// do nothing
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "readNetworkHistory: no config file, " + e);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "readNetworkHistory: failed to parse, " + e, e);
} catch (IOException e) {
- Log.e(TAG, "readNetworkHistory: No config file, revert to default, " + e, e);
+ Log.e(TAG, "readNetworkHistory: failed to read, " + e, e);
}
}
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
index e916c8825..ed4a0bd12 100644
--- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
@@ -99,8 +99,7 @@ public class WifiQualifiedNetworkSelector {
private static final int INVALID_TIME_STAMP = -1;
private long mLastQualifiedNetworkSelectionTimeStamp = INVALID_TIME_STAMP;
- // Temporarily, for dog food
- private final LocalLog mLocalLog = new LocalLog(1024);
+ private final LocalLog mLocalLog = new LocalLog(512);
private int mRssiScoreSlope = RSSI_SCORE_SLOPE;
private int mRssiScoreOffset = RSSI_SCORE_OFFSET;
private int mSameBssidAward = SAME_BSSID_AWARD;
@@ -627,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)) {
@@ -791,7 +790,9 @@ public class WifiQualifiedNetworkSelector {
potentialCandidate = network;
}
//update the cached candidate
- if (score > status.getCandidateScore()) {
+ if (score > status.getCandidateScore() || (score == status.getCandidateScore()
+ && status.getCandidate() != null
+ && scanResult.level > status.getCandidate().level)) {
status.setCandidate(scanResult);
status.setCandidateScore(score);
}
@@ -805,6 +806,7 @@ public class WifiQualifiedNetworkSelector {
currentHighestScore = highestScore;
scanResultCandidate = scanResult;
networkCandidate = configurationCandidateForThisScan;
+ networkCandidate.getNetworkSelectionStatus().setCandidate(scanResultCandidate);
}
}
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/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 297c29f78..e5a537dd0 100755
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -136,6 +136,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private static final boolean DBG = true;
private static final boolean VDBG = false;
private boolean mIsFactoryResetOn = false;
+ private boolean mSubSystemRestart = false;
private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
final WifiStateMachine mWifiStateMachine;
@@ -143,14 +144,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private final Context mContext;
private final FrameworkFacade mFacade;
- final LockList mLocks = new LockList();
- // some wifi lock statistics
- private int mFullHighPerfLocksAcquired;
- private int mFullHighPerfLocksReleased;
- private int mFullLocksAcquired;
- private int mFullLocksReleased;
- private int mScanLocksAcquired;
- private int mScanLocksReleased;
private SoftApStateMachine mSoftApStateMachine;
private int mStaAndApConcurrency = 0;
private String mSoftApInterfaceName = null;
@@ -343,6 +336,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
WifiStateMachineHandler mWifiStateMachineHandler;
private WifiController mWifiController;
+ private final WifiLockManager mWifiLockManager;
public WifiServiceImpl(Context context) {
mContext = context;
@@ -375,10 +369,11 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mNotificationController = new WifiNotificationController(mContext,
wifiThread.getLooper(), mWifiStateMachine, mFacade, null);
+ mWifiLockManager = new WifiLockManager(mContext, mBatteryStats);
mClientHandler = new ClientHandler(wifiThread.getLooper());
mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mLocks, wifiThread.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, wifiThread.getLooper(), mFacade);
if (ensureConcurrencyFileExist()) {
readConcurrencyConfig();
}
@@ -393,6 +388,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
mWifiController.setSoftApStateMachine(mSoftApStateMachine);
}
+ // Set the WifiController for WifiLastResortWatchdog
+ mWifiInjector.getWifiLastResortWatchdog().setWifiController(mWifiController);
}
@@ -431,9 +428,12 @@ public class WifiServiceImpl extends IWifiManager.Stub {
String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
Log.d(TAG, "resetting networks because SIM was removed");
- mWifiStateMachine.resetSimAuthNetworks();
+ mWifiStateMachine.resetSimAuthNetworks(false);
Log.d(TAG, "resetting country code because SIM is removed");
mCountryCode.simCardRemoved();
+ } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
+ Log.d(TAG, "resetting networks because SIM was loaded");
+ mWifiStateMachine.resetSimAuthNetworks(true);
}
}
},
@@ -1187,11 +1187,13 @@ public class WifiServiceImpl extends IWifiManager.Stub {
/**
* Get the country code
- * @return ISO 3166 country code.
+ * @return Get the best choice country code for wifi, regardless of if it was set or
+ * not.
+ * Returns null when there is no country code available.
*/
public String getCountryCode() {
enforceConnectivityInternalPermission();
- String country = mCountryCode.getCurrentCountryCode();
+ String country = mCountryCode.getCountryCode();
return country;
}
/**
@@ -1449,7 +1451,38 @@ public class WifiServiceImpl extends IWifiManager.Stub {
resetWifiNetworks();
mIsFactoryResetOn = false;
}
+ if (mSubSystemRestart) {
+ setWifiApEnabled(null, true);
+ }
+ } else if ( state == WifiManager.WIFI_STATE_DISABLED) {
+ if (mSubSystemRestart) {
+ setWifiEnabled(true);
+ }
}
+ } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+ int wifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
+ WifiManager.WIFI_AP_STATE_FAILED);
+ if (mSubSystemRestart) {
+ if (wifiApState == WifiManager.WIFI_AP_STATE_DISABLED) {
+ if (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED) {
+ setWifiEnabled(false);
+ } else {
+ /**
+ * STA in DISABLED state, hence just restart SAP.
+ * This should cover two scenarios
+ * 1. Only SAP ON ( before SSR ) in STA + SAP.
+ * 2. No STA + SAP.
+ */
+ setWifiApEnabled(null, true);
+ mSubSystemRestart = false;
+ }
+ } else if (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED) {
+ mSubSystemRestart = false;
+ }
+ }
+
+ } else if (action.equals(WifiManager.WIFI_AP_SUB_SYSTEM_RESTART)) {
+ handleSubSystemRestart();
}
}
};
@@ -1482,7 +1515,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-
+ intentFilter.addAction(WifiManager.WIFI_AP_SUB_SYSTEM_RESTART);
+ intentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
boolean trackEmergencyCallState = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
if (trackEmergencyCallState) {
@@ -1581,16 +1615,9 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
pw.println();
- pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
- mFullHighPerfLocksAcquired + " full high perf, " +
- mScanLocksAcquired + " scan");
- pw.println("Locks released: " + mFullLocksReleased + " full, " +
- mFullHighPerfLocksReleased + " full high perf, " +
- mScanLocksReleased + " scan");
- pw.println();
pw.println("Locks held:");
- mLocks.dump(pw);
-
+ mWifiLockManager.dump(pw);
+ pw.println();
pw.println("Multicast Locks held:");
for (Multicaster l : mMulticasters) {
pw.print(" ");
@@ -1603,251 +1630,35 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
- private class WifiLock extends DeathRecipient {
- int mMode;
- WorkSource mWorkSource;
-
- WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
- super(tag, binder);
- mMode = lockMode;
- mWorkSource = ws;
- }
-
- public void binderDied() {
- synchronized (mLocks) {
- releaseWifiLockLocked(mBinder);
- }
- }
-
- public String toString() {
- return "WifiLock{" + mTag + " type=" + mMode + " uid=" + mUid + "}";
- }
- }
-
- public class LockList {
- private List<WifiLock> mList;
-
- private LockList() {
- mList = new ArrayList<WifiLock>();
- }
-
- synchronized boolean hasLocks() {
- return !mList.isEmpty();
- }
-
- synchronized int getStrongestLockMode() {
- if (mList.isEmpty()) {
- return WifiManager.WIFI_MODE_FULL;
- }
-
- if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
- return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
- }
-
- if (mFullLocksAcquired > mFullLocksReleased) {
- return WifiManager.WIFI_MODE_FULL;
- }
-
- return WifiManager.WIFI_MODE_SCAN_ONLY;
- }
-
- synchronized void updateWorkSource(WorkSource ws) {
- for (int i = 0; i < mLocks.mList.size(); i++) {
- ws.add(mLocks.mList.get(i).mWorkSource);
- }
- }
-
- private void addLock(WifiLock lock) {
- if (findLockByBinder(lock.mBinder) < 0) {
- mList.add(lock);
- }
- }
-
- private WifiLock removeLock(IBinder binder) {
- int index = findLockByBinder(binder);
- if (index >= 0) {
- WifiLock ret = mList.remove(index);
- ret.unlinkDeathRecipient();
- return ret;
- } else {
- return null;
- }
- }
-
- private int findLockByBinder(IBinder binder) {
- int size = mList.size();
- for (int i = size - 1; i >= 0; i--) {
- if (mList.get(i).mBinder == binder)
- return i;
- }
- return -1;
- }
-
- private void dump(PrintWriter pw) {
- for (WifiLock l : mList) {
- pw.print(" ");
- pw.println(l);
- }
- }
- }
-
- void enforceWakeSourcePermission(int uid, int pid) {
- if (uid == android.os.Process.myUid()) {
- return;
- }
- mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
- pid, uid, null);
- }
-
+ @Override
public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
- if (lockMode != WifiManager.WIFI_MODE_FULL &&
- lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
- lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
- Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
- if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
- return false;
- }
- if (ws != null && ws.size() == 0) {
- ws = null;
- }
- if (ws != null) {
- enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
- }
- if (ws == null) {
- ws = new WorkSource(Binder.getCallingUid());
- }
- WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
- synchronized (mLocks) {
- return acquireWifiLockLocked(wifiLock);
- }
- }
-
- private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
- switch(wifiLock.mMode) {
- case WifiManager.WIFI_MODE_FULL:
- case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
- case WifiManager.WIFI_MODE_SCAN_ONLY:
- mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
- break;
- }
- }
-
- private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
- switch(wifiLock.mMode) {
- case WifiManager.WIFI_MODE_FULL:
- case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
- case WifiManager.WIFI_MODE_SCAN_ONLY:
- mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
- break;
- }
- }
-
- private boolean acquireWifiLockLocked(WifiLock wifiLock) {
- if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
-
- mLocks.addLock(wifiLock);
-
- long ident = Binder.clearCallingIdentity();
- try {
- noteAcquireWifiLock(wifiLock);
- switch(wifiLock.mMode) {
- case WifiManager.WIFI_MODE_FULL:
- ++mFullLocksAcquired;
- break;
- case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
- ++mFullHighPerfLocksAcquired;
- break;
-
- case WifiManager.WIFI_MODE_SCAN_ONLY:
- ++mScanLocksAcquired;
- break;
- }
+ if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
mWifiController.sendMessage(CMD_LOCKS_CHANGED);
return true;
- } catch (RemoteException e) {
- return false;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
- int uid = Binder.getCallingUid();
- int pid = Binder.getCallingPid();
- if (ws != null && ws.size() == 0) {
- ws = null;
- }
- if (ws != null) {
- enforceWakeSourcePermission(uid, pid);
- }
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLocks) {
- int index = mLocks.findLockByBinder(lock);
- if (index < 0) {
- throw new IllegalArgumentException("Wifi lock not active");
- }
- WifiLock wl = mLocks.mList.get(index);
- noteReleaseWifiLock(wl);
- wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
- noteAcquireWifiLock(wl);
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
}
+ return false;
}
- public boolean releaseWifiLock(IBinder lock) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
- synchronized (mLocks) {
- return releaseWifiLockLocked(lock);
- }
+ @Override
+ public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
+ mWifiLockManager.updateWifiLockWorkSource(binder, ws);
}
- private boolean releaseWifiLockLocked(IBinder lock) {
- boolean hadLock;
-
- WifiLock wifiLock = mLocks.removeLock(lock);
-
- if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
-
- hadLock = (wifiLock != null);
-
- long ident = Binder.clearCallingIdentity();
- try {
- if (hadLock) {
- noteReleaseWifiLock(wifiLock);
- switch(wifiLock.mMode) {
- case WifiManager.WIFI_MODE_FULL:
- ++mFullLocksReleased;
- break;
- case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
- ++mFullHighPerfLocksReleased;
- break;
- case WifiManager.WIFI_MODE_SCAN_ONLY:
- ++mScanLocksReleased;
- break;
- }
- mWifiController.sendMessage(CMD_LOCKS_CHANGED);
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
+ @Override
+ public boolean releaseWifiLock(IBinder binder) {
+ if (mWifiLockManager.releaseWifiLock(binder)) {
+ mWifiController.sendMessage(CMD_LOCKS_CHANGED);
+ return true;
}
-
- return hadLock;
+ return false;
}
- private abstract class DeathRecipient
- implements IBinder.DeathRecipient {
+ private class Multicaster implements IBinder.DeathRecipient {
String mTag;
int mUid;
IBinder mBinder;
- DeathRecipient(String tag, IBinder binder) {
- super();
+ Multicaster(String tag, IBinder binder) {
mTag = tag;
mUid = Binder.getCallingUid();
mBinder = binder;
@@ -1858,20 +1669,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
- void unlinkDeathRecipient() {
- mBinder.unlinkToDeath(this, 0);
- }
-
- public int getUid() {
- return mUid;
- }
- }
-
- private class Multicaster extends DeathRecipient {
- Multicaster(String tag, IBinder binder) {
- super(tag, binder);
- }
-
+ @Override
public void binderDied() {
Slog.e(TAG, "Multicaster binderDied");
synchronized (mMulticasters) {
@@ -1882,6 +1680,14 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
public String toString() {
return "Multicaster{" + mTag + " uid=" + mUid + "}";
}
@@ -1971,6 +1777,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
enforceAccessPermission();
mWifiStateMachine.enableVerboseLogging(verbose);
mWifiController.enableVerboseLogging(verbose);
+ mWifiLockManager.enableVerboseLogging(verbose);
}
public int getVerboseLoggingLevel() {
@@ -2297,4 +2104,9 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
return true;
}
+
+ private void handleSubSystemRestart() {
+ mSubSystemRestart = true;
+ setWifiApEnabled(null, false);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 5815f0e59..f35a92b60 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;
@@ -110,6 +111,7 @@ import com.android.server.wifi.hotspot2.IconEvent;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
+import com.android.server.wifi.util.TelephonyUtil;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -582,10 +584,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;
@@ -1080,7 +1086,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
R.bool.config_wifi_enable_wifi_firmware_debugging);
if (enableFirmwareLogs) {
- mWifiLogger = facade.makeRealLogger(this, mWifiNative, mBuildProperties);
+ mWifiLogger = facade.makeRealLogger(mContext, this, mWifiNative, mBuildProperties);
} else {
mWifiLogger = facade.makeBaseLogger();
}
@@ -1176,7 +1182,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
sendMessage(CMD_BOOT_COMPLETED);
}
},
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_AUTO_CONNECT_TYPE), false,
@@ -1356,25 +1362,39 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
void enableVerboseLogging(int verbose) {
+ if (mVerboseLoggingLevel == verbose) {
+ // We are already at the desired verbosity, avoid resetting StateMachine log records by
+ // returning here until underlying bug is fixed (b/28027593)
+ return;
+ }
mVerboseLoggingLevel = verbose;
mFacade.setIntegerSetting(
mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
updateLoggingLevel();
}
+ /**
+ * Set wpa_supplicant log level using |mVerboseLoggingLevel| flag.
+ */
+ void setSupplicantLogLevel() {
+ if (mVerboseLoggingLevel > 0) {
+ mWifiNative.setSupplicantLogLevel("DEBUG");
+ } else {
+ mWifiNative.setSupplicantLogLevel("INFO");
+ }
+ }
+
void updateLoggingLevel() {
if (mVerboseLoggingLevel > 0) {
DBG = true;
- mWifiNative.setSupplicantLogLevel("DEBUG");
setLogRecSize(ActivityManager.isLowRamDeviceStatic()
? NUM_LOG_RECS_VERBOSE_LOW_MEMORY : NUM_LOG_RECS_VERBOSE);
- configureVerboseHalLogging(true);
} else {
DBG = false;
- mWifiNative.setSupplicantLogLevel("INFO");
setLogRecSize(NUM_LOG_RECS_NORMAL);
- configureVerboseHalLogging(false);
}
+ configureVerboseHalLogging(mVerboseLoggingLevel > 0);
+ setSupplicantLogLevel();
mCountryCode.enableVerboseLogging(mVerboseLoggingLevel);
mWifiLogger.startLogging(DBG);
mWifiMonitor.enableVerboseLogging(mVerboseLoggingLevel);
@@ -2006,6 +2026,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
/**
+ * Allow tests to confirm the operational mode for WSM.
+ */
+ @VisibleForTesting
+ protected int getOperationalModeForTest() {
+ return mOperationalMode;
+ }
+
+ /**
* TODO: doc
*/
public List<ScanResult> syncGetScanResultsList() {
@@ -2280,8 +2308,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
/**
* reset cached SIM credential data
*/
- public synchronized void resetSimAuthNetworks() {
- sendMessage(CMD_RESET_SIM_NETWORKS);
+ public synchronized void resetSimAuthNetworks(boolean simPresent) {
+ sendMessage(CMD_RESET_SIM_NETWORKS, simPresent ? 1 : 0);
}
/**
@@ -2414,6 +2442,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);
@@ -2427,10 +2462,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
pw.println("Supplicant status " + mWifiNative.status(true));
- if (mCountryCode.getCurrentCountryCode() != null) {
- pw.println("CurrentCountryCode " + mCountryCode.getCurrentCountryCode());
+ if (mCountryCode.getCountryCodeSentToDriver() != null) {
+ pw.println("CountryCode sent to driver " + mCountryCode.getCountryCodeSentToDriver());
} else {
- pw.println("CurrentCountryCode is not initialized");
+ if (mCountryCode.getCountryCode() != null) {
+ pw.println("CountryCode: " +
+ mCountryCode.getCountryCode() + " was not sent to driver");
+ } else {
+ pw.println("CountryCode was not initialized");
+ }
}
pw.println("mConnectedModeGScanOffloadStarted " + mConnectedModeGScanOffloadStarted);
pw.println("mGScanPeriodMilli " + mGScanPeriodMilli);
@@ -2657,7 +2697,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);
@@ -3030,12 +3071,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
enableRssiPolling(screenOn);
if (mUserWantsSuspendOpt.get()) {
+ int shouldReleaseWakeLock = 0;
if (screenOn) {
- sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
+ sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, shouldReleaseWakeLock);
} else {
- // Allow 2s for suspend optimizations to be set
- mSuspendWakeLock.acquire(2000);
- sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
+ if (isConnected()) {
+ // Allow 2s for suspend optimizations to be set
+ mSuspendWakeLock.acquire(2000);
+ shouldReleaseWakeLock = 1;
+ }
+ sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, shouldReleaseWakeLock);
}
}
mScreenBroadcastReceived.set(true);
@@ -3281,6 +3326,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (newRssi > 0) newRssi -= 256;
mWifiInfo.setRssi(newRssi);
/*
+ * Log the rssi poll value in metrics
+ */
+ mWifiMetrics.incrementRssiPollRssiCount(newRssi);
+ /*
* Rather then sending the raw RSSI out every time it
* changes, we precalculate the signal level that would
* be displayed in the status bar, and only send the
@@ -4016,23 +4065,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);
}
@@ -4041,9 +4100,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);
+ }
}
}
}
@@ -4053,9 +4117,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);
+ }
+ }
}
}
}
@@ -4213,7 +4282,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
break;
case CMD_SET_SUSPEND_OPT_ENABLED:
if (message.arg1 == 1) {
- mSuspendWakeLock.release();
+ if (message.arg2 == 1) {
+ mSuspendWakeLock.release();
+ }
setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
} else {
setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
@@ -4259,7 +4330,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:
@@ -4424,6 +4497,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
updateDataInterface();
if (mWifiNative.startSupplicant(mP2pSupported)) {
+ setSupplicantLogLevel();
setWifiState(WIFI_STATE_ENABLING);
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring(mInterfaceName);
@@ -4450,6 +4524,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
transitionTo(mInitialState);
}
break;
+ case CMD_SET_OPERATIONAL_MODE:
+ mOperationalMode = message.arg1;
+ break;
default:
return NOT_HANDLED;
}
@@ -4652,7 +4729,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
replyToMessage(message, message.what, stats);
break;
case CMD_RESET_SIM_NETWORKS:
- log("resetting EAP-SIM/AKA/AKA' networks since SIM was removed");
+ log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed");
mWifiConfigManager.resetSimNetworks();
break;
default:
@@ -4811,10 +4888,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);
@@ -4957,7 +5037,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case CMD_SET_SUSPEND_OPT_ENABLED:
if (message.arg1 == 1) {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
- mSuspendWakeLock.release();
+ if (message.arg2 == 1) {
+ mSuspendWakeLock.release();
+ }
} else {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
}
@@ -5704,8 +5786,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);
@@ -5770,24 +5855,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
&& targetWificonfiguration.networkId == networkId
&& targetWificonfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.IEEE8021X)
- && (eapMethod == WifiEnterpriseConfig.Eap.SIM
- || eapMethod == WifiEnterpriseConfig.Eap.AKA
- || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
- TelephonyManager tm = (TelephonyManager)
- mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm != null) {
- String imsi = tm.getSubscriberId();
- String mccMnc = "";
-
- if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
- mccMnc = tm.getSimOperator();
-
- String identity = buildIdentity(eapMethod, imsi, mccMnc);
-
- if (!identity.isEmpty()) {
- mWifiNative.simIdentityResponse(networkId, identity);
- identitySent = true;
- }
+ && TelephonyUtil.isSimEapMethod(eapMethod)) {
+ String identity = TelephonyUtil.getSimIdentity(mContext, eapMethod);
+ if (identity != null) {
+ mWifiNative.simIdentityResponse(networkId, identity);
+ identitySent = true;
}
}
if (!identitySent) {
@@ -5829,12 +5901,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
replyToMessage(message, message.what,
mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
break;
- /* Do a redundant disconnect without transition */
- case CMD_DISCONNECT:
- mWifiConfigManager.setAndEnableLastSelectedConfiguration
- (WifiConfiguration.INVALID_NETWORK_ID);
- mWifiNative.disconnect();
- break;
case CMD_RECONNECT:
if (mWifiConnectivityManager != null) {
mWifiConnectivityManager.forceConnectivityScan();
@@ -6810,7 +6876,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);
@@ -6882,10 +6949,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
stopRssiMonitoringOffload();
break;
case CMD_RESET_SIM_NETWORKS:
- if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ if (message.arg1 == 0 // sim was removed
+ && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
WifiConfiguration config =
mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
- if (mWifiConfigManager.isSimConfig(config)) {
+ if (TelephonyUtil.isSimConfig(config)) {
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
}
@@ -7276,8 +7344,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 ||
@@ -7422,18 +7488,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):
@@ -7583,6 +7647,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
case CMD_START_SCAN:
deferMessage(message);
return HANDLED;
+ case CMD_DISCONNECT:
+ if (DBG) log("Ignore CMD_DISCONNECT when already disconnecting.");
+ break;
case CMD_DISCONNECTING_WATCHDOG_TIMER:
if (disconnectingWatchdogCount == message.arg1) {
if (DBG) log("disconnecting watchdog! -> disconnect");
@@ -7684,7 +7751,19 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
setAndEnableLastSelectedConfiguration(
WifiConfiguration.INVALID_NETWORK_ID);
break;
- /* Ignore network disconnect */
+ case CMD_DISCONNECT:
+ if (SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) {
+ if (DBG) {
+ log("CMD_DISCONNECT when supplicant is connecting - do not ignore");
+ }
+ mWifiConfigManager.setAndEnableLastSelectedConfiguration(
+ WifiConfiguration.INVALID_NETWORK_ID);
+ mWifiNative.disconnect();
+ break;
+ }
+ if (DBG) log("Ignore CMD_DISCONNECT when already disconnected.");
+ break;
+ /* Ignore network disconnect */
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
// Interpret this as an L2 connection failure
break;
@@ -7877,11 +7956,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
sendMessage(CMD_AP_STOPPED);
} else if (state == WIFI_AP_STATE_FAILED) {
sendMessage(CMD_START_AP_FAILURE);
- } else if (state == WifiManager.WIFI_AP_STATE_RESTART) {
- sendMessage(CMD_AP_STOPPED);
- sendMessage(CMD_START_AP, null);
- return;
}
+
setWifiApState(state, reason);
}
}
@@ -7906,7 +7982,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
checkAndSetConnectivityInstance();
mSoftApManager = mFacade.makeSoftApManager(
mContext, getHandler().getLooper(), mWifiNative, mNwService,
- mCm, mCountryCode.getCurrentCountryCode(),
+ mCm, mCountryCode.getCountryCode(),
mWifiApConfigStore.getAllowed2GChannel(),
new SoftApListener());
mSoftApManager.start(config);
@@ -8117,6 +8193,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
return result;
}
+ // TODO move to TelephonyUtil, same with utilities above
String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
StringBuilder sb = new StringBuilder();
for (String challenge : requestData) {
@@ -8178,6 +8255,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
return sb.toString();
}
+ // TODO move to TelephonyUtil
void handleGsmAuthRequest(SimAuthRequestData requestData) {
if (targetWificonfiguration == null
|| targetWificonfiguration.networkId == requestData.networkId) {
@@ -8205,6 +8283,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
+ // TODO move to TelephonyUtil
void handle3GAuthRequest(SimAuthRequestData requestData) {
StringBuilder sb = new StringBuilder();
byte[] rand = null;
@@ -8293,7 +8372,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);
+ }
+ }
}
/**
@@ -8344,6 +8427,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++;
@@ -8357,6 +8442,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);
@@ -8364,17 +8455,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) {
@@ -8473,4 +8555,11 @@ 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/configparse/ConfigBuilder.java b/service/java/com/android/server/wifi/configparse/ConfigBuilder.java
index 070c69b95..9bcfddbb6 100644
--- a/service/java/com/android/server/wifi/configparse/ConfigBuilder.java
+++ b/service/java/com/android/server/wifi/configparse/ConfigBuilder.java
@@ -173,26 +173,25 @@ public class ConfigBuilder {
List<X509Certificate> clientChain, PrivateKey key)
throws IOException, GeneralSecurityException {
- Credential credential = homeSP.getCredential();
-
WifiConfiguration config;
- EAP.EAPMethodID eapMethodID = credential.getEAPMethod().getEAPMethodID();
+ EAP.EAPMethodID eapMethodID = homeSP.getCredential().getEAPMethod().getEAPMethodID();
switch (eapMethodID) {
case EAP_TTLS:
if (key != null || clientChain != null) {
- Log.w(TAG, "Client cert and/or key included with EAP-TTLS profile");
+ Log.w(TAG, "Client cert and/or key unnecessarily included with EAP-TTLS "+
+ "profile");
}
- config = buildTTLSConfig(homeSP);
+ config = buildTTLSConfig(homeSP, caCert);
break;
case EAP_TLS:
- config = buildTLSConfig(homeSP, clientChain, key);
+ config = buildTLSConfig(homeSP, clientChain, key, caCert);
break;
case EAP_AKA:
case EAP_AKAPrim:
case EAP_SIM:
if (key != null || clientChain != null || caCert != null) {
- Log.i(TAG, "Client/CA cert and/or key included with " +
+ Log.i(TAG, "Client/CA cert and/or key unnecessarily included with " +
eapMethodID + " profile");
}
config = buildSIMConfig(homeSP);
@@ -201,11 +200,6 @@ public class ConfigBuilder {
throw new IOException("Unsupported EAP Method: " + eapMethodID);
}
- WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
-
- enterpriseConfig.setCaCertificate(caCert);
- enterpriseConfig.setAnonymousIdentity("anonymous@" + credential.getRealm());
-
return config;
}
@@ -233,7 +227,28 @@ public class ConfigBuilder {
}
*/
- private static WifiConfiguration buildTTLSConfig(HomeSP homeSP)
+ private static void setAnonymousIdentityToNaiRealm(
+ WifiConfiguration config, Credential credential) {
+ /**
+ * Set WPA supplicant's anonymous identity field to a string containing the NAI realm, so
+ * that this value will be sent to the EAP server as part of the EAP-Response/ Identity
+ * packet. WPA supplicant will reset this field after using it for the EAP-Response/Identity
+ * packet, and revert to using the (real) identity field for subsequent transactions that
+ * request an identity (e.g. in EAP-TTLS).
+ *
+ * This NAI realm value (the portion of the identity after the '@') is used to tell the
+ * AAA server which AAA/H to forward packets to. The hardcoded username, "anonymous", is a
+ * placeholder that is not used--it is set to this value by convention. See Section 5.1 of
+ * RFC3748 for more details.
+ *
+ * NOTE: we do not set this value for EAP-SIM/AKA/AKA', since the EAP server expects the
+ * EAP-Response/Identity packet to contain an actual, IMSI-based identity, in order to
+ * identify the device.
+ */
+ config.enterpriseConfig.setAnonymousIdentity("anonymous@" + credential.getRealm());
+ }
+
+ private static WifiConfiguration buildTTLSConfig(HomeSP homeSP, X509Certificate caCert)
throws IOException {
Credential credential = homeSP.getCredential();
@@ -255,13 +270,17 @@ public class ConfigBuilder {
enterpriseConfig.setPhase2Method(remapInnerMethod(ttlsParam.getType()));
enterpriseConfig.setIdentity(credential.getUserName());
enterpriseConfig.setPassword(credential.getPassword());
+ enterpriseConfig.setCaCertificate(caCert);
+
+ setAnonymousIdentityToNaiRealm(config, credential);
return config;
}
private static WifiConfiguration buildTLSConfig(HomeSP homeSP,
List<X509Certificate> clientChain,
- PrivateKey clientKey)
+ PrivateKey clientKey,
+ X509Certificate caCert)
throws IOException, GeneralSecurityException {
Credential credential = homeSP.getCredential();
@@ -296,6 +315,9 @@ public class ConfigBuilder {
WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
enterpriseConfig.setClientCertificateAlias(alias);
enterpriseConfig.setClientKeyEntry(clientKey, clientCertificate);
+ enterpriseConfig.setCaCertificate(caCert);
+
+ setAnonymousIdentityToNaiRealm(config, credential);
return config;
}
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/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index 5b82167e5..ad259d653 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -1376,8 +1376,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
WifiP2pDevice owner = group.getOwner();
if (owner == null) {
- loge("Ignored invitation from null owner");
- break;
+ int id = group.getNetworkId();
+ if (id < 0) {
+ loge("Ignored invitation from null owner");
+ break;
+ }
+
+ String addr = mGroups.getOwnerAddr(id);
+ if (addr != null) {
+ group.setOwner(new WifiP2pDevice(addr));
+ owner = group.getOwner();
+ } else {
+ loge("Ignored invitation from null owner");
+ break;
+ }
}
config = new WifiP2pConfig();
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 7108cb857..9f8fb2f58 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -76,7 +76,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private static final int MIN_PERIOD_PER_CHANNEL_MS = 200; // DFS needs 120 ms
private static final int UNKNOWN_PID = -1;
- private final LocalLog mLocalLog = new LocalLog(1024);
+ private final LocalLog mLocalLog = new LocalLog(512);
private void localLog(String message) {
mLocalLog.log(message);
@@ -136,7 +136,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
if (client != null) {
- logw("duplicate client connection: " + msg.sendingUid);
+ logw("duplicate client connection: " + msg.sendingUid + ", messenger="
+ + msg.replyTo);
client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
return;
@@ -151,7 +152,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
AsyncChannel.STATUS_SUCCESSFUL);
- if (DBG) Log.d(TAG, "client connected: " + client);
+ localLog("client connected: " + client);
return;
}
case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
@@ -163,10 +164,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
- if (client != null) {
- if (DBG) {
- Log.d(TAG, "client disconnected: " + client + ", reason: " + msg.arg1);
- }
+ 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();
}
return;
@@ -215,6 +216,15 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
mWifiChangeStateMachine.sendMessage(Message.obtain(msg));
break;
+ case WifiScanner.CMD_REGISTER_SCAN_LISTENER:
+ logScanRequest("registerScanListener", ci, msg.arg2, null, null, null);
+ mSingleScanListeners.addRequest(ci, msg.arg2, null, null);
+ replySucceeded(msg);
+ break;
+ case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER:
+ logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null);
+ mSingleScanListeners.removeRequest(ci, msg.arg2);
+ break;
default:
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request");
break;
@@ -243,6 +253,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private final WifiScannerImpl.WifiScannerImplFactory mScannerImplFactory;
private final ArrayMap<Messenger, ClientInfo> mClients;
+ private final RequestList<Void> mSingleScanListeners = new RequestList<>();
+
private ChannelHelper mChannelHelper;
private BackgroundScanScheduler mBackgroundScheduler;
private WifiNative.ScanSettings mPreviousSchedule;
@@ -419,6 +431,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private final IdleState mIdleState = new IdleState();
private final ScanningState mScanningState = new ScanningState();
+ private WifiNative.ScanSettings mActiveScanSettings = null;
private RequestList<ScanSettings> mActiveScans = new RequestList<>();
private RequestList<ScanSettings> mPendingScans = new RequestList<>();
@@ -547,12 +560,24 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
WorkSource workSource =
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
- if (validateAndAddToScanQueue(ci, handler, scanSettings, workSource)) {
+ if (validateScanRequest(ci, handler, scanSettings, workSource)) {
+ logScanRequest("addSingleScanRequest", ci, handler, workSource,
+ scanSettings, null);
replySucceeded(msg);
+
+ // If there is an active scan that will fulfill the scan request then
+ // mark this request as an active scan, otherwise mark it pending.
// If were not currently scanning then try to start a scan. Otherwise
// this scan will be scheduled when transitioning back to IdleState
// after finishing the current scan.
- if (getCurrentState() != mScanningState) {
+ if (getCurrentState() == mScanningState) {
+ if (activeScanSatisfies(scanSettings)) {
+ mActiveScans.addRequest(ci, handler, workSource, scanSettings);
+ } else {
+ mPendingScans.addRequest(ci, handler, workSource, scanSettings);
+ }
+ } else {
+ mPendingScans.addRequest(ci, handler, workSource, scanSettings);
tryToStartNewScan();
}
} else {
@@ -598,6 +623,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
@Override
public void exit() {
+ mActiveScanSettings = null;
try {
mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
} catch (RemoteException e) {
@@ -639,7 +665,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
}
- boolean validateAndAddToScanQueue(ClientInfo ci, int handler, ScanSettings settings,
+ boolean validateScanRequest(ClientInfo ci, int handler, ScanSettings settings,
WorkSource workSource) {
if (ci == null) {
Log.d(TAG, "Failing single scan request ClientInfo not found " + handler);
@@ -651,8 +677,46 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
return false;
}
}
- logScanRequest("addSingleScanRequest", ci, handler, workSource, settings, null);
- mPendingScans.addRequest(ci, handler, workSource, settings);
+ return true;
+ }
+
+ boolean activeScanSatisfies(ScanSettings settings) {
+ if (mActiveScanSettings == null) {
+ return false;
+ }
+
+ // there is always one bucket for a single scan
+ WifiNative.BucketSettings activeBucket = mActiveScanSettings.buckets[0];
+
+ // validate that all requested channels are being scanned
+ ChannelCollection activeChannels = mChannelHelper.createChannelCollection();
+ activeChannels.addChannels(activeBucket);
+ if (!activeChannels.containsSettings(settings)) {
+ return false;
+ }
+
+ // if the request is for a full scan, but there is no ongoing full scan
+ if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
+ && (activeBucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
+ == 0) {
+ return false;
+ }
+
+ if (settings.hiddenNetworkIds != null) {
+ if (mActiveScanSettings.hiddenNetworkIds == null) {
+ return false;
+ }
+ Set<Integer> activeHiddenNetworkIds = new HashSet<>();
+ for (int id : mActiveScanSettings.hiddenNetworkIds) {
+ activeHiddenNetworkIds.add(id);
+ }
+ for (int id : settings.hiddenNetworkIds) {
+ if (!activeHiddenNetworkIds.contains(id)) {
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -711,6 +775,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};
if (mScannerImpl.startSingleScan(settings, this)) {
+ // store the active scan settings
+ mActiveScanSettings = settings;
// swap pending and active scan requests
RequestList<ScanSettings> tmp = mActiveScans;
mActiveScans = mPendingScans;
@@ -745,6 +811,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result);
}
}
+
+ for (RequestInfo<Void> entry : mSingleScanListeners) {
+ entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result);
+ }
}
void reportScanResults(ScanData results) {
@@ -755,18 +825,26 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mWifiMetrics.incrementEmptyScanResultCount();
}
}
+ ScanData[] allResults = new ScanData[] {results};
for (RequestInfo<ScanSettings> entry : mActiveScans) {
- ScanData[] resultsArray = new ScanData[] {results};
ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
- mChannelHelper, resultsArray, entry.settings, -1);
- WifiScanner.ParcelableScanData parcelableScanData =
+ mChannelHelper, allResults, entry.settings, -1);
+ WifiScanner.ParcelableScanData parcelableResultsToDeliver =
new WifiScanner.ParcelableScanData(resultsToDeliver);
logCallback("singleScanResults", entry.clientInfo, entry.handlerId,
describeForLog(resultsToDeliver));
- entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableScanData);
+ entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
// make sure the handler is removed
entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
}
+
+ WifiScanner.ParcelableScanData parcelableAllResults =
+ new WifiScanner.ParcelableScanData(allResults);
+ for (RequestInfo<Void> entry : mSingleScanListeners) {
+ logCallback("singleScanResults", entry.clientInfo, entry.handlerId,
+ describeForLog(allResults));
+ entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
+ }
}
}
@@ -976,8 +1054,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
replySucceeded(msg);
break;
case WifiScanner.CMD_SET_HOTLIST:
- addHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj);
- replySucceeded(msg);
+ if (addHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
break;
case WifiScanner.CMD_RESET_HOTLIST:
removeHotlist(ci, msg.arg2);
@@ -1117,13 +1198,13 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (DBG) Log.d(TAG, "scan stopped");
return true;
} else {
- Log.d(TAG, "starting scan: "
+ localLog("starting scan: "
+ "base period=" + schedule.base_period_ms
+ ", max ap per scan=" + schedule.max_ap_per_scan
+ ", batched scans=" + schedule.report_threshold_num_scans);
for (int b = 0; b < schedule.num_buckets; b++) {
WifiNative.BucketSettings bucket = schedule.buckets[b];
- Log.d(TAG, "bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)"
+ localLog("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)"
+ "[" + bucket.report_events + "]: "
+ ChannelHelper.toString(bucket));
}
@@ -1214,14 +1295,22 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mActiveBackgroundScans.clear();
}
- private void addHotlist(ClientInfo ci, int handler, WifiScanner.HotlistSettings settings) {
+ private boolean addHotlist(ClientInfo ci, int handler,
+ WifiScanner.HotlistSettings settings) {
+ if (ci == null) {
+ Log.d(TAG, "Failing hotlist request ClientInfo not found " + handler);
+ return false;
+ }
mActiveHotlistSettings.addRequest(ci, handler, null, settings);
resetHotlist();
+ return true;
}
private void removeHotlist(ClientInfo ci, int handler) {
- mActiveHotlistSettings.removeRequest(ci, handler);
- resetHotlist();
+ if (ci != null) {
+ mActiveHotlistSettings.removeRequest(ci, handler);
+ resetHotlist();
+ }
}
private void resetHotlist() {
@@ -1820,6 +1909,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
public void cleanup() {
+ mSingleScanListeners.removeAllForClient(this);
mSingleScanStateMachine.removeSingleScanRequests(this);
mBackgroundScanStateMachine.removeBackgroundScanSettings(this);
mBackgroundScanStateMachine.removeHotlistSettings(this);
@@ -1891,7 +1981,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
@Override
public String toString() {
- return "ClientInfo[uid=" + mUid + "]";
+ return "ClientInfo[uid=" + mUid + "," + mMessenger + "]";
}
}
@@ -1988,6 +2078,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
public void sendRequestToClientHandler(int what) {
sendRequestToClientHandler(what, null, null);
}
+
+ @Override
+ public String toString() {
+ return "InternalClientInfo[]";
+ }
}
void replySucceeded(Message msg) {
@@ -2080,9 +2175,12 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
case WifiScanner.CMD_START_TRACKING_CHANGE:
- addWifiChangeHandler(ci, msg.arg2);
- replySucceeded(msg);
- transitionTo(mMovingState);
+ if (addWifiChangeHandler(ci, msg.arg2)) {
+ replySucceeded(msg);
+ transitionTo(mMovingState);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
break;
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
// nothing to do
@@ -2114,8 +2212,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
case WifiScanner.CMD_START_TRACKING_CHANGE:
- addWifiChangeHandler(ci, msg.arg2);
- replySucceeded(msg);
+ if (addWifiChangeHandler(ci, msg.arg2)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
break;
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
removeWifiChangeHandler(ci, msg.arg2);
@@ -2167,8 +2268,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
case WifiScanner.CMD_START_TRACKING_CHANGE:
- addWifiChangeHandler(ci, msg.arg2);
- replySucceeded(msg);
+ if (addWifiChangeHandler(ci, msg.arg2)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
break;
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
removeWifiChangeHandler(ci, msg.arg2);
@@ -2394,7 +2498,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
}
- private void addWifiChangeHandler(ClientInfo ci, int handler) {
+ private boolean addWifiChangeHandler(ClientInfo ci, int handler) {
+ if (ci == null) {
+ Log.d(TAG, "Failing wifi change request ClientInfo not found " + handler);
+ return false;
+ }
mActiveWifiChangeHandlers.add(Pair.create(ci, handler));
// Add an internal client to make background scan requests.
if (mInternalClientInfo == null) {
@@ -2402,11 +2510,14 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
new InternalClientInfo(ci.getUid(), new Messenger(this.getHandler()));
mInternalClientInfo.register();
}
+ return true;
}
private void removeWifiChangeHandler(ClientInfo ci, int handler) {
- mActiveWifiChangeHandlers.remove(Pair.create(ci, handler));
- untrackSignificantWifiChangeOnEmpty();
+ if (ci != null) {
+ mActiveWifiChangeHandlers.remove(Pair.create(ci, handler));
+ untrackSignificantWifiChangeOnEmpty();
+ }
}
private void untrackSignificantWifiChangeOnEmpty() {
@@ -2520,7 +2631,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
StringBuilder sb = new StringBuilder();
sb.append(request)
.append(": ")
- .append(ci.toString())
+ .append((ci == null) ? "ClientInfo[unknown]" : ci.toString())
.append(",Id=")
.append(id);
if (workSource != null) {
@@ -2540,11 +2651,9 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
void logCallback(String callback, ClientInfo ci, int id, String extra) {
StringBuilder sb = new StringBuilder();
sb.append(callback)
- .append(": ");
- if (ci != null) {
- sb.append(ci.toString());
- }
- sb .append(",Id=")
+ .append(": ")
+ .append((ci == null) ? "ClientInfo[unknown]" : ci.toString())
+ .append(",Id=")
.append(id);
if (extra != null) {
sb.append(",").append(extra);
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/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java
new file mode 100644
index 000000000..3d7ce455c
--- /dev/null
+++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.util;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.telephony.TelephonyManager;
+
+/**
+ * Utilities for the Wifi Service to interact with telephony.
+ */
+public class TelephonyUtil {
+
+ /**
+ * Get the identity for the current SIM or null if the sim is not available
+ */
+ public static String getSimIdentity(Context context, int eapMethod) {
+ TelephonyManager tm = TelephonyManager.from(context);
+ if (tm != null) {
+ String imsi = tm.getSubscriberId();
+ String mccMnc = "";
+
+ if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
+ mccMnc = tm.getSimOperator();
+ }
+
+ return buildIdentity(eapMethod, imsi, mccMnc);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * create Permanent Identity base on IMSI,
+ *
+ * rfc4186 & rfc4187:
+ * identity = usernam@realm
+ * with username = prefix | IMSI
+ * and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
+ */
+ private static String buildIdentity(int eapMethod, String imsi, String mccMnc) {
+ if (imsi == null || imsi.isEmpty()) {
+ return null;
+ }
+
+ String prefix;
+ if (eapMethod == WifiEnterpriseConfig.Eap.SIM) {
+ prefix = "1";
+ } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) {
+ prefix = "0";
+ } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) {
+ prefix = "6";
+ } else { // not a valide EapMethod
+ return null;
+ }
+
+ /* extract mcc & mnc from mccMnc */
+ String mcc;
+ String mnc;
+ if (mccMnc != null && !mccMnc.isEmpty()) {
+ mcc = mccMnc.substring(0, 3);
+ mnc = mccMnc.substring(3);
+ if (mnc.length() == 2) {
+ mnc = "0" + mnc;
+ }
+ } else {
+ // extract mcc & mnc from IMSI, assume mnc size is 3
+ mcc = imsi.substring(0, 3);
+ mnc = imsi.substring(3, 6);
+ }
+
+ return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
+ }
+
+ /**
+ * Checks if the network is a sim config.
+ *
+ * @param config Config corresponding to the network.
+ * @return true if it is a sim config, false otherwise.
+ */
+ public static boolean isSimConfig(WifiConfiguration config) {
+ if (config == null || config.enterpriseConfig == null) {
+ return false;
+ }
+
+ return isSimEapMethod(config.enterpriseConfig.getEapMethod());
+ }
+
+ /**
+ * Checks if the network is a sim config.
+ *
+ * @param method
+ * @return true if it is a sim config, false otherwise.
+ */
+ public static boolean isSimEapMethod(int eapMethod) {
+ return eapMethod == WifiEnterpriseConfig.Eap.SIM
+ || eapMethod == WifiEnterpriseConfig.Eap.AKA
+ || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME;
+ }
+}
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 80a19c00e..baed910b4 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -849,6 +849,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);
@@ -1175,7 +1182,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);
@@ -1222,14 +1229,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",
@@ -1238,14 +1243,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",
@@ -1266,7 +1269,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;
@@ -1284,7 +1287,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;
}
@@ -1309,18 +1312,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;
@@ -1334,7 +1325,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");
@@ -1353,7 +1344,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 43a4166dc..8128ec115 100644
--- a/service/proto/wifi.proto
+++ b/service/proto/wifi.proto
@@ -186,6 +186,49 @@ message WifiLog {
// The time duration represented by this wifi log, from start to end of capture
optional int32 record_duration_sec = 34;
+
+ // 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.
@@ -257,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.
@@ -265,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 {
@@ -337,3 +383,30 @@ message ConnectionEvent {
// Has bug report been taken.
optional bool automatic_bug_report_taken = 9;
}
+
+// Number of occurrences of a specific RSSI poll rssi value
+message RssiPollCount {
+ // RSSI
+ optional int32 rssi = 1;
+
+ // 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/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index c091517d7..b91df5ae3 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -20,7 +20,6 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,7 +29,6 @@ import android.content.Context;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.InterfaceConfiguration;
-import android.net.LinkAddress;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
@@ -69,12 +67,6 @@ public class SoftApManagerTest {
@Mock SoftApManager.Listener mListener;
@Mock InterfaceConfiguration mInterfaceConfiguration;
- /**
- * Internal BroadcastReceiver that SoftApManager uses to listen for tethering
- * events from ConnectivityManager.
- */
- BroadcastReceiver mBroadcastReceiver;
-
SoftApManager mSoftApManager;
/** Sets up test. */
@@ -89,19 +81,12 @@ public class SoftApManagerTest {
when(mConnectivityManager.getTetherableWifiRegexs())
.thenReturn(AVAILABLE_DEVICES);
- mSoftApManager = new SoftApManager(mContext,
- mLooper.getLooper(),
+ mSoftApManager = new SoftApManager(mLooper.getLooper(),
mWifiNative,
mNmService,
- mConnectivityManager,
TEST_COUNTRY_CODE,
mAllowed2GChannels,
mListener);
- ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mContext).registerReceiver(
- broadcastReceiverCaptor.capture(), any(IntentFilter.class));
- mBroadcastReceiver = broadcastReceiverCaptor.getValue();
mLooper.dispatchAll();
}
@@ -119,35 +104,6 @@ public class SoftApManagerTest {
WifiManager.WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
}
- /** Tests the handling of timeout after tethering is started. */
- @Test
- public void tetheringTimedOut() throws Exception {
- startSoftApAndVerifyEnabled();
- announceAvailableForTethering();
- verifyTetheringRequested();
-
- InOrder order = inOrder(mListener);
-
- /* Move the time forward to simulate notification timeout. */
- mLooper.moveTimeForward(5000);
- mLooper.dispatchAll();
-
- /* Verify soft ap is disabled. */
- verify(mNmService).stopAccessPoint(eq(TEST_INTERFACE_NAME));
- order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
- order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
- }
-
- /** Tests the handling of tethered notification after tethering is started. */
- @Test
- public void tetherCompleted() throws Exception {
- startSoftApAndVerifyEnabled();
- announceAvailableForTethering();
- verifyTetheringRequested();
- announceTethered();
- verifySoftApNotDisabled();
- }
-
/** Tests the handling of stop command when soft AP is not started. */
@Test
public void stopWhenNotStarted() throws Exception {
@@ -198,31 +154,4 @@ public class SoftApManagerTest {
verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
}
-
- /** Sends a broadcast intent indicating that the interface is available for tethering. */
- protected void announceAvailableForTethering() throws Exception {
- when(mConnectivityManager.tether(TEST_INTERFACE_NAME))
- .thenReturn(ConnectivityManager.TETHER_ERROR_NO_ERROR);
- ArrayList<String> availableList =
- new ArrayList<String>(Arrays.asList(AVAILABLE_DEVICES));
- TestUtil.sendTetherStateChanged(
- mBroadcastReceiver, mContext, availableList, new ArrayList<String>());
- mLooper.dispatchAll();
- }
-
- /** Verifies that tethering was requested. */
- protected void verifyTetheringRequested() throws Exception {
- verify(mInterfaceConfiguration).setLinkAddress(any(LinkAddress.class));
- verify(mInterfaceConfiguration).setInterfaceUp();
- verify(mNmService).setInterfaceConfig(eq(TEST_INTERFACE_NAME), eq(mInterfaceConfiguration));
- }
-
- /** Sends a broadcast intent indicating that the interface is tethered. */
- protected void announceTethered() throws Exception {
- ArrayList<String> deviceList =
- new ArrayList<String>(Arrays.asList(AVAILABLE_DEVICES));
- TestUtil.sendTetherStateChanged(
- mBroadcastReceiver, mContext, deviceList, deviceList);
- mLooper.dispatchAll();
- }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
index 145c84026..3993fe565 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -19,6 +19,7 @@ package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.content.Context;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Before;
@@ -155,6 +156,7 @@ public class WifiConfigStoreTest {
+ "}\n";
@Mock private WifiNative mWifiNative;
+ @Mock private Context mContext;
private MockKeyStore mMockKeyStore;
private WifiConfigStore mWifiConfigStore;
@@ -163,8 +165,8 @@ public class WifiConfigStoreTest {
MockitoAnnotations.initMocks(this);
mMockKeyStore = new MockKeyStore();
- mWifiConfigStore = new WifiConfigStore(mWifiNative, mMockKeyStore.createMock(), null,
- false, true);
+ mWifiConfigStore = new WifiConfigStore(mContext, mWifiNative, mMockKeyStore.createMock(),
+ null, false, true);
}
/**
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 2434c2db7..281ffa163 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -17,6 +17,7 @@
package com.android.server.wifi;
import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
+import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -32,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;
@@ -45,6 +47,7 @@ import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -69,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());
}
@@ -94,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);
@@ -126,12 +131,23 @@ 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 =
+ ArgumentCaptor.forClass(ScanListener.class);
+
+ 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() {
@@ -144,6 +160,7 @@ public class WifiConnectivityManagerTest {
public void answer(ScanSettings settings, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onResults(scanDatas);
+ allSingleScanListenerCaptor.getValue().onResults(scanDatas);
}}).when(scanner).startScan(anyObject(), anyObject(), anyObject());
// This unfortunately needs to be a somewhat valid scan result, otherwise
@@ -215,6 +232,7 @@ public class WifiConnectivityManagerTest {
WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
when(wifiConfigManager.getWifiConfiguration(anyInt())).thenReturn(null);
+ when(wifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(true);
wifiConfigManager.mThresholdSaturatedRssi24 = new AtomicInteger(
WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND);
wifiConfigManager.mCurrentNetworkBoost = new AtomicInteger(
@@ -321,6 +339,30 @@ public class WifiConnectivityManagerTest {
}
/**
+ * Screen turned on while WiFi in connected state but
+ * auto roaming is disabled.
+ *
+ * Expected behavior: WifiConnectivityManager doesn't invoke
+ * WifiStateMachine.autoConnectToNetwork() because roaming
+ * is turned off.
+ */
+ @Test
+ public void turnScreenOnWhenWifiInConnectedStateRoamingDisabled() {
+ // Set WiFi to connected state
+ mWifiConnectivityManager.handleConnectionStateChanged(
+ WifiConnectivityManager.WIFI_STATE_CONNECTED);
+
+ // Turn off auto roaming
+ when(mWifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(false);
+
+ // Set screen to on
+ mWifiConnectivityManager.handleScreenStateChanged(true);
+
+ verify(mWifiStateMachine, times(0)).autoConnectToNetwork(
+ CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+ }
+
+ /**
* Multiple back to back connection attempts within the rate interval should be rate limited.
*
* Expected behavior: WifiConnectivityManager calls WifiStateMachine.autoConnectToNetwork()
@@ -724,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.
@@ -854,4 +897,99 @@ public class WifiConnectivityManagerTest {
verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
}
+
+ /**
+ * Verify that we retry connectivity scan up to MAX_SCAN_RESTART_ALLOWED times
+ * when Wifi somehow gets into a bad state and fails to scan.
+ *
+ * Expected behavior: WifiConnectivityManager schedules connectivity scan
+ * MAX_SCAN_RESTART_ALLOWED times.
+ */
+ @Test
+ public void checkMaximumScanRetry() {
+ // Set screen to ON
+ mWifiConnectivityManager.handleScreenStateChanged(true);
+
+ doAnswer(new AnswerWithArguments() {
+ public void answer(ScanSettings settings, ScanListener listener,
+ WorkSource workSource) throws Exception {
+ listener.onFailure(-1, "ScanFailure");
+ }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
+
+ // Set WiFi to disconnected state to trigger the single scan based periodic scan
+ mWifiConnectivityManager.handleConnectionStateChanged(
+ WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+
+ // Fire the alarm timer 2x timers
+ for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) {
+ mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG);
+ mLooper.dispatchAll();
+ }
+
+ // Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED
+ // times. Note, WifiScanner.startScan() is invoked MAX_SCAN_RESTART_ALLOWED + 1 times.
+ // The very first scan is the initial one, and the other MAX_SCAN_RESTART_ALLOWED
+ // are the retrial ones.
+ verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 1)).startScan(
+ anyObject(), anyObject(), anyObject());
+ }
+
+ /**
+ * Listen to scan results not requested by WifiConnectivityManager and
+ * act on them.
+ *
+ * Expected behavior: WifiConnectivityManager calls
+ * WifiStateMachine.autoConnectToNetwork() with the
+ * expected candidate network ID and BSSID.
+ */
+ @Test
+ public void listenToAllSingleScanResults() {
+ ScanSettings settings = new ScanSettings();
+ ScanListener scanListener = mock(ScanListener.class);
+
+ // Request a single scan outside of WifiConnectivityManager.
+ mWifiScanner.startScan(settings, scanListener, WIFI_WORK_SOURCE);
+
+ // Verify that WCM receives the scan results and initiates a connection
+ // to the network.
+ 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/WifiControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
index 44a710a05..c187faf27 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
@@ -16,9 +16,13 @@
package com.android.server.wifi;
+import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
+
import static com.android.server.wifi.WifiController.CMD_AP_STOPPED;
+import static com.android.server.wifi.WifiController.CMD_DEVICE_IDLE;
import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
+import static com.android.server.wifi.WifiController.CMD_RESTART_WIFI;
import static com.android.server.wifi.WifiController.CMD_SET_AP;
import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
@@ -28,6 +32,7 @@ import static org.mockito.Mockito.*;
import android.content.ContentResolver;
import android.content.Context;
+import android.os.WorkSource;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -79,7 +84,7 @@ public class WifiControllerTest {
@Mock FrameworkFacade mFacade;
@Mock WifiSettingsStore mSettingsStore;
@Mock WifiStateMachine mWifiStateMachine;
- @Mock WifiServiceImpl.LockList mLockList;
+ @Mock WifiLockManager mWifiLockManager;
WifiController mWifiController;
@@ -94,7 +99,7 @@ public class WifiControllerTest {
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mLockList, mLooper.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
mWifiController.start();
mLooper.dispatchAll();
@@ -265,4 +270,184 @@ public class WifiControllerTest {
inOrder.verify(mWifiStateMachine).setDriverStart(true);
assertEquals("DeviceActiveState", getCurrentState().getName());
}
+
+ /**
+ * When AP mode is enabled and wifi is toggled on, we should transition to
+ * DeviceActiveState after the AP is disabled.
+ * Enter DeviceActiveState, activate AP mode, toggle WiFi.
+ * <p>
+ * Expected: AP should successfully start and exit, then return to DeviceActiveState.
+ */
+ @Test
+ public void testReturnToDeviceActiveStateAfterWifiEnabledShutdown() throws Exception {
+ enableWifi();
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+
+ mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget();
+ mLooper.dispatchAll();
+ assertEquals("ApEnabledState", getCurrentState().getName());
+
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
+ mWifiController.obtainMessage(CMD_WIFI_TOGGLED).sendToTarget();
+ mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget();
+ mLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mWifiStateMachine);
+ inOrder.verify(mWifiStateMachine).setSupplicantRunning(true);
+ inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ inOrder.verify(mWifiStateMachine).setDriverStart(true);
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+ }
+
+ /**
+ * When the wifi device is idle, AP mode is enabled and disabled
+ * we should return to the appropriate Idle state.
+ * Enter DeviceActiveState, indicate idle device, activate AP mode, disable AP mode.
+ * <p>
+ * Expected: AP should successfully start and exit, then return to a device idle state.
+ */
+ @Test
+ public void testReturnToDeviceIdleStateAfterAPModeShutdown() throws Exception {
+ enableWifi();
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+
+ // make sure mDeviceIdle is set to true
+ when(mWifiLockManager.getStrongestLockMode()).thenReturn(WIFI_MODE_FULL);
+ when(mWifiLockManager.createMergedWorkSource()).thenReturn(new WorkSource());
+ mWifiController.sendMessage(CMD_DEVICE_IDLE);
+ mLooper.dispatchAll();
+ assertEquals("FullLockHeldState", getCurrentState().getName());
+
+ mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget();
+ mLooper.dispatchAll();
+ assertEquals("ApEnabledState", getCurrentState().getName());
+
+ when(mSettingsStore.getWifiSavedState()).thenReturn(1);
+ mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget();
+ mLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mWifiStateMachine);
+ inOrder.verify(mWifiStateMachine).setSupplicantRunning(true);
+ inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ inOrder.verify(mWifiStateMachine).setDriverStart(true);
+ assertEquals("FullLockHeldState", getCurrentState().getName());
+ }
+
+ /**
+ * The command to trigger a WiFi reset should not trigger any action by WifiController if we
+ * are not in STA mode.
+ * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures
+ * should be ignored.
+ * Create and start WifiController in ApStaDisabledState, send command to restart WiFi
+ * <p>
+ * Expected: WiFiController should not call WifiStateMachine.setSupplicantRunning(false)
+ */
+ @Test
+ public void testRestartWifiStackInApStaDisabledState() throws Exception {
+ // Start a new WifiController with wifi disabled
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
+
+ when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+
+ mWifiController = new WifiController(mContext, mWifiStateMachine,
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
+
+ mWifiController.start();
+ mLooper.dispatchAll();
+
+ reset(mWifiStateMachine);
+ assertEquals("ApStaDisabledState", getCurrentState().getName());
+ mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mLooper.dispatchAll();
+ verifyZeroInteractions(mWifiStateMachine);
+ }
+
+ /**
+ * The command to trigger a WiFi reset should not trigger any action by WifiController if we
+ * are not in STA mode, even if scans are allowed.
+ * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures
+ * should be ignored.
+ * Create and start WifiController in StaDisablediWithScanState, send command to restart WiFi
+ * <p>
+ * Expected: WiFiController should not call WifiStateMachine.setSupplicantRunning(false)
+ */
+ @Test
+ public void testRestartWifiStackInStaDisabledWithScanState() throws Exception {
+ reset(mWifiStateMachine);
+ assertEquals("StaDisabledWithScanState", getCurrentState().getName());
+ mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mLooper.dispatchAll();
+ verifyZeroInteractions(mWifiStateMachine);
+ }
+
+ /**
+ * The command to trigger a WiFi reset should trigger a wifi reset in WifiStateMachine through
+ * the WifiStateMachine.setSupplicantRunning(false) call when in STA mode.
+ * WiFi is in connect mode, calls to reset the wifi stack due to connection failures
+ * should trigger a supplicant stop, and subsequently, a driver reload.
+ * Create and start WifiController in DeviceActiveState, send command to restart WiFi
+ * <p>
+ * Expected: WiFiController should call WifiStateMachine.setSupplicantRunning(false),
+ * WifiStateMachine should enter CONNECT_MODE and the wifi driver should be started.
+ */
+ @Test
+ public void testRestartWifiStackInStaEnabledState() throws Exception {
+ enableWifi();
+
+ reset(mWifiStateMachine);
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+ mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mLooper.dispatchAll();
+ InOrder inOrder = inOrder(mWifiStateMachine);
+ inOrder.verify(mWifiStateMachine).setSupplicantRunning(false);
+ inOrder.verify(mWifiStateMachine).setSupplicantRunning(true);
+ inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ inOrder.verify(mWifiStateMachine).setDriverStart(true);
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+ }
+
+ /**
+ * The command to trigger a WiFi reset should not trigger a reset when in ECM mode.
+ * Enable wifi and enter ECM state, send command to restart wifi.
+ * <p>
+ * Expected: The command to trigger a wifi reset should be ignored and we should remain in ECM
+ * mode.
+ */
+ @Test
+ public void testRestartWifiStackDoesNotExitECMMode() throws Exception {
+ enableWifi();
+ assertEquals("DeviceActiveState", getCurrentState().getName());
+ when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
+
+ mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
+ mLooper.dispatchAll();
+ assertInEcm(true);
+
+ reset(mWifiStateMachine);
+ mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mLooper.dispatchAll();
+ assertInEcm(true);
+ verifyZeroInteractions(mWifiStateMachine);
+ }
+
+ /**
+ * The command to trigger a WiFi reset should not trigger a reset when in AP mode.
+ * Enter AP mode, send command to restart wifi.
+ * <p>
+ * Expected: The command to trigger a wifi reset should be ignored and we should remain in AP
+ * mode.
+ */
+ @Test
+ public void testRestartWifiStackDoesNotExitAPMode() throws Exception {
+ mWifiController.obtainMessage(CMD_SET_AP, 1).sendToTarget();
+ mLooper.dispatchAll();
+ assertEquals("ApEnabledState", getCurrentState().getName());
+
+ reset(mWifiStateMachine);
+ mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mLooper.dispatchAll();
+ verifyZeroInteractions(mWifiStateMachine);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
index 2e62a309b..faa2f71f8 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
@@ -71,7 +71,7 @@ public class WifiCountryCodeTest {
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
verify(mWifiNative).setCountryCode(anyString());
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -81,13 +81,13 @@ public class WifiCountryCodeTest {
@Test
public void useTelephonyCountryCode() throws Exception {
mWifiCountryCode.setCountryCode(mTelephonyCountryCode, false);
- assertEquals(null, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(null, mWifiCountryCode.getCountryCodeSentToDriver());
// Supplicant started.
mWifiCountryCode.setReadyForChange(true);
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
verify(mWifiNative).setCountryCode(anyString());
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -98,13 +98,13 @@ public class WifiCountryCodeTest {
public void setTelephonyCountryCodeAfterSupplicantStarts() throws Exception {
// Supplicant starts.
mWifiCountryCode.setReadyForChange(true);
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
// Telephony country code arrives.
mWifiCountryCode.setCountryCode(mTelephonyCountryCode, false);
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
verify(mWifiNative, times(2)).setCountryCode(anyString());
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -120,11 +120,11 @@ public class WifiCountryCodeTest {
// Telephony country code arrives.
mWifiCountryCode.setCountryCode(mTelephonyCountryCode, false);
// Telephony coutry code won't be applied at this time.
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
mWifiCountryCode.setReadyForChange(true);
// Telephony coutry is applied after supplicant is ready.
verify(mWifiNative, times(2)).setCountryCode(anyString());
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -138,15 +138,15 @@ public class WifiCountryCodeTest {
mWifiCountryCode.setReadyForChange(true);
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
// SIM card is removed.
mWifiCountryCode.simCardRemoved();
// Country code restting is not applied yet.
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
mWifiCountryCode.setReadyForChange(true);
// Country code restting is applied when supplicant is ready.
verify(mWifiNative, times(2)).setCountryCode(anyString());
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -160,15 +160,15 @@ public class WifiCountryCodeTest {
mWifiCountryCode.setReadyForChange(true);
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
// Airplane mode is enabled.
mWifiCountryCode.simCardRemoved();
// Country code restting is not applied yet.
- assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
mWifiCountryCode.setReadyForChange(true);
// Country code restting is applied when supplicant is ready.
verify(mWifiNative, times(2)).setCountryCode(anyString());
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
/**
@@ -188,6 +188,6 @@ public class WifiCountryCodeTest {
// Wifi get L2 connected.
mWifiCountryCode.setReadyForChange(false);
verify(mWifiNative).setCountryCode(anyString());
- assertEquals(persistentCountryCode, mWifiCountryCode.getCurrentCountryCode());
+ assertEquals(persistentCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java
index 64f1ce0fd..08163e7f2 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java
@@ -19,6 +19,7 @@ package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
+import static org.mockito.MockitoAnnotations.*;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiSsid;
@@ -27,6 +28,7 @@ import android.util.Pair;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,7 +40,8 @@ import java.util.List;
@SmallTest
public class WifiLastResortWatchdogTest {
WifiLastResortWatchdog mLastResortWatchdog;
- WifiMetrics mWifiMetrics;
+ @Mock WifiMetrics mWifiMetrics;
+ @Mock WifiController mWifiController;
private String[] mSsids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
private String[] mBssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
"c0:ff:ee:ee:e3:ee"};
@@ -51,8 +54,9 @@ public class WifiLastResortWatchdogTest {
@Before
public void setUp() throws Exception {
- mWifiMetrics = mock(WifiMetrics.class);
+ initMocks(this);
mLastResortWatchdog = new WifiLastResortWatchdog(mWifiMetrics);
+ mLastResortWatchdog.setWifiController(mWifiController);
}
private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids,
@@ -1276,6 +1280,8 @@ public class WifiLastResortWatchdogTest {
ssids[ssids.length - 1], bssids[ssids.length - 1],
WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
assertEquals(true, watchdogTriggered);
+ verify(mWifiController).sendMessage(WifiController.CMD_RESTART_WIFI);
+ reset(mWifiController);
}
/**
@@ -1434,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);
@@ -1444,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);
@@ -1472,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/WifiLockManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
new file mode 100644
index 000000000..1bbdda981
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.WorkSource;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/** Unit tests for {@link WifiLockManager}. */
+@SmallTest
+public class WifiLockManagerTest {
+
+ private static final int DEFAULT_TEST_UID_1 = 35;
+ private static final int DEFAULT_TEST_UID_2 = 53;
+ private static final int WIFI_LOCK_MODE_INVALID = -1;
+ private static final String TEST_WIFI_LOCK_TAG = "TestTag";
+
+ WifiLockManager mWifiLockManager;
+ @Mock IBatteryStats mBatteryStats;
+ @Mock IBinder mBinder;
+ WorkSource mWorkSource;
+ @Mock Context mContext;
+
+ /**
+ * Method to setup a WifiLockManager for the tests.
+ * The WifiLockManager uses mocks for BatteryStats and Context.
+ */
+ @Before
+ public void setUp() {
+ mWorkSource = new WorkSource(DEFAULT_TEST_UID_1);
+ MockitoAnnotations.initMocks(this);
+ mWifiLockManager = new WifiLockManager(mContext, mBatteryStats);
+ }
+
+ private void acquireWifiLockSuccessful(int lockMode, String tag, IBinder binder, WorkSource ws)
+ throws Exception {
+ ArgumentCaptor<IBinder.DeathRecipient> deathRecipient =
+ ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+
+ assertTrue(mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws));
+ assertThat(mWifiLockManager.getStrongestLockMode(),
+ not(WifiManager.WIFI_MODE_NO_LOCKS_HELD));
+ InOrder inOrder = inOrder(binder, mBatteryStats);
+ inOrder.verify(binder).linkToDeath(deathRecipient.capture(), eq(0));
+ inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(ws);
+ }
+
+ private void releaseWifiLockSuccessful(IBinder binder) throws Exception {
+ ArgumentCaptor<IBinder.DeathRecipient> deathRecipient =
+ ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+
+ assertTrue(mWifiLockManager.releaseWifiLock(binder));
+ InOrder inOrder = inOrder(binder, mBatteryStats);
+ inOrder.verify(binder).unlinkToDeath(deathRecipient.capture(), eq(0));
+ inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(any(WorkSource.class));
+ }
+
+ /**
+ * Test to check that a new WifiLockManager should not be holding any locks.
+ */
+ @Test
+ public void newWifiLockManagerShouldNotHaveAnyLocks() {
+ assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD, mWifiLockManager.getStrongestLockMode());
+ }
+
+ /**
+ * Test to verify that the lock mode is verified before adding a lock.
+ *
+ * Steps: call acquireWifiLock with an invalid lock mode.
+ * Expected: the call should throw an IllegalArgumentException.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void acquireWifiLockShouldThrowExceptionOnInivalidLockMode() throws Exception {
+ mWifiLockManager.acquireWifiLock(WIFI_LOCK_MODE_INVALID, "", mBinder, mWorkSource);
+ }
+
+ /**
+ * Test that a call to acquireWifiLock with valid parameters works.
+ *
+ * Steps: call acquireWifiLock on the empty WifiLockManager.
+ * Expected: A subsequent call to getStrongestLockMode should reflect the type of the lock we
+ * just added
+ */
+ @Test
+ public void acquireWifiLockWithValidParamsShouldSucceed() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "", mBinder, mWorkSource);
+ assertEquals(WifiManager.WIFI_MODE_FULL, mWifiLockManager.getStrongestLockMode());
+ }
+
+ /**
+ * Test that a call to acquireWifiLock will not succeed if there is already a lock for the same
+ * binder instance.
+ *
+ * Steps: call acquireWifiLock twice
+ * Expected: Second call should return false
+ */
+ @Test
+ public void secondCallToAcquireWifiLockWithSameBinderShouldFail() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "", mBinder, mWorkSource);
+ assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY, mWifiLockManager.getStrongestLockMode());
+ assertFalse(mWifiLockManager.acquireWifiLock(
+ WifiManager.WIFI_MODE_SCAN_ONLY, "", mBinder, mWorkSource));
+ }
+
+ /**
+ * After acquiring a lock, we should be able to remove it.
+ *
+ * Steps: acquire a WifiLock and then remove it.
+ * Expected: Since a single lock was added, removing it should leave the WifiLockManager without
+ * any locks. We should not see any errors.
+ */
+ @Test
+ public void releaseWifiLockShouldSucceed() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "", mBinder, mWorkSource);
+ releaseWifiLockSuccessful(mBinder);
+ assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD, mWifiLockManager.getStrongestLockMode());
+ }
+
+ /**
+ * Releasing locks for one caller should not release locks for a different caller.
+ *
+ * Steps: acquire locks for two callers and remove locks for one.
+ * Expected: locks for remaining caller should still be active.
+ */
+ @Test
+ public void releaseLocksForOneCallerNotImpactOtherCallers() throws Exception {
+ IBinder toReleaseBinder = mock(IBinder.class);
+ WorkSource toReleaseWS = new WorkSource(DEFAULT_TEST_UID_1);
+ WorkSource toKeepWS = new WorkSource(DEFAULT_TEST_UID_2);
+
+ acquireWifiLockSuccessful(
+ WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", toReleaseBinder, toReleaseWS);
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "", mBinder, toKeepWS);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_FULL_HIGH_PERF);
+ releaseWifiLockSuccessful(toReleaseBinder);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_SCAN_ONLY);
+ releaseWifiLockSuccessful(mBinder);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_NO_LOCKS_HELD);
+ }
+
+ /**
+ * Attempting to release a lock that we do not hold should return false.
+ *
+ * Steps: release a WifiLock
+ * Expected: call to releaseWifiLock should return false.
+ */
+ @Test
+ public void releaseWifiLockWithoutAcquireWillReturnFalse() {
+ assertFalse(mWifiLockManager.releaseWifiLock(mBinder));
+ }
+
+ /**
+ * Test used to verify call for getStrongestLockMode.
+ *
+ * Steps: The test first checks the return value for no held locks and then proceeds to test
+ * with a single lock of each type.
+ * Expected: getStrongestLockMode should reflect the type of lock we just added.
+ */
+ @Test
+ public void checkForProperValueForGetStrongestLockMode() throws Exception {
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_NO_LOCKS_HELD);
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_FULL_HIGH_PERF);
+ releaseWifiLockSuccessful(mBinder);
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "", mBinder, mWorkSource);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_FULL);
+ releaseWifiLockSuccessful(mBinder);
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "", mBinder, mWorkSource);
+ assertEquals(mWifiLockManager.getStrongestLockMode(), WifiManager.WIFI_MODE_SCAN_ONLY);
+ }
+
+ /**
+ * We should be able to create a merged WorkSource holding WorkSources for all active locks.
+ *
+ * Steps: call createMergedWorkSource and verify it is empty, add a lock and call again, it
+ * should have one entry.
+ * Expected: the first call should return a worksource with size 0 and the second should be size
+ * 1.
+ */
+ @Test
+ public void createMergedWorkSourceShouldSucceed() throws Exception {
+ WorkSource checkMWS = mWifiLockManager.createMergedWorkSource();
+ assertEquals(checkMWS.size(), 0);
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+ checkMWS = mWifiLockManager.createMergedWorkSource();
+ assertEquals(checkMWS.size(), 1);
+ }
+
+ /**
+ * Test the ability to update a WifiLock WorkSource with a new WorkSource.
+ *
+ * Steps: acquire a WifiLock with the default test worksource, then attempt to update it.
+ * Expected: Verify calls to release the original WorkSource and acquire with the new one to
+ * BatteryStats.
+ */
+ @Test
+ public void testUpdateWifiLockWorkSourceCalledWithWorkSource() throws Exception {
+ WorkSource newWorkSource = new WorkSource(DEFAULT_TEST_UID_2);
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+
+ mWifiLockManager.updateWifiLockWorkSource(mBinder, newWorkSource);
+ InOrder inOrder = inOrder(mBatteryStats);
+ inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
+ inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(newWorkSource));
+ }
+
+ /**
+ * Test the ability to update a WifiLock WorkSource with the callers UID.
+ *
+ * Steps: acquire a WifiLock with the default test worksource, then attempt to update it.
+ * Expected: Verify calls to release the original WorkSource and acquire with the new one to
+ * BatteryStats.
+ */
+ @Test
+ public void testUpdateWifiLockWorkSourceCalledWithUID() throws Exception {
+ WorkSource newWorkSource = new WorkSource(Binder.getCallingUid());
+
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+
+ mWifiLockManager.updateWifiLockWorkSource(mBinder, null);
+ InOrder inOrder = inOrder(mBatteryStats);
+ inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
+ inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(newWorkSource));
+ }
+
+ /**
+ * Test an attempt to update a WifiLock that is not active.
+ *
+ * Steps: call updateWifiLockWorkSource
+ * Expected: catch an IllegalArgumentException
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdateWifiLockWorkSourceCalledWithoutActiveLock() throws Exception {
+ mWifiLockManager.updateWifiLockWorkSource(mBinder, null);
+ }
+
+ /**
+ * Verfies that dump() does not fail when no locks are held.
+ */
+ @Test
+ public void dumpDoesNotFailWhenNoLocksAreHeld() {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ mWifiLockManager.dump(pw);
+
+ String wifiLockManagerDumpString = sw.toString();
+ assertTrue(wifiLockManagerDumpString.contains(
+ "Locks acquired: 0 full, 0 full high perf, 0 scan"));
+ assertTrue(wifiLockManagerDumpString.contains(
+ "Locks released: 0 full, 0 full high perf, 0 scan"));
+ assertTrue(wifiLockManagerDumpString.contains("Locks held:"));
+ assertFalse(wifiLockManagerDumpString.contains("WifiLock{"));
+ }
+
+ /**
+ * Verifies that dump() contains lock information when there are locks held.
+ */
+ @Test
+ public void dumpOutputsCorrectInformationWithActiveLocks() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+ releaseWifiLockSuccessful(mBinder);
+
+ acquireWifiLockSuccessful(
+ WifiManager.WIFI_MODE_FULL, TEST_WIFI_LOCK_TAG, mBinder, mWorkSource);
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ mWifiLockManager.dump(pw);
+
+ String wifiLockManagerDumpString = sw.toString();
+ assertTrue(wifiLockManagerDumpString.contains(
+ "Locks acquired: 1 full, 1 full high perf, 0 scan"));
+ assertTrue(wifiLockManagerDumpString.contains(
+ "Locks released: 0 full, 1 full high perf, 0 scan"));
+ assertTrue(wifiLockManagerDumpString.contains("Locks held:"));
+ assertTrue(wifiLockManagerDumpString.contains(
+ "WifiLock{" + TEST_WIFI_LOCK_TAG + " type=" + WifiManager.WIFI_MODE_FULL
+ + " uid=" + Binder.getCallingUid() + "}"));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLoggerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLoggerTest.java
index 55dc683c7..d915ff368 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiLoggerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLoggerTest.java
@@ -16,7 +16,10 @@
package com.android.server.wifi;
+import android.content.Context;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.R;
+import android.util.LocalLog;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -52,11 +55,16 @@ public class WifiLoggerTest {
@Mock WifiStateMachine mWsm;
@Mock WifiNative mWifiNative;
@Mock BuildProperties mBuildProperties;
+ @Mock Context mContext;
WifiLogger mWifiLogger;
private static final String FAKE_RING_BUFFER_NAME = "fake-ring-buffer";
- private WifiNative.RingBufferStatus mFakeRbs;
+ private static final int SMALL_RING_BUFFER_SIZE_KB = 32;
+ private static final int LARGE_RING_BUFFER_SIZE_KB = 1024;
+ private static final int BYTES_PER_KBYTE = 1024;
+ private LocalLog mWifiNativeLocalLog;
+ private WifiNative.RingBufferStatus mFakeRbs;
/**
* Returns the data that we would dump in a bug report, for our ring buffer.
* @return a 2-D byte array, where the first dimension is the record number, and the second
@@ -72,20 +80,29 @@ public class WifiLoggerTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
mFakeRbs = new WifiNative.RingBufferStatus();
mFakeRbs.name = FAKE_RING_BUFFER_NAME;
-
WifiNative.RingBufferStatus[] ringBufferStatuses = new WifiNative.RingBufferStatus[] {
mFakeRbs
};
+ mWifiNativeLocalLog = new LocalLog(8192);
when(mWifiNative.getRingBufferStatus()).thenReturn(ringBufferStatuses);
when(mWifiNative.readKernelLog()).thenReturn("");
+ when(mWifiNative.getLocalLog()).thenReturn(mWifiNativeLocalLog);
when(mBuildProperties.isEngBuild()).thenReturn(false);
when(mBuildProperties.isUserdebugBuild()).thenReturn(false);
when(mBuildProperties.isUserBuild()).thenReturn(true);
- mWifiLogger = new WifiLogger(mWsm, mWifiNative, mBuildProperties);
+ MockResources resources = new MockResources();
+ resources.setInteger(R.integer.config_wifi_logger_ring_buffer_default_size_limit_kb,
+ SMALL_RING_BUFFER_SIZE_KB);
+ resources.setInteger(R.integer.config_wifi_logger_ring_buffer_verbose_size_limit_kb,
+ LARGE_RING_BUFFER_SIZE_KB);
+ when(mContext.getResources()).thenReturn(resources);
+
+ mWifiLogger = new WifiLogger(mContext, mWsm, mWifiNative, mBuildProperties);
mWifiNative.enableVerboseLogging(0);
}
@@ -197,7 +214,7 @@ public class WifiLoggerTest {
final boolean verbosityToggle = false;
mWifiLogger.startLogging(verbosityToggle);
- final byte[] data = new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL];
+ final byte[] data = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE];
mWifiLogger.onRingBufferData(mFakeRbs, data);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
@@ -214,7 +231,7 @@ public class WifiLoggerTest {
final boolean verbosityToggle = false;
mWifiLogger.startLogging(verbosityToggle);
- final byte[] data1 = new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL];
+ final byte[] data1 = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE];
final byte[] data2 = {1, 2, 3};
mWifiLogger.onRingBufferData(mFakeRbs, data1);
mWifiLogger.onRingBufferData(mFakeRbs, data2);
@@ -526,7 +543,7 @@ public class WifiLoggerTest {
final boolean verbosityToggle = false;
mWifiLogger.startLogging(verbosityToggle);
mWifiLogger.onRingBufferData(
- mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL + 1]);
+ mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(0, getLoggerRingBufferData().length);
}
@@ -540,7 +557,7 @@ public class WifiLoggerTest {
when(mBuildProperties.isUserBuild()).thenReturn(false);
mWifiLogger.startLogging(verbosityToggle);
mWifiLogger.onRingBufferData(
- mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL + 1]);
+ mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(0, getLoggerRingBufferData().length);
}
@@ -554,7 +571,7 @@ public class WifiLoggerTest {
when(mBuildProperties.isUserBuild()).thenReturn(false);
mWifiLogger.startLogging(verbosityToggle);
mWifiLogger.onRingBufferData(
- mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL + 1]);
+ mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(0, getLoggerRingBufferData().length);
}
@@ -564,7 +581,8 @@ public class WifiLoggerTest {
public void ringBufferSizeIsLargeInVerboseMode() throws Exception {
final boolean verbosityToggle = true;
mWifiLogger.startLogging(verbosityToggle);
- mWifiLogger.onRingBufferData(mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_LARGE]);
+ mWifiLogger.onRingBufferData(
+ mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(1, getLoggerRingBufferData().length);
}
@@ -574,7 +592,8 @@ public class WifiLoggerTest {
public void startLoggingGrowsRingBuffersIfNeeded() throws Exception {
mWifiLogger.startLogging(false /* verbose disabled */);
mWifiLogger.startLogging(true /* verbose enabled */);
- mWifiLogger.onRingBufferData(mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_LARGE]);
+ mWifiLogger.onRingBufferData(
+ mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(1, getLoggerRingBufferData().length);
}
@@ -584,7 +603,7 @@ public class WifiLoggerTest {
public void startLoggingShrinksRingBuffersIfNeeded() throws Exception {
mWifiLogger.startLogging(true /* verbose enabled */);
mWifiLogger.onRingBufferData(
- mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL + 1]);
+ mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]);
// Existing data is nuked (too large).
mWifiLogger.startLogging(false /* verbose disabled */);
@@ -593,7 +612,7 @@ public class WifiLoggerTest {
// New data must obey limit as well.
mWifiLogger.onRingBufferData(
- mFakeRbs, new byte[WifiLogger.RING_BUFFER_BYTE_LIMIT_SMALL + 1]);
+ mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_NONE);
assertEquals(0, getLoggerRingBufferData().length);
}
@@ -704,4 +723,17 @@ public class WifiLoggerTest {
mWifiLogger.dump(new FileDescriptor(), pw, new String[]{});
assertFalse(sw.toString().contains(WifiLogger.FIRMWARE_DUMP_SECTION_HEADER));
}
+
+ /** Verifies that the dump() includes contents of WifiNative's LocalLog. */
+ @Test
+ public void dumpIncludesContentOfWifiNativeLocalLog() {
+ final String wifiNativeLogMessage = "This is a message";
+ mWifiNativeLocalLog.log(wifiNativeLogMessage);
+
+ mWifiLogger.startLogging(false /* verbose disabled */);
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ mWifiLogger.dump(new FileDescriptor(), pw, new String[]{});
+ assertTrue(sw.toString().contains(wifiNativeLogMessage));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 530b2180b..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,6 +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
*/
@@ -162,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);
@@ -236,6 +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(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);
+ }
}
/**
@@ -254,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);
@@ -311,8 +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(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);
}
/**
@@ -450,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",
@@ -468,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 64fee84fc..1726e7d32 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
@@ -2233,4 +2233,96 @@ public class WifiQualifiedNetworkSelectorTest {
assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
.BestCandidateType.NONE, evaluator.getBestCandidateType());
}
+
+ /**
+ * Case #46 Choose 2.4GHz BSSID with stronger RSSI value over
+ * 5GHz BSSID with weaker RSSI value
+ *
+ * In this test. we simulate following scenario:
+ * Two APs are found in scan results
+ * BSSID1 is @ 5GHz with RSSI -82
+ * BSSID2 is @ 2Ghz with RSSI -72
+ * These two BSSIDs get exactly the same QNS score
+ *
+ * expect BSSID2 to be chosen as it has stronger RSSI value
+ */
+ @Test
+ public void chooseStrongerRssiOver5GHz() {
+ String[] ssids = {"\"test1\"", "\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] frequencies = {5220, 2437};
+ String[] caps = {"[ESS]", "[ESS]"};
+ int[] levels = {-82, -72};
+ 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);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ false, scanDetails, false, false, true, false);
+
+ 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 e0f94ad17..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()));
@@ -475,6 +485,75 @@ public class WifiStateMachineTest {
assertEquals("InitialState", getCurrentState().getName());
}
+ /**
+ * Test to check that mode changes from WifiController will be properly handled in the
+ * InitialState by WifiStateMachine.
+ */
+ @Test
+ public void checkOperationalModeInInitialState() throws Exception {
+ when(mWifiNative.loadDriver()).thenReturn(true);
+ when(mWifiNative.startHal()).thenReturn(true);
+ when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(true);
+
+ mLooper.dispatchAll();
+ assertEquals("InitialState", getCurrentState().getName());
+ assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
+
+ mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
+ mLooper.dispatchAll();
+ assertEquals(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE,
+ mWsm.getOperationalModeForTest());
+
+ mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
+ mLooper.dispatchAll();
+ assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
+
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
+ }
+
+ /**
+ * Test that mode changes for WifiStateMachine in the InitialState are realized when supplicant
+ * is started.
+ */
+ @Test
+ public void checkStartInCorrectStateAfterChangingInitialState() throws Exception {
+ when(mWifiNative.loadDriver()).thenReturn(true);
+ when(mWifiNative.startHal()).thenReturn(true);
+ when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(true);
+
+ // Check initial state
+ mLooper.dispatchAll();
+ assertEquals("InitialState", getCurrentState().getName());
+ assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
+
+ // Update the mode
+ mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
+ mLooper.dispatchAll();
+ assertEquals(WifiStateMachine.SCAN_ONLY_MODE, mWsm.getOperationalModeForTest());
+
+ // Start supplicant so we move to the next state
+ mWsm.setSupplicantRunning(true);
+ mLooper.dispatchAll();
+ assertEquals("SupplicantStartingState", getCurrentState().getName());
+ when(mWifiNative.setBand(anyInt())).thenReturn(true);
+ when(mWifiNative.setDeviceName(anyString())).thenReturn(true);
+ when(mWifiNative.setManufacturer(anyString())).thenReturn(true);
+ when(mWifiNative.setModelName(anyString())).thenReturn(true);
+ when(mWifiNative.setModelNumber(anyString())).thenReturn(true);
+ when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
+ when(mWifiNative.setConfigMethods(anyString())).thenReturn(true);
+ when(mWifiNative.setDeviceType(anyString())).thenReturn(true);
+ when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
+ when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true);
+
+ mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
+ mLooper.dispatchAll();
+
+ assertEquals("ScanModeState", getCurrentState().getName());
+ }
+
private void addNetworkAndVerifySuccess() throws Exception {
addNetworkAndVerifySuccess(false);
}
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 62f510526..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");
@@ -39,6 +39,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.server.wifi.BidirectionalAsyncChannel;
import com.android.server.wifi.Clock;
@@ -137,13 +138,13 @@ public class WifiScanningServiceTest {
return controlChannel;
}
- private Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler) {
+ private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler) {
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
order.verify(handler).handleMessage(messageCaptor.capture());
return messageCaptor.getValue();
}
- private Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler,
+ private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler,
final int what) {
CapturingMatcher<Message> messageMatcher = new CapturingMatcher<Message>() {
public boolean matches(Object argument) {
@@ -155,14 +156,14 @@ public class WifiScanningServiceTest {
return messageMatcher.getLastValue();
}
- private void verifyScanResultsRecieved(InOrder order, Handler handler, int listenerId,
+ private static void verifyScanResultsRecieved(InOrder order, Handler handler, int listenerId,
WifiScanner.ScanData... expected) {
Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler,
WifiScanner.CMD_SCAN_RESULT);
assertScanResultsMessage(listenerId, expected, scanResultMessage);
}
- private void assertScanResultsMessage(int listenerId, WifiScanner.ScanData[] expected,
+ private static void assertScanResultsMessage(int listenerId, WifiScanner.ScanData[] expected,
Message scanResultMessage) {
assertEquals("what", WifiScanner.CMD_SCAN_RESULT, scanResultMessage.what);
assertEquals("listenerId", listenerId, scanResultMessage.arg2);
@@ -170,18 +171,19 @@ public class WifiScanningServiceTest {
((WifiScanner.ParcelableScanData) scanResultMessage.obj).getResults());
}
- private void verifySingleScanCompletedRecieved(InOrder order, Handler handler, int listenerId) {
+ private static void verifySingleScanCompletedRecieved(InOrder order, Handler handler,
+ int listenerId) {
Message completedMessage = verifyHandleMessageAndGetMessage(order, handler,
WifiScanner.CMD_SINGLE_SCAN_COMPLETED);
assertSingleScanCompletedMessage(listenerId, completedMessage);
}
- private void assertSingleScanCompletedMessage(int listenerId, Message completedMessage) {
+ private static void assertSingleScanCompletedMessage(int listenerId, Message completedMessage) {
assertEquals("what", WifiScanner.CMD_SINGLE_SCAN_COMPLETED, completedMessage.what);
assertEquals("listenerId", listenerId, completedMessage.arg2);
}
- private void sendBackgroundScanRequest(BidirectionalAsyncChannel controlChannel,
+ private static void sendBackgroundScanRequest(BidirectionalAsyncChannel controlChannel,
int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) {
Bundle scanParams = new Bundle();
scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
@@ -190,7 +192,7 @@ public class WifiScanningServiceTest {
scanRequestId, scanParams));
}
- private void sendSingleScanRequest(BidirectionalAsyncChannel controlChannel,
+ private static void sendSingleScanRequest(BidirectionalAsyncChannel controlChannel,
int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) {
Bundle scanParams = new Bundle();
scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
@@ -199,12 +201,24 @@ public class WifiScanningServiceTest {
scanRequestId, scanParams));
}
- private void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) {
+ private static void registerScanListener(BidirectionalAsyncChannel controlChannel,
+ int listenerRequestId) {
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_REGISTER_SCAN_LISTENER, 0,
+ listenerRequestId, null));
+ }
+
+ private static void deregisterScanListener(BidirectionalAsyncChannel controlChannel,
+ int listenerRequestId) {
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DEREGISTER_SCAN_LISTENER, 0,
+ listenerRequestId, null));
+ }
+
+ private static void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) {
Message response = verifyHandleMessageAndGetMessage(order, handler);
assertSuccessfulResponse(arg2, response);
}
- private void assertSuccessfulResponse(int arg2, Message response) {
+ private static void assertSuccessfulResponse(int arg2, Message response) {
if (response.what == WifiScanner.CMD_OP_FAILED) {
WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj;
fail("response indicates failure, reason=" + result.reason
@@ -215,13 +229,65 @@ public class WifiScanningServiceTest {
}
}
- private void verifyFailedResponse(InOrder order, Handler handler, int arg2,
+ /**
+ * If multiple results are expected for a single hardware scan then the order that they are
+ * dispatched is dependant on the order which they are iterated through internally. This
+ * function validates that the order is either one way or the other. A scan listener can
+ * optionally be provided as well and will be checked after the after the single scan requests.
+ */
+ private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
+ int requestId1, ScanResults results1, int requestId2, ScanResults results2,
+ int listenerRequestId, ScanResults listenerResults) {
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ handlerOrder.verify(handler, times(listenerResults == null ? 4 : 5))
+ .handleMessage(messageCaptor.capture());
+ int firstListenerId = messageCaptor.getAllValues().get(0).arg2;
+ assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId1,
+ firstListenerId == requestId2 || firstListenerId == requestId1);
+ if (firstListenerId == requestId2) {
+ assertScanResultsMessage(requestId2,
+ new WifiScanner.ScanData[] {results2.getScanData()},
+ messageCaptor.getAllValues().get(0));
+ assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(1));
+ assertScanResultsMessage(requestId1,
+ new WifiScanner.ScanData[] {results1.getScanData()},
+ messageCaptor.getAllValues().get(2));
+ assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(3));
+ if (listenerResults != null) {
+ assertScanResultsMessage(listenerRequestId,
+ new WifiScanner.ScanData[] {listenerResults.getScanData()},
+ messageCaptor.getAllValues().get(4));
+ }
+ } else {
+ assertScanResultsMessage(requestId1,
+ new WifiScanner.ScanData[] {results1.getScanData()},
+ messageCaptor.getAllValues().get(0));
+ assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(1));
+ assertScanResultsMessage(requestId2,
+ new WifiScanner.ScanData[] {results2.getScanData()},
+ messageCaptor.getAllValues().get(2));
+ assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3));
+ if (listenerResults != null) {
+ assertScanResultsMessage(listenerRequestId,
+ new WifiScanner.ScanData[] {listenerResults.getScanData()},
+ messageCaptor.getAllValues().get(4));
+ }
+ }
+ }
+
+ private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
+ int requestId1, ScanResults results1, int requestId2, ScanResults results2) {
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2,
+ results2, -1, null);
+ }
+
+ private static void verifyFailedResponse(InOrder order, Handler handler, int arg2,
int expectedErrorReason, String expectedErrorDescription) {
Message response = verifyHandleMessageAndGetMessage(order, handler);
assertFailedResponse(arg2, expectedErrorReason, expectedErrorDescription, response);
}
- private void assertFailedResponse(int arg2, int expectedErrorReason,
+ private static void assertFailedResponse(int arg2, int expectedErrorReason,
String expectedErrorDescription, Message response) {
if (response.what == WifiScanner.CMD_OP_SUCCEEDED) {
fail("response indicates success");
@@ -299,22 +365,24 @@ public class WifiScanningServiceTest {
private void assertDumpContainsRequestLog(String type, int id) {
String serviceDump = dumpService();
- Pattern logLineRegex = Pattern.compile("^.+" + type + ": ClientInfo\\[uid=\\d+\\],Id=" +
- id + ".*$", Pattern.MULTILINE);
+ Pattern logLineRegex = Pattern.compile("^.+" + type
+ + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id
+ + ".*$", Pattern.MULTILINE);
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();
String extraPattern = extra == null ? "" : "," + extra;
- Pattern logLineRegex = Pattern.compile("^.+" + callback + ": ClientInfo\\[uid=\\d+\\],Id=" +
- id + extraPattern + "$", Pattern.MULTILINE);
+ Pattern logLineRegex = Pattern.compile("^.+" + callback
+ + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id
+ + extraPattern + "$", Pattern.MULTILINE);
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 {
@@ -439,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));
}
/**
@@ -450,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
@@ -561,9 +641,95 @@ public class WifiScanningServiceTest {
verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource));
}
- // TODO Add more single scan tests
- // * disable wifi while scanning
- // * disable wifi while scanning with pending scan
+ /**
+ * Send a single scan request and then disable Wi-Fi before it completes
+ */
+ @Test
+ public void sendSingleScanRequestThenDisableWifi() {
+ WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 2293;
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId);
+
+ // disable wifi
+ TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+
+ // validate failed response
+ mLooper.dispatchAll();
+ verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ verifyNoMoreInteractions(handler);
+ }
+
+ /**
+ * Send a single scan request, schedule a second pending scan and disable Wi-Fi before the first
+ * scan completes.
+ */
+ @Test
+ public void sendSingleScanAndPendingScanAndListenerThenDisableWifi() {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 2293;
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 2294;
+
+ int listenerRequestId = 2295;
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // Request scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId1);
+
+ // Request scan 2
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId2);
+
+ // Setup scan listener
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ // disable wifi
+ TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+
+ // validate failed response
+ mLooper.dispatchAll();
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ order.verify(handler, times(2)).handleMessage(messageCaptor.capture());
+ assertFailedResponse(requestId1, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted", messageCaptor.getAllValues().get(0));
+ assertFailedResponse(requestId2, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted", messageCaptor.getAllValues().get(1));
+ // No additional callbacks for scan listener
+ verifyNoMoreInteractions(handler);
+ }
/**
* Send a single scan request and then a second one after the first completes.
@@ -627,8 +793,8 @@ public class WifiScanningServiceTest {
}
/**
- * Send a single scan request and then a second one before the first completes.
- * Verify that both are scheduled and succeed.
+ * Send a single scan request and then a second one not satisfied by the first before the first
+ * completes. Verify that both are scheduled and succeed.
*/
@Test
public void sendSingleScanRequestWhilePreviousScanRunning() {
@@ -693,8 +859,8 @@ public class WifiScanningServiceTest {
/**
- * Send a single scan request and then two more before the first completes.
- * Verify that the first completes and the second two are merged.
+ * Send a single scan request and then two more before the first completes. Neither are
+ * satisfied by the first scan. Verify that the first completes and the second two are merged.
*/
@Test
public void sendMultipleSingleScanRequestWhilePreviousScanRunning() throws RemoteException {
@@ -777,32 +943,8 @@ public class WifiScanningServiceTest {
mLooper.dispatchAll();
- // unfortunatally the order that these events are dispatched is dependant on the order which
- // they are iterated through internally
- ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
- handlerOrder.verify(handler, times(4)).handleMessage(messageCaptor.capture());
- int firstListenerId = messageCaptor.getAllValues().get(0).arg2;
- assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId3,
- firstListenerId == requestId2 || firstListenerId == requestId3);
- if (firstListenerId == requestId2) {
- assertScanResultsMessage(requestId2,
- new WifiScanner.ScanData[] {results2.getScanData()},
- messageCaptor.getAllValues().get(0));
- assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(1));
- assertScanResultsMessage(requestId3,
- new WifiScanner.ScanData[] {results3.getScanData()},
- messageCaptor.getAllValues().get(2));
- assertSingleScanCompletedMessage(requestId3, messageCaptor.getAllValues().get(3));
- } else {
- assertScanResultsMessage(requestId3,
- new WifiScanner.ScanData[] {results3.getScanData()},
- messageCaptor.getAllValues().get(0));
- assertSingleScanCompletedMessage(requestId3, messageCaptor.getAllValues().get(1));
- assertScanResultsMessage(requestId2,
- new WifiScanner.ScanData[] {results2.getScanData()},
- messageCaptor.getAllValues().get(2));
- assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3));
- }
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3,
+ results3);
assertEquals(mWifiMetrics.getOneshotScanCount(), 3);
assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 3);
@@ -819,6 +961,357 @@ public class WifiScanningServiceTest {
"results=" + results3.getRawScanResults().length);
}
+
+ /**
+ * Send a single scan request and then a second one satisfied by the first before the first
+ * completes. Verify that only one scan is scheduled.
+ */
+ @Test
+ public void sendSingleScanRequestWhilePreviousScanRunningAndMergeIntoFirstScan() {
+ // Split by frequency to make it easier to determine which results each request is expecting
+ ScanResults results24GHz = ScanResults.create(0, 2400, 2400, 2400, 2450);
+ ScanResults results5GHz = ScanResults.create(0, 5150, 5150, 5175);
+ ScanResults resultsBoth = ScanResults.merge(results24GHz, results5GHz);
+
+ WifiScanner.ScanSettings requestSettings1 = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = resultsBoth;
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(WifiScanner.WIFI_BAND_24_GHZ, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = results24GHz;
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+
+ // Queue scan 2 (will be folded into ongoing scan)
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(resultsBoth.getScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2,
+ results2);
+
+ assertEquals(mWifiMetrics.getOneshotScanCount(), 2);
+ assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 2);
+ }
+
+ /**
+ * Send a single scan request and then two more before the first completes, one of which is
+ * satisfied by the first scan. Verify that the first two complete together the second scan is
+ * just for the other scan.
+ */
+ @Test
+ public void sendMultipleSingleScanRequestWhilePreviousScanRunningAndMergeOneIntoFirstScan()
+ throws RemoteException {
+ // Split by frequency to make it easier to determine which results each request is expecting
+ ScanResults results2400 = ScanResults.create(0, 2400, 2400, 2400);
+ ScanResults results2450 = ScanResults.create(0, 2450);
+ ScanResults results1and3 = ScanResults.merge(results2400, results2450);
+
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400, 2450), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ WorkSource workSource1 = new WorkSource(1121);
+ ScanResults results1 = results1and3;
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ WorkSource workSource2 = new WorkSource(Binder.getCallingUid()); // don't explicitly set
+ ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
+
+ WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId3 = 15;
+ WorkSource workSource3 = new WorkSource(2292);
+ ScanResults results3 = results2400;
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, workSource1);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+ verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource1));
+
+
+ // Queue scan 2 (will not run because previous is in progress)
+ // uses uid of calling process
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // Queue scan 3 (will be merged into the active scan)
+ sendSingleScanRequest(controlChannel, requestId3, requestSettings3, workSource3);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId3);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1and3.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId3,
+ results3);
+ // only the requests know at the beginning of the scan get blamed
+ verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource1));
+ verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource2));
+
+ // now that the first scan completed we expect the second and third ones to start
+ WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings2));
+
+ // dispatch scan 2 and 3 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2.getScanData());
+ eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+
+ verifyScanResultsRecieved(handlerOrder, handler, requestId2, results2.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId2);
+ assertEquals(mWifiMetrics.getOneshotScanCount(), 3);
+ assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 3);
+
+ verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource2));
+
+ assertDumpContainsRequestLog("addSingleScanRequest", requestId1);
+ assertDumpContainsRequestLog("addSingleScanRequest", requestId2);
+ assertDumpContainsRequestLog("addSingleScanRequest", requestId3);
+ assertDumpContainsCallbackLog("singleScanResults", requestId1,
+ "results=" + results1.getRawScanResults().length);
+ assertDumpContainsCallbackLog("singleScanResults", requestId2,
+ "results=" + results2.getRawScanResults().length);
+ assertDumpContainsCallbackLog("singleScanResults", requestId3,
+ "results=" + results3.getRawScanResults().length);
+ }
+
+ /**
+ * Register a single scan listener and do a single scan
+ */
+ @Test
+ public void registerScanListener() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
+ ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
+
+ int requestId = 12;
+ int listenerRequestId = 13;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results.getRawScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId);
+ verifyScanResultsRecieved(order, handler, listenerRequestId, results.getScanData());
+ verifyNoMoreInteractions(handler);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results.getScanData().getResults().length);
+ }
+
+ /**
+ * Register a single scan listener and do a single scan
+ */
+ @Test
+ public void deregisterScanListener() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
+ ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
+
+ int requestId = 12;
+ int listenerRequestId = 13;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+
+ deregisterScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results.getRawScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId);
+ verifyNoMoreInteractions(handler);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsRequestLog("deregisterScanListener", listenerRequestId);
+ }
+
+ /**
+ * Send a single scan request and then two more before the first completes. Neither are
+ * satisfied by the first scan. Verify that the first completes and the second two are merged.
+ */
+ @Test
+ public void scanListenerRecievesAllResults() throws RemoteException {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = ScanResults.create(0, 2400);
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
+
+ WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId3 = 15;
+ ScanResults results3 = ScanResults.create(0, 5150, 5150, 5150, 5150);
+
+ WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5150));
+ ScanResults results2and3 = ScanResults.merge(results2, results3);
+
+ int listenerRequestId = 13;
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+
+
+ // Queue scan 2 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // Queue scan 3 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId3, requestSettings3, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId3);
+
+ // Register scan listener
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, listenerRequestId);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
+ verifyScanResultsRecieved(handlerOrder, handler, listenerRequestId, results1.getScanData());
+
+ // now that the first scan completed we expect the second and third ones to start
+ WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder,
+ nativeSettings2and3);
+
+ // dispatch scan 2 and 3 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2and3.getScanData());
+ eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3,
+ results3, listenerRequestId, results2and3);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results1.getRawScanResults().length);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results2and3.getRawScanResults().length);
+ }
+
+
private void doSuccessfulBackgroundScan(WifiScanner.ScanSettings requestSettings,
WifiNative.ScanSettings nativeSettings) {
startServiceAndLoadDriver();
@@ -1155,4 +1648,90 @@ public class WifiScanningServiceTest {
expectSwPnoScan(order, scanSettings.second, scanResults);
verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
}
+
+ /**
+ * Tries to simulate the race scenario where a client is disconnected immediately after single
+ * scan request is sent to |SingleScanStateMachine|.
+ */
+ @Test
+ public void processSingleScanRequestAfterDisconnect() throws Exception {
+ startServiceAndLoadDriver();
+ BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class));
+ mLooper.dispatchAll();
+
+ // Send the single scan request and then send the disconnect immediately after.
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 10;
+
+ 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,
+ 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
+ // disconnect after.
+ mLooper.dispatchAll();
+
+ // Now check that we logged the invalid request.
+ String serviceDump = dumpService();
+ Pattern logLineRegex = Pattern.compile("^.+" + "singleScanInvalidRequest: "
+ + "ClientInfo\\[unknown\\],Id=" + requestId + ",bad request$", Pattern.MULTILINE);
+ assertTrue("dump did not contain log with ClientInfo[unknown]: " + serviceDump + "\n",
+ 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);
+ }
}