Merge "METRICS: histograms of scanresult sums in scan" into oc-dr1-dev
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 4382c81..d6009c7 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -532,6 +532,9 @@
private void initializeInternal() {
initIServiceManagerIfNecessary();
+ if (isSupportedInternal()) {
+ initIWifiIfNecessary();
+ }
}
private void teardownInternal() {
@@ -561,9 +564,7 @@
Log.d(TAG, "IWifi registration notification: fqName=" + fqName
+ ", name=" + name + ", preexisting=" + preexisting);
synchronized (mLock) {
- mWifi = null; // get rid of old copy!
initIWifiIfNecessary();
- stopWifi(); // just in case
}
}
};
@@ -673,7 +674,8 @@
mWifi = null;
return;
}
- managerStatusListenerDispatch();
+ // Stopping wifi just in case. This would also trigger the status callback.
+ stopWifi();
} catch (RemoteException e) {
Log.e(TAG, "Exception while operating on IWifi: " + e);
}
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index 9c90bcf..98a5932 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -16,13 +16,16 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -31,6 +34,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Random;
import java.util.UUID;
@@ -50,6 +54,15 @@
private static final int RAND_SSID_INT_MIN = 1000;
private static final int RAND_SSID_INT_MAX = 9999;
+ @VisibleForTesting
+ static final int SSID_MIN_LEN = 1;
+ @VisibleForTesting
+ static final int SSID_MAX_LEN = 32;
+ @VisibleForTesting
+ static final int PSK_MIN_LEN = 8;
+ @VisibleForTesting
+ static final int PSK_MAX_LEN = 63;
+
private WifiConfiguration mWifiApConfig = null;
private ArrayList<Integer> mAllowed2GChannel = null;
@@ -224,4 +237,110 @@
config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
return config;
}
+
+ /**
+ * Verify provided SSID for existence, length and conversion to bytes
+ *
+ * @param ssid String ssid name
+ * @return boolean indicating ssid met requirements
+ */
+ private static boolean validateApConfigSsid(String ssid) {
+ if (TextUtils.isEmpty(ssid)) {
+ Log.d(TAG, "SSID for softap configuration must be set.");
+ return false;
+ }
+
+ if (ssid.length() < SSID_MIN_LEN || ssid.length() > SSID_MAX_LEN) {
+ Log.d(TAG, "SSID for softap configuration string size must be at least "
+ + SSID_MIN_LEN + " and not more than " + SSID_MAX_LEN);
+ return false;
+ }
+
+ try {
+ ssid.getBytes(StandardCharsets.UTF_8);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "softap config SSID verification failed: malformed string " + ssid);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Verify provided preSharedKey in ap config for WPA2_PSK network meets requirements.
+ */
+ private static boolean validateApConfigPreSharedKey(String preSharedKey) {
+ if (preSharedKey.length() < PSK_MIN_LEN || preSharedKey.length() > PSK_MAX_LEN) {
+ Log.d(TAG, "softap network password string size must be at least " + PSK_MIN_LEN
+ + " and no more than " + PSK_MAX_LEN);
+ return false;
+ }
+
+ try {
+ preSharedKey.getBytes(StandardCharsets.UTF_8);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "softap network password verification failed: malformed string");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate a WifiConfiguration is properly configured for use by SoftApManager.
+ *
+ * This method checks the length of the SSID and for sanity between security settings (if it
+ * requires a password, was one provided?).
+ *
+ * @param apConfig {@link WifiConfiguration} to use for softap mode
+ * @return boolean true if the provided config meets the minimum set of details, false
+ * otherwise.
+ */
+ static boolean validateApWifiConfiguration(@NonNull WifiConfiguration apConfig) {
+ // first check the SSID
+ if (!validateApConfigSsid(apConfig.SSID)) {
+ // failed SSID verificiation checks
+ return false;
+ }
+
+ // now check security settings: settings app allows open and WPA2 PSK
+ if (apConfig.allowedKeyManagement == null) {
+ Log.d(TAG, "softap config key management bitset was null");
+ return false;
+ }
+
+ String preSharedKey = apConfig.preSharedKey;
+ boolean hasPreSharedKey = !TextUtils.isEmpty(preSharedKey);
+ int authType;
+
+ try {
+ authType = apConfig.getAuthType();
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Unable to get AuthType for softap config: " + e.getMessage());
+ return false;
+ }
+
+ if (authType == KeyMgmt.NONE) {
+ // open networks should not have a password
+ if (hasPreSharedKey) {
+ Log.d(TAG, "open softap network should not have a password");
+ return false;
+ }
+ } else if (authType == KeyMgmt.WPA2_PSK) {
+ // this is a config that should have a password - check that first
+ if (!hasPreSharedKey) {
+ Log.d(TAG, "softap network password must be set");
+ return false;
+ }
+
+ if (!validateApConfigPreSharedKey(preSharedKey)) {
+ // failed preSharedKey checks
+ return false;
+ }
+ } else {
+ // this is not a supported security type
+ Log.d(TAG, "softap configs must either be open or WPA2 PSK networks");
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index c0ec8b7..973b659 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -1684,24 +1684,21 @@
}
/**
- * Set the TX power limit.
- * Primarily used for meeting SAR requirements during voice calls.
- *
- * @param powerLevelInDbm Power level to set in dBm.
- * @return true for success; false for failure or if the HAL version does not support this API.
+ * Tx power level scenarios that can be selected.
*/
- public boolean setTxPowerLimit(int powerLevelInDbm) {
- return mWifiVendorHal.setTxPowerLimit(powerLevelInDbm);
- }
+ public static final int TX_POWER_SCENARIO_NORMAL = 0;
+ public static final int TX_POWER_SCENARIO_VOICE_CALL = 1;
/**
- * Reset the TX power limit.
+ * Select one of the pre-configured TX power level scenarios or reset it back to normal.
* Primarily used for meeting SAR requirements during voice calls.
*
+ * @param scenario Should be one {@link #TX_POWER_SCENARIO_NORMAL} or
+ * {@link #TX_POWER_SCENARIO_VOICE_CALL}.
* @return true for success; false for failure or if the HAL version does not support this API.
*/
- public boolean resetTxPowerLimit() {
- return mWifiVendorHal.resetTxPowerLimit();
+ public boolean selectTxPowerScenario(int scenario) {
+ return mWifiVendorHal.selectTxPowerScenario(scenario);
}
/********************************************************
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index fe24705..89068a8 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -25,11 +25,11 @@
import android.net.wifi.WifiInfo;
import android.text.TextUtils;
import android.util.LocalLog;
-import android.util.Log;
import android.util.Pair;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wifi.util.ScanResultUtil;
import java.util.ArrayList;
import java.util.HashSet;
@@ -61,6 +61,8 @@
private final int mThresholdQualifiedRssi5;
private final int mThresholdMinimumRssi24;
private final int mThresholdMinimumRssi5;
+ private final int mStayOnNetworkMinimumTxRate;
+ private final int mStayOnNetworkMinimumRxRate;
private final boolean mEnableAutoJoinWhenAssociated;
/**
@@ -146,6 +148,18 @@
+ " , ID: " + network.networkId);
}
+ int currentRssi = wifiInfo.getRssi();
+ boolean hasQualifiedRssi =
+ (wifiInfo.is24GHz() && (currentRssi > mThresholdQualifiedRssi24))
+ || (wifiInfo.is5GHz() && (currentRssi > mThresholdQualifiedRssi5));
+ // getTxSuccessRate() and getRxSuccessRate() returns the packet rate in per 5 seconds unit.
+ boolean hasActiveStream = (wifiInfo.getTxSuccessRatePps() > mStayOnNetworkMinimumTxRate)
+ || (wifiInfo.getRxSuccessRatePps() > mStayOnNetworkMinimumRxRate);
+ if (hasQualifiedRssi && hasActiveStream) {
+ localLog("Stay on current network because of good RSSI and ongoing traffic");
+ return true;
+ }
+
// Ephemeral network is not qualified.
if (network.ephemeral) {
localLog("Current network is an ephemeral one.");
@@ -158,28 +172,15 @@
return false;
}
- int currentRssi = wifiInfo.getRssi();
if (wifiInfo.is24GHz()) {
// 2.4GHz networks is not qualified whenever 5GHz is available
if (is5GHzNetworkAvailable(scanDetails)) {
localLog("Current network is 2.4GHz. 5GHz networks available.");
return false;
}
- // When 5GHz is not available, we go through normal 2.4GHz qualification
- if (currentRssi < mThresholdQualifiedRssi24) {
- localLog("Current network band=2.4GHz, RSSI["
- + currentRssi + "]-acceptable but not qualified.");
- return false;
- }
- } else if (wifiInfo.is5GHz()) {
- // Must be 5GHz, so we always apply qualification checks
- if (currentRssi < mThresholdQualifiedRssi5) {
- localLog("Current network band=5GHz, RSSI["
- + currentRssi + "]-acceptable but not qualified.");
- return false;
- }
- } else {
- Log.e(TAG, "We're on a wifi network that's neither 2.4 or 5GHz... aliens!");
+ }
+ if (!hasQualifiedRssi) {
+ localLog("Current network RSSI[" + currentRssi + "]-acceptable but not qualified.");
return false;
}
@@ -345,9 +346,7 @@
for (ScanDetail scanDetail : mFilteredNetworks) {
ScanResult scanResult = scanDetail.getScanResult();
- // A capability of [ESS] represents an open access point
- // that is available for an STA to connect
- if (scanResult.capabilities == null || !scanResult.capabilities.equals("[ESS]")) {
+ if (!ScanResultUtil.isScanResultForOpenNetwork(scanResult)) {
continue;
}
@@ -585,5 +584,9 @@
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
R.bool.config_wifi_framework_enable_associated_network_selection);
+ mStayOnNetworkMinimumTxRate = context.getResources().getInteger(
+ R.integer.config_wifi_framework_min_tx_rate_for_staying_on_network);
+ mStayOnNetworkMinimumRxRate = context.getResources().getInteger(
+ R.integer.config_wifi_framework_min_rx_rate_for_staying_on_network);
}
}
diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java
index 98747a3..894d57c 100644
--- a/service/java/com/android/server/wifi/WifiScoreReport.java
+++ b/service/java/com/android/server/wifi/WifiScoreReport.java
@@ -38,6 +38,7 @@
private static final int DUMPSYS_ENTRY_COUNT_LIMIT = 14400; // 12 hours on 3 second poll
private boolean mVerboseLoggingEnabled = false;
+ private static final long FIRST_REASONABLE_WALL_CLOCK = 1490000000000L; // mid-December 2016
// Cache of the last score report.
private String mReport;
@@ -69,8 +70,10 @@
*/
public void reset() {
mReport = "";
- mReportValid = false;
- mSessionNumber++;
+ if (mReportValid) {
+ mSessionNumber++;
+ mReportValid = false;
+ }
mConnectedScore.reset();
mAggressiveConnectedScore.reset();
if (mVerboseLoggingEnabled) Log.d(TAG, "reset");
@@ -112,15 +115,16 @@
long millis = mConnectedScore.getMillis();
- logLinkMetrics(wifiInfo);
-
mConnectedScore.updateUsingWifiInfo(wifiInfo, millis);
mAggressiveConnectedScore.updateUsingWifiInfo(wifiInfo, millis);
+ int s0 = mConnectedScore.generateScore();
+ int s1 = mAggressiveConnectedScore.generateScore();
+
if (aggressiveHandover == 0) {
- score = mConnectedScore.generateScore();
+ score = s0;
} else {
- score = mAggressiveConnectedScore.generateScore();
+ score = s1;
}
//sanitize boundaries
@@ -131,6 +135,8 @@
score = 0;
}
+ logLinkMetrics(wifiInfo, s0, s1);
+
//report score
if (score != wifiInfo.score) {
if (mVerboseLoggingEnabled) {
@@ -157,8 +163,9 @@
/**
* Data logging for dumpsys
*/
- private void logLinkMetrics(WifiInfo wifiInfo) {
+ private void logLinkMetrics(WifiInfo wifiInfo, int s0, int s1) {
long now = mClock.getWallClockMillis();
+ if (now < FIRST_REASONABLE_WALL_CLOCK) return;
double rssi = wifiInfo.getRssi();
int freq = wifiInfo.getFrequency();
int linkSpeed = wifiInfo.getLinkSpeed();
@@ -169,9 +176,10 @@
try {
String timestamp = new SimpleDateFormat("MM-dd HH:mm:ss.SSS").format(new Date(now));
String s = String.format(Locale.US, // Use US to avoid comma/decimal confusion
- "%s,%d,%.1f,%d,%d,%.2f,%.2f,%.2f,%.2f",
+ "%s,%d,%.1f,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d",
timestamp, mSessionNumber, rssi, freq, linkSpeed,
- txSuccessRate, txRetriesRate, txBadRate, rxSuccessRate);
+ txSuccessRate, txRetriesRate, txBadRate, rxSuccessRate,
+ s0, s1);
mLinkMetricsHistory.add(s);
} catch (Exception e) {
Log.e(TAG, "format problem", e);
@@ -193,7 +201,7 @@
* @param args unused
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("time,session,rssi,freq,linkspeed,tx_good,tx_retry,tx_bad,rx");
+ pw.println("time,session,rssi,freq,linkspeed,tx_good,tx_retry,tx_bad,rx,s0,s1");
for (String line : mLinkMetricsHistory) {
pw.println(line);
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index d222727..d6faf9b 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -780,11 +780,19 @@
mLog.trace("setWifiEnabled package=% uid=% enable=%").c(packageName)
.c(Binder.getCallingUid()).c(enable).flush();
+ boolean isFromSettings =
+ mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid());
+
+ // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
+ if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
+ mLog.trace("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
+ return false;
+ }
+
// If SoftAp is enabled, only Settings is allowed to toggle wifi
boolean apEnabled =
mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
- boolean isFromSettings =
- mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid());
+
if (apEnabled && !isFromSettings) {
mLog.trace("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
return false;
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 33d8a14..2d24d20 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -733,10 +733,7 @@
private static final int CMD_DIAGS_CONNECT_TIMEOUT = BASE + 252;
/* Used to set the tx power limit for SAR during the start of a phone call. */
- private static final int CMD_SET_SAR_TX_POWER_LIMIT = BASE + 253;
-
- /* Used to reset the tx power limit for SAR at end of a phone call. */
- private static final int CMD_RESET_SAR_TX_POWER_LIMIT = BASE + 254;
+ private static final int CMD_SELECT_TX_POWER_SCENARIO = BASE + 253;
// For message logging.
private static final Class[] sMessageClasses = {
@@ -804,7 +801,6 @@
private final boolean mEnableChipWakeUpWhenAssociated;
private final boolean mEnableRssiPollWhenAssociated;
private final boolean mEnableVoiceCallSarTxPowerLimit;
- private final int mVoiceCallSarTxPowerLimitInDbm;
int mRunningBeaconCount = 0;
@@ -951,7 +947,7 @@
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
mLinkProperties = new LinkProperties();
- mPhoneStateListener = new WifiPhoneStateListener();
+ mPhoneStateListener = new WifiPhoneStateListener(looper);
mNetworkInfo.setIsAvailable(false);
mLastBssid = null;
@@ -1051,8 +1047,6 @@
R.bool.config_wifi_enable_disconnection_debounce);
mEnableVoiceCallSarTxPowerLimit = mContext.getResources().getBoolean(
R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit);
- mVoiceCallSarTxPowerLimitInDbm = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm);
mEnableChipWakeUpWhenAssociated = true;
mEnableRssiPollWhenAssociated = true;
@@ -3145,11 +3139,11 @@
}
private WifiInfo getWiFiInfoForUid(int uid) {
+ WifiInfo result = new WifiInfo(mWifiInfo);
if (Binder.getCallingUid() == Process.myUid()) {
- return mWifiInfo;
+ return result;
}
- WifiInfo result = new WifiInfo(mWifiInfo);
result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
IBinder binder = mFacade.getService("package");
@@ -3778,13 +3772,19 @@
* Listen for phone call state events to set/reset TX power limits for SAR requirements.
*/
private class WifiPhoneStateListener extends PhoneStateListener {
+ WifiPhoneStateListener(Looper looper) {
+ super(looper);
+ }
+
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (mEnableVoiceCallSarTxPowerLimit) {
if (state == CALL_STATE_OFFHOOK) {
- sendMessage(CMD_SET_SAR_TX_POWER_LIMIT, mVoiceCallSarTxPowerLimitInDbm);
+ sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
+ WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
} else if (state == CALL_STATE_IDLE) {
- sendMessage(CMD_RESET_SAR_TX_POWER_LIMIT);
+ sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
+ WifiNative.TX_POWER_SCENARIO_NORMAL);
}
}
}
@@ -3942,8 +3942,7 @@
case CMD_ROAM_WATCHDOG_TIMER:
case CMD_DISABLE_P2P_WATCHDOG_TIMER:
case CMD_DISABLE_EPHEMERAL_NETWORK:
- case CMD_SET_SAR_TX_POWER_LIMIT:
- case CMD_RESET_SAR_TX_POWER_LIMIT:
+ case CMD_SELECT_TX_POWER_SCENARIO:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
break;
case CMD_SET_SUSPEND_OPT_ENABLED:
@@ -4336,9 +4335,11 @@
// appropriately.
if (mEnableVoiceCallSarTxPowerLimit) {
if (getTelephonyManager().isOffhook()) {
- sendMessage(CMD_SET_SAR_TX_POWER_LIMIT, mVoiceCallSarTxPowerLimitInDbm);
- } else if (getTelephonyManager().isIdle()) {
- sendMessage(CMD_RESET_SAR_TX_POWER_LIMIT);
+ sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
+ WifiNative.TX_POWER_SCENARIO_VOICE_CALL);
+ } else {
+ sendMessage(CMD_SELECT_TX_POWER_SCENARIO,
+ WifiNative.TX_POWER_SCENARIO_NORMAL);
}
}
@@ -4523,17 +4524,11 @@
mWifiConnectivityManager.forceConnectivityScan();
}
break;
- case CMD_SET_SAR_TX_POWER_LIMIT:
- int txPowerLevelInDbm = message.arg1;
- logd("Setting Tx power limit to " + txPowerLevelInDbm);
- if (!mWifiNative.setTxPowerLimit(txPowerLevelInDbm)) {
- loge("Failed to set TX power limit");
- }
- break;
- case CMD_RESET_SAR_TX_POWER_LIMIT:
- logd("Resetting Tx power limit");
- if (!mWifiNative.resetTxPowerLimit()) {
- loge("Failed to reset TX power limit");
+ case CMD_SELECT_TX_POWER_SCENARIO:
+ int txPowerScenario = message.arg1;
+ logd("Setting Tx power scenario to " + txPowerScenario);
+ if (!mWifiNative.selectTxPowerScenario(txPowerScenario)) {
+ loge("Failed to set TX power scenario");
}
break;
default:
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index b434f51..12674aa 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -2370,40 +2370,42 @@
return android.hardware.wifi.V1_1.IWifiChip.castFrom(mIWifiChip);
}
- /**
- * Set the TX power limit.
- * Primarily used for meeting SAR requirements during voice calls.
- *
- * @param powerLevelInDbm Power level to set in dBm.
- * @return true for success; false for failure or if the HAL version does not support this API.
- */
- public boolean setTxPowerLimit(int powerLevelInDbm) {
- synchronized (sLock) {
- try {
- android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
- if (iWifiChipV11 == null) return boolResult(false);
- WifiStatus status = iWifiChipV11.setTxPowerLimit(powerLevelInDbm);
- if (!ok(status)) return false;
- } catch (RemoteException e) {
- handleRemoteException(e);
- return false;
- }
- return true;
+ private int frameworkToHalTxPowerScenario(int scenario) {
+ switch (scenario) {
+ case WifiNative.TX_POWER_SCENARIO_VOICE_CALL:
+ return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
+ default:
+ throw new IllegalArgumentException("bad scenario: " + scenario);
}
}
/**
- * Reset the TX power limit.
+ * Select one of the pre-configured TX power level scenarios or reset it back to normal.
* Primarily used for meeting SAR requirements during voice calls.
*
+ * @param scenario Should be one {@link WifiNative#TX_POWER_SCENARIO_NORMAL} or
+ * {@link WifiNative#TX_POWER_SCENARIO_VOICE_CALL}.
* @return true for success; false for failure or if the HAL version does not support this API.
*/
- public boolean resetTxPowerLimit() {
+ public boolean selectTxPowerScenario(int scenario) {
synchronized (sLock) {
try {
android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
if (iWifiChipV11 == null) return boolResult(false);
- WifiStatus status = iWifiChipV11.resetTxPowerLimit();
+ WifiStatus status;
+ if (scenario != WifiNative.TX_POWER_SCENARIO_NORMAL) {
+ int halScenario;
+ try {
+ halScenario = frameworkToHalTxPowerScenario(scenario);
+ } catch (IllegalArgumentException e) {
+ mLog.err("Illegal argument for select tx power scenario")
+ .c(e.toString()).flush();
+ return false;
+ }
+ status = iWifiChipV11.selectTxPowerScenario(halScenario);
+ } else {
+ status = iWifiChipV11.resetTxPowerScenario();
+ }
if (!ok(status)) return false;
} catch (RemoteException e) {
handleRemoteException(e);
diff --git a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
index 211e62a..0fadd80 100644
--- a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
@@ -27,6 +27,9 @@
import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* WifiScanner implementation that takes advantage of the gscan HAL API
* The gscan API is used to perform background scans and wificond is used for oneshot scans.
@@ -151,4 +154,9 @@
return mWificondScannerDelegate.shouldScheduleBackgroundScanForHwPno();
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mWificondScannerDelegate.dump(fd, pw, args);
+ }
}
diff --git a/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
index e0fb535..5281b3a 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
@@ -26,6 +26,8 @@
import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Comparator;
/**
@@ -158,4 +160,6 @@
* @return true if background scan needs to be started, false otherwise.
*/
public abstract boolean shouldScheduleBackgroundScanForHwPno();
+
+ protected abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
}
diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
index af874b9..ab2a5dc 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -2156,6 +2156,9 @@
}
pw.println();
}
+ if (mScannerImpl != null) {
+ mScannerImpl.dump(fd, pw, args);
+ }
}
void logScanRequest(String request, ClientInfo ci, int id, WorkSource workSource,
diff --git a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
index fd7fddb..84105ee 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -32,6 +32,8 @@
import com.android.server.wifi.WifiNative;
import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,6 +83,7 @@
private boolean mBackgroundScanPaused = false;
private ScanBuffer mBackgroundScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
+ private ArrayList<ScanDetail> mNativeScanResults;
private WifiScanner.ScanData mLatestSingleScanResult =
new WifiScanner.ScanData(0, 0, new ScanResult[0]);
@@ -535,11 +538,11 @@
// got a scan before we started scanning or after scan was canceled
return;
}
- ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
+ mNativeScanResults = mWifiNative.getScanResults();
List<ScanResult> hwPnoScanResults = new ArrayList<>();
int numFilteredScanResults = 0;
- for (int i = 0; i < nativeResults.size(); ++i) {
- ScanResult result = nativeResults.get(i).getScanResult();
+ for (int i = 0; i < mNativeScanResults.size(); ++i) {
+ ScanResult result = mNativeScanResults.get(i).getScanResult();
long timestamp_ms = result.timestamp / 1000; // convert us -> ms
if (timestamp_ms > mLastScanSettings.startTime) {
if (mLastScanSettings.hwPnoScanActive) {
@@ -556,11 +559,8 @@
if (mLastScanSettings.hwPnoScanActive
&& mLastScanSettings.pnoScanEventHandler != null) {
- ScanResult[] pnoScanResultsArray = new ScanResult[hwPnoScanResults.size()];
- for (int i = 0; i < pnoScanResultsArray.length; ++i) {
- ScanResult result = nativeResults.get(i).getScanResult();
- pnoScanResultsArray[i] = hwPnoScanResults.get(i);
- }
+ ScanResult[] pnoScanResultsArray =
+ hwPnoScanResults.toArray(new ScanResult[hwPnoScanResults.size()]);
mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
}
// On pno scan result event, we are expecting a mLastScanSettings for pno scan.
@@ -598,12 +598,12 @@
}
if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
- ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();
+ mNativeScanResults = mWifiNative.getScanResults();
List<ScanResult> singleScanResults = new ArrayList<>();
List<ScanResult> backgroundScanResults = new ArrayList<>();
int numFilteredScanResults = 0;
- for (int i = 0; i < nativeResults.size(); ++i) {
- ScanResult result = nativeResults.get(i).getScanResult();
+ for (int i = 0; i < mNativeScanResults.size(); ++i) {
+ ScanResult result = mNativeScanResults.get(i).getScanResult();
long timestamp_ms = result.timestamp / 1000; // convert us -> ms
if (timestamp_ms > mLastScanSettings.startTime) {
if (mLastScanSettings.backgroundScanActive) {
@@ -772,6 +772,40 @@
return false;
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mSettingsLock) {
+ pw.println("Latest native scan results:");
+ if (mNativeScanResults != null && mNativeScanResults.size() != 0) {
+ long nowMs = mClock.getElapsedSinceBootMillis();
+ pw.println(" BSSID Frequency RSSI Age(sec) SSID "
+ + " Flags");
+ for (ScanDetail scanDetail : mNativeScanResults) {
+ ScanResult r = scanDetail.getScanResult();
+ long timeStampMs = r.timestamp / 1000;
+ String age;
+ if (timeStampMs <= 0) {
+ age = "___?___";
+ } else if (nowMs < timeStampMs) {
+ age = " 0.000";
+ } else if (timeStampMs < nowMs - 1000000) {
+ age = ">1000.0";
+ } else {
+ age = String.format("%3.3f", (nowMs - timeStampMs) / 1000.0);
+ }
+ String ssid = r.SSID == null ? "" : r.SSID;
+ pw.printf(" %17s %9d %5d %7s %-32s %s\n",
+ r.BSSID,
+ r.frequency,
+ r.level,
+ age,
+ String.format("%1.32s", ssid),
+ r.capabilities);
+ }
+ }
+ }
+ }
+
private static class LastScanSettings {
public long startTime;
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 3e203a6..7a25e17 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -120,6 +120,9 @@
anyLong())).thenReturn(true);
when(mServiceManagerMock.registerForNotifications(anyString(), anyString(),
any(IServiceNotification.Stub.class))).thenReturn(true);
+ when(mServiceManagerMock.getTransport(
+ eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
+ .thenReturn(IServiceManager.Transport.HWBINDER);
when(mWifiMock.linkToDeath(any(IHwBinder.DeathRecipient.class), anyLong())).thenReturn(
true);
when(mWifiMock.registerEventCallback(any(IWifiEventCallback.class))).thenReturn(mStatusOk);
@@ -164,6 +167,22 @@
}
/**
+ * Test the service manager notification coming in after
+ * {@link HalDeviceManager#initIWifiIfNecessary()} is already invoked as a part of
+ * {@link HalDeviceManager#initialize()}.
+ */
+ @Test
+ public void testServiceRegisterationAfterInitialize() throws Exception {
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+
+ // This should now be ignored since IWifi is already non-null.
+ mServiceNotificationCaptor.getValue().onRegistration(IWifi.kInterfaceName, "", true);
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, mWifiMock, mServiceManagerMock);
+ }
+
+ /**
* Validate that multiple callback registrations are called and that duplicate ones are
* only called once.
*/
@@ -221,7 +240,7 @@
// verify: service and callback calls
mInOrder.verify(mWifiMock).start();
- mInOrder.verify(mManagerStatusListenerMock, times(3)).onStatusChanged();
+ mInOrder.verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
verifyNoMoreInteractions(mManagerStatusListenerMock);
}
@@ -1058,17 +1077,14 @@
*/
@Test
public void testIsSupportedTrue() throws Exception {
- when(mServiceManagerMock.getTransport(
- eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
- .thenReturn(IServiceManager.Transport.HWBINDER);
mInOrder = inOrder(mServiceManagerMock, mWifiMock);
executeAndValidateInitializationSequence();
assertTrue(mDut.isSupported());
}
/**
- * Validate that isSupported() returns true when IServiceManager finds the vendor HAL daemon in
- * the VINTF.
+ * Validate that isSupported() returns false when IServiceManager does not find the vendor HAL
+ * daemon in the VINTF.
*/
@Test
public void testIsSupportedFalse() throws Exception {
@@ -1076,7 +1092,7 @@
eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
.thenReturn(IServiceManager.Transport.EMPTY);
mInOrder = inOrder(mServiceManagerMock, mWifiMock);
- executeAndValidateInitializationSequence();
+ executeAndValidateInitializationSequence(false);
assertFalse(mDut.isSupported());
}
@@ -1088,6 +1104,10 @@
}
private void executeAndValidateInitializationSequence() throws Exception {
+ executeAndValidateInitializationSequence(true);
+ }
+
+ private void executeAndValidateInitializationSequence(boolean isSupported) throws Exception {
// act:
mDut.initialize();
@@ -1097,13 +1117,20 @@
mInOrder.verify(mServiceManagerMock).registerForNotifications(eq(IWifi.kInterfaceName),
eq(""), mServiceNotificationCaptor.capture());
- // act: get the service started (which happens even when service was already up)
- mServiceNotificationCaptor.getValue().onRegistration(IWifi.kInterfaceName, "", true);
+ // The service should already be up at this point.
+ mInOrder.verify(mServiceManagerMock).getTransport(eq(IWifi.kInterfaceName),
+ eq(HalDeviceManager.HAL_INSTANCE_NAME));
- // verify: wifi initialization sequence
- mInOrder.verify(mWifiMock).linkToDeath(mDeathRecipientCaptor.capture(), anyLong());
- mInOrder.verify(mWifiMock).registerEventCallback(mWifiEventCallbackCaptor.capture());
- collector.checkThat("isReady is true", mDut.isReady(), equalTo(true));
+ // verify: wifi initialization sequence if vendor HAL is supported.
+ if (isSupported) {
+ mInOrder.verify(mWifiMock).linkToDeath(mDeathRecipientCaptor.capture(), anyLong());
+ mInOrder.verify(mWifiMock).registerEventCallback(mWifiEventCallbackCaptor.capture());
+ // verify: onStop called as a part of initialize.
+ mInOrder.verify(mWifiMock).stop();
+ collector.checkThat("isReady is true", mDut.isReady(), equalTo(true));
+ } else {
+ collector.checkThat("isReady is false", mDut.isReady(), equalTo(false));
+ }
}
private void executeAndValidateStartupSequence()throws Exception {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
index 2d3b066..02064d8 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
@@ -17,6 +17,7 @@
package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -36,6 +37,7 @@
import java.io.File;
import java.lang.reflect.Method;
+import java.util.Random;
/**
* Unit tests for {@link com.android.server.wifi.WifiApConfigStore}.
@@ -50,12 +52,15 @@
private static final String TEST_DEFAULT_AP_SSID = "TestAP";
private static final String TEST_CONFIGURED_AP_SSID = "ConfiguredAP";
private static final String TEST_DEFAULT_HOTSPOT_SSID = "TestShare";
+ private static final String TEST_DEFAULT_HOTSPOT_PSK = "TestPassword";
private static final int RAND_SSID_INT_MIN = 1000;
private static final int RAND_SSID_INT_MAX = 9999;
+ private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
@Mock Context mContext;
@Mock BackupManagerProxy mBackupManagerProxy;
File mApConfigFile;
+ Random mRandom;
@Before
public void setUp() throws Exception {
@@ -73,6 +78,8 @@
resources.setString(R.string.wifi_localhotspot_configure_ssid_default,
TEST_DEFAULT_HOTSPOT_SSID);
when(mContext.getResources()).thenReturn(resources);
+
+ mRandom = new Random();
}
@After
@@ -195,6 +202,17 @@
}
/**
+ * Verify a proper WifiConfiguration is generate by getDefaultApConfiguration().
+ */
+ @Test
+ public void getDefaultApConfigurationIsValid() {
+ WifiApConfigStore store = new WifiApConfigStore(
+ mContext, mBackupManagerProxy, mApConfigFile.getPath());
+ WifiConfiguration config = store.getApConfiguration();
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
* Verify a proper local only hotspot config is generated when called properly with the valid
* context.
*/
@@ -204,5 +222,147 @@
verifyDefaultApConfig(config, TEST_DEFAULT_HOTSPOT_SSID);
// The LOHS config should also have a specific network id set - check that as well.
assertEquals(WifiConfiguration.LOCAL_ONLY_NETWORK_ID, config.networkId);
+
+ // verify that the config passes the validateApWifiConfiguration check
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
+ * Helper method to generate random SSIDs.
+ *
+ * Note: this method has limited use as a random SSID generator. The characters used in this
+ * method do no not cover all valid inputs.
+ * @param length number of characters to generate for the name
+ * @return String generated string of random characters
+ */
+ private String generateRandomString(int length) {
+
+ StringBuilder stringBuilder = new StringBuilder(length);
+ int index = -1;
+ while (stringBuilder.length() < length) {
+ index = mRandom.nextInt(TEST_CHAR_SET_AS_STRING.length());
+ stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Verify the SSID checks in validateApWifiConfiguration.
+ *
+ * Cases to check and verify they trigger failed verification:
+ * null WifiConfiguration.SSID
+ * empty WifiConfiguration.SSID
+ * invalid WifiConfiguaration.SSID length
+ *
+ * Additionally check a valid SSID with a random (within valid ranges) length.
+ */
+ @Test
+ public void testSsidVerificationInValidateApWifiConfigurationCheck() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = null;
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+ config.SSID = "";
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+ // check a string that is too large
+ config.SSID = generateRandomString(WifiApConfigStore.SSID_MAX_LEN + 1);
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // now check a valid SSID with a random length
+ config.SSID = generateRandomString(mRandom.nextInt(WifiApConfigStore.SSID_MAX_LEN + 1));
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
+ * Verify the Open network checks in validateApWifiConfiguration.
+ *
+ * If the configured network is open, it should not have a password set.
+ *
+ * Additionally verify a valid open network passes verification.
+ */
+ @Test
+ public void testOpenNetworkConfigInValidateApWifiConfigurationCheck() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = TEST_DEFAULT_HOTSPOT_SSID;
+
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ config.preSharedKey = TEST_DEFAULT_HOTSPOT_PSK;
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // open networks should not have a password set
+ config.preSharedKey = null;
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ config.preSharedKey = "";
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
+ * Verify the WPA2_PSK network checks in validateApWifiConfiguration.
+ *
+ * If the configured network is configured with a preSharedKey, verify that the passwork is set
+ * and it meets length requirements.
+ */
+ @Test
+ public void testWpa2PskNetworkConfigInValidateApWifiConfigurationCheck() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = TEST_DEFAULT_HOTSPOT_SSID;
+
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ config.preSharedKey = null;
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+ config.preSharedKey = "";
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // test too short
+ config.preSharedKey =
+ generateRandomString(WifiApConfigStore.PSK_MIN_LEN - 1);
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // test too long
+ config.preSharedKey =
+ generateRandomString(WifiApConfigStore.PSK_MAX_LEN + 1);
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // explicitly test min length
+ config.preSharedKey =
+ generateRandomString(WifiApConfigStore.PSK_MIN_LEN);
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // explicitly test max length
+ config.preSharedKey =
+ generateRandomString(WifiApConfigStore.PSK_MAX_LEN);
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+
+ // test random (valid length)
+ int maxLen = WifiApConfigStore.PSK_MAX_LEN;
+ int minLen = WifiApConfigStore.PSK_MIN_LEN;
+ config.preSharedKey =
+ generateRandomString(mRandom.nextInt(maxLen - minLen) + minLen);
+ assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
+ * Verify an invalid AuthType setting (that would trigger an IllegalStateException)
+ * returns false when triggered in the validateApWifiConfiguration.
+ */
+ @Test
+ public void testInvalidAuthTypeInValidateApWifiConfigurationCheck() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = TEST_DEFAULT_HOTSPOT_SSID;
+
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
+ }
+
+ /**
+ * Verify an unsupported authType returns false for validateApWifiConfigurationCheck.
+ */
+ @Test
+ public void testUnsupportedAuthTypeInValidateApWifiConfigurationCheck() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = TEST_DEFAULT_HOTSPOT_SSID;
+
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ assertFalse(WifiApConfigStore.validateApWifiConfiguration(config));
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
index fee9033..4965a35 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
@@ -76,6 +76,10 @@
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
mThresholdQualifiedRssi5G = mResource.getInteger(
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+ mStayOnNetworkMinimumTxRate = mResource.getInteger(
+ R.integer.config_wifi_framework_min_tx_rate_for_staying_on_network);
+ mStayOnNetworkMinimumRxRate = mResource.getInteger(
+ R.integer.config_wifi_framework_min_rx_rate_for_staying_on_network);
mThresholdSaturatedRssi2G = mResource.getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
mThresholdSaturatedRssi5G = mResource.getInteger(
@@ -149,6 +153,8 @@
private int mThresholdMinimumRssi5G;
private int mThresholdQualifiedRssi2G;
private int mThresholdQualifiedRssi5G;
+ private int mStayOnNetworkMinimumTxRate;
+ private int mStayOnNetworkMinimumRxRate;
private int mThresholdSaturatedRssi2G;
private int mThresholdSaturatedRssi5G;
@@ -172,6 +178,12 @@
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
.thenReturn(-85);
when(mResource.getInteger(
+ R.integer.config_wifi_framework_max_tx_rate_for_full_scan))
+ .thenReturn(8);
+ when(mResource.getInteger(
+ R.integer.config_wifi_framework_max_rx_rate_for_full_scan))
+ .thenReturn(8);
+ when(mResource.getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz))
.thenReturn(-57);
when(mResource.getInteger(
@@ -615,9 +627,19 @@
*/
@Test
public void test2GhzQualifiedNo5GhzAvailable() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
// Do not perform selection on 2GHz if current network is good and no 5GHz available
- testStayOrSwitch(mThresholdQualifiedRssi2G, false,
- mThresholdQualifiedRssi2G + 10, false, false);
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ false /* not open network */,
+ // Should not try to switch.
+ false);
}
/**
@@ -632,24 +654,24 @@
*/
@Test
public void test2GhzHighQuality5GhzAvailable() {
- // When on 2GHz, even with "good" signal strength, run selection if 5GHz available
- testStayOrSwitch(mThresholdQualifiedRssi2G, false,
- mThresholdQualifiedRssi5G - 1, true, true);
- }
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
- /**
- * Wifi network selector performs network selection on 2Ghz networks if the current network
- * is not of high quality.
- *
- * WifiStateMachine is under connected state and 2.4GHz test1 is connected.
- *
- * Expected behavior: network selection is performed
- */
- @Test
- public void test2GhzNotQualifiedOther2GhzAvailable() {
- // Run Selection on 2Ghz networks when not qualified even if no 5GHz available
- testStayOrSwitch(mThresholdQualifiedRssi2G - 1, false,
- mThresholdQualifiedRssi2G - 10, false, true);
+ // When on 2GHz, even with "good" signal strength, run selection if 5GHz available
+ testStayOrTryToSwitch(
+ // Parameters for network1:
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ false /* not open network */,
+ // Parameters for network2:
+ mThresholdQualifiedRssi5G + 1 /* rssi */,
+ true /* a 5G network */,
+ false /* not open network */,
+ // Should try to switch.
+ true);
}
/**
@@ -662,10 +684,19 @@
*/
@Test
public void test5GhzNotQualifiedLowRssi() {
- // Run Selection when the current 5Ghz network has low RSSI, regardless of what may
- // be available. The second scan result is irrelevant.
- testStayOrSwitch(mThresholdQualifiedRssi5G - 1, true,
- mThresholdQualifiedRssi2G - 1, false, true);
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G - 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
+ // Run Selection when the current 5Ghz network has low RSSI.
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
+ true /* a 5G network */,
+ false /* not open network */,
+ // Should try to switch.
+ true);
}
/**
@@ -678,9 +709,162 @@
*/
@Test
public void test5GhzQualified() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
// Connected to a high quality 5Ghz network, so the other result is irrelevant
- testStayOrSwitch(mThresholdQualifiedRssi5G, true,
- mThresholdQualifiedRssi5G + 10, true, false);
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
+ true /* a 5G network */,
+ false /* not open network */,
+ // Should not try to switch.
+ false);
+ }
+
+ /**
+ * New network selection is performed if the currently connected network
+ * band is 2G and there is no sign of streaming traffic.
+ *
+ * Expected behavior: Network Selector perform network selection after connected
+ * to the first one.
+ */
+ @Test
+ public void band2GNetworkIsNotSufficientWhenNoOngoingTrafficAnd5GhzAvailable() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
+ testStayOrTryToSwitch(
+ // Parameters for network1:
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ false /* not open network */,
+ // Parameters for network2:
+ mThresholdQualifiedRssi5G + 1 /* rssi */,
+ true /* a 5G network */,
+ false /* not open network */,
+ // Should try to switch.
+ true);
+ }
+
+ /**
+ * New network selection is performed if the currently connected network
+ * band is 2G with bad rssi.
+ *
+ * Expected behavior: Network Selector perform network selection after connected
+ * to the first one.
+ */
+ @Test
+ public void band2GNetworkIsNotSufficientWithBadRssi() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G - 1);
+ // No streaming traffic.
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ false /* not open network */,
+ // Should try to switch.
+ true);
+ }
+
+ /**
+ * New network selection is not performed if the currently connected 2G network
+ * has good Rssi and sign of streaming tx traffic.
+ *
+ * Expected behavior: Network selector does not perform network selection.
+ */
+ @Test
+ public void band2GNetworkIsSufficientWhenOnGoingTxTrafficCombinedWithGoodRssi() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
+ // Streaming traffic
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(
+ (double) (mStayOnNetworkMinimumTxRate + 1));
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ true /* open network */,
+ // Should not try to switch.
+ false);
+ }
+
+ /**
+ * New network selection is not performed if the currently connected 2G network
+ * has good Rssi and sign of streaming rx traffic.
+ *
+ * Expected behavior: Network selector does not perform network selection.
+ */
+ @Test
+ public void band2GNetworkIsSufficientWhenOnGoingRxTrafficCombinedWithGoodRssi() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
+ // Streaming traffic
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(
+ (double) (mStayOnNetworkMinimumRxRate + 1));
+
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
+ false /* not a 5G network */,
+ true /* open network */,
+ // Should not try to switch.
+ false);
+ }
+
+ /**
+ * New network selection is not performed if the currently connected 5G network
+ * has good Rssi and sign of streaming tx traffic.
+ *
+ * Expected behavior: Network selector does not perform network selection.
+ */
+ @Test
+ public void band5GNetworkIsSufficientWhenOnGoingTxTrafficCombinedWithGoodRssi() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
+ // Streaming traffic
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(
+ (double) (mStayOnNetworkMinimumTxRate + 1));
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
+ true /* a 5G network */,
+ true /* open network */,
+ // Should not try to switch.
+ false);
+ }
+
+ /**
+ * New network selection is not performed if the currently connected 5G network
+ * has good Rssi and sign of streaming rx traffic.
+ *
+ * Expected behavior: Network selector does not perform network selection.
+ */
+ @Test
+ public void band5GNetworkIsSufficientWhenOnGoingRxTrafficCombinedWithGoodRssi() {
+ // Rssi after connected.
+ when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
+ // Streaming traffic
+ when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
+ when(mWifiInfo.getRxSuccessRatePps()).thenReturn(
+ (double) (mStayOnNetworkMinimumRxRate + 1));
+
+ testStayOrTryToSwitch(
+ mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
+ true /* a 5G network */,
+ true /* open network */,
+ // Should not try to switch.
+ false);
}
/**
@@ -690,45 +874,78 @@
* It sets up two networks, connects to the first, and then ensures that
* both are available in the scan results for the NetworkSelector.
*/
- private void testStayOrSwitch(int levelNetwork1, boolean is5GHzNetwork1,
- int levelNetwork2, boolean is5GHzNetwork2, boolean shouldSelect) {
- // Create an updated ScanDetails that includes a new network
+ private void testStayOrTryToSwitch(
+ int rssiNetwork1, boolean is5GHzNetwork1, boolean isOpenNetwork1,
+ int rssiNetwork2, boolean is5GHzNetwork2, boolean isOpenNetwork2,
+ boolean shouldSelect) {
String[] ssids = {"\"test1\"", "\"test2\""};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
- int[] freqs = new int[2];
- freqs[0] = is5GHzNetwork1 ? 5180 : 2437;
- freqs[1] = is5GHzNetwork2 ? 5180 : 2437;
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {levelNetwork1, levelNetwork2};
- int[] securities = {SECURITY_PSK, SECURITY_PSK};
+ int[] freqs = {is5GHzNetwork1 ? 5180 : 2437, is5GHzNetwork2 ? 5180 : 2437};
+ String[] caps = {isOpenNetwork1 ? "[ESS]" : "[WPA2-EAP-CCMP][ESS]",
+ isOpenNetwork2 ? "[ESS]" : "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {rssiNetwork1, rssiNetwork2};
+ int[] securities = {isOpenNetwork1 ? SECURITY_NONE : SECURITY_PSK,
+ isOpenNetwork2 ? SECURITY_NONE : SECURITY_PSK};
+ testStayOrTryToSwitchImpl(ssids, bssids, freqs, caps, levels, securities, shouldSelect);
+ }
+ /**
+ * This is a meta-test that given one scan results, will
+ * determine whether or not network selection should be performed.
+ *
+ * It sets up two networks, connects to the first, and then ensures that
+ * the scan results for the NetworkSelector.
+ */
+ private void testStayOrTryToSwitch(
+ int rssi, boolean is5GHz, boolean isOpenNetwork,
+ boolean shouldSelect) {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {is5GHz ? 5180 : 2437};
+ String[] caps = {isOpenNetwork ? "[ESS]" : "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {rssi};
+ int[] securities = {isOpenNetwork ? SECURITY_NONE : SECURITY_PSK};
+ testStayOrTryToSwitchImpl(ssids, bssids, freqs, caps, levels, securities, shouldSelect);
+ }
+
+ private void testStayOrTryToSwitchImpl(String[] ssids, String[] bssids, int[] freqs,
+ String[] caps, int[] levels, int[] securities,
+ boolean shouldSelect) {
// Make a network selection to connect to test1.
ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
freqs, caps, levels, securities, mWifiConfigManager, mClock);
List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
HashSet<String> blacklist = new HashSet<String>();
- WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
- blacklist, mWifiInfo, false, true, false);
+ // DummyNetworkEvaluator always return the first network in the scan results
+ // for connection, so this should connect to the first network.
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(
+ scanDetails,
+ blacklist, mWifiInfo, false, true, true);
+ assertNotNull("Result should be not null", candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanDetails.get(0).getScanResult(), candidate);
when(mWifiInfo.getNetworkId()).thenReturn(0);
when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
- when(mWifiInfo.is24GHz()).thenReturn(!is5GHzNetwork1);
- when(mWifiInfo.is5GHz()).thenReturn(is5GHzNetwork1);
- when(mWifiInfo.getRssi()).thenReturn(levels[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(!ScanResult.is5GHz(freqs[0]));
+ when(mWifiInfo.is5GHz()).thenReturn(ScanResult.is5GHz(freqs[0]));
+
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
candidate = mWifiNetworkSelector.selectNetwork(scanDetails, blacklist, mWifiInfo,
true, false, false);
- if (!shouldSelect) {
- assertEquals("Expect null configuration", null, candidate);
- } else {
+ // DummyNetworkEvaluator always return the first network in the scan results
+ // for connection, so if nework selection is performed, the first network should
+ // be returned as candidate.
+ if (shouldSelect) {
assertNotNull("Result should be not null", candidate);
- ScanResult expectedResult = scanDetails.get(0).getScanResult();
WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
- expectedResult, candidate);
+ scanDetails.get(0).getScanResult(), candidate);
+ } else {
+ assertEquals("Expect null configuration", null, candidate);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 3b11d28..055050d 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -362,6 +362,7 @@
public void testSetWifiEnabledSuccess() throws Exception {
when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
}
@@ -386,12 +387,39 @@
doThrow(new SecurityException()).when(mContext)
.enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
eq("WifiService"));
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true);
verify(mWifiStateMachine, never()).syncGetWifiApState();
}
/**
* Verify that a call from an app with the NETWORK_SETTINGS permission can enable wifi if we
+ * are in airplane mode.
+ */
+ @Test
+ public void testSetWifiEnabledFromNetworkSettingsHolderWhenInAirplaneMode() throws Exception {
+ when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+ when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true));
+ verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
+ }
+
+ /**
+ * Verify that a caller without the NETWORK_SETTINGS permission can't enable wifi
+ * if we are in airplane mode.
+ */
+ @Test
+ public void testSetWifiEnabledFromAppFailsWhenInAirplaneMode() throws Exception {
+ when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+ when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
+ assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
+ verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
+ }
+
+ /**
+ * Verify that a call from an app with the NETWORK_SETTINGS permission can enable wifi if we
* are in softap mode.
*/
@Test
@@ -399,6 +427,7 @@
when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
}
@@ -410,6 +439,7 @@
public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception {
when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
+ when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mSettingsStore, never()).handleWifiToggled(anyBoolean());
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 10d6460..4dd0621 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -1902,7 +1902,7 @@
* setting/resetting Tx power limit.
*/
@Test
- public void testVoiceCallSar_disabledTxPowerLimit_WifiOn() throws Exception {
+ public void testVoiceCallSar_disabledTxPowerScenario_WifiOn() throws Exception {
loadComponentsInStaMode();
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
@@ -1915,7 +1915,7 @@
* setting/resetting Tx power limit.
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimit_WifiOn() throws Exception {
+ public void testVoiceCallSar_enabledTxPowerScenario_WifiOn() throws Exception {
mResources.setBoolean(
R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
initializeWsm();
@@ -1933,16 +1933,13 @@
* {@link TelephonyManager#CALL_STATE_OFFHOOK}.
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimitCallStateOffHook_WhenWifiTurnedOn()
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn()
throws Exception {
- int powerLevelInDbm = -45;
- mResources.setInteger(
- R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm,
- powerLevelInDbm);
mResources.setBoolean(
R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
initializeWsm();
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
when(mTelephonyManager.isOffhook()).thenReturn(true);
loadComponentsInStaMode();
@@ -1950,7 +1947,7 @@
assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
assertEquals("DisconnectedState", getCurrentState().getName());
assertNotNull(mPhoneStateListener);
- verify(mWifiNative).setTxPowerLimit(eq(powerLevelInDbm));
+ verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
}
/**
@@ -1959,12 +1956,13 @@
* {@link TelephonyManager#CALL_STATE_IDLE}.
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimitCallStateIdle_WhenWifiTurnedOn()
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiTurnedOn()
throws Exception {
mResources.setBoolean(
R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
initializeWsm();
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
when(mTelephonyManager.isIdle()).thenReturn(true);
loadComponentsInStaMode();
@@ -1972,7 +1970,30 @@
assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
assertEquals("DisconnectedState", getCurrentState().getName());
assertNotNull(mPhoneStateListener);
- verify(mWifiNative).resetTxPowerLimit();
+ }
+
+ /**
+ * Test that we do register the telephony call state listener on devices which do support
+ * setting/resetting Tx power limit and set the tx power level if we're in state
+ * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
+ * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
+ */
+ @Test
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiTurnedOn_Fails()
+ throws Exception {
+ mResources.setBoolean(
+ R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
+ initializeWsm();
+
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
+ when(mTelephonyManager.isOffhook()).thenReturn(true);
+
+ loadComponentsInStaMode();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ assertEquals(WifiStateMachine.CONNECT_MODE, mWsm.getOperationalModeForTest());
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ assertNotNull(mPhoneStateListener);
+ verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
}
/**
@@ -1981,16 +2002,14 @@
* {@link TelephonyManager#CALL_STATE_OFFHOOK}.
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimitCallStateOffHook_WhenWifiOn() throws Exception {
- int powerLevelInDbm = -45;
- mResources.setInteger(
- R.integer.config_wifi_framework_voice_call_sar_tx_power_limit_in_dbm,
- powerLevelInDbm);
- testVoiceCallSar_enabledTxPowerLimit_WifiOn();
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn()
+ throws Exception {
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
+ testVoiceCallSar_enabledTxPowerScenario_WifiOn();
mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
mLooper.dispatchAll();
- verify(mWifiNative).setTxPowerLimit(eq(powerLevelInDbm));
+ verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
}
/**
@@ -1999,12 +2018,31 @@
* {@link TelephonyManager#CALL_STATE_IDLE}.
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimitCallStateIdle_WhenWifiOn() throws Exception {
- testVoiceCallSar_enabledTxPowerLimit_WifiOn();
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateIdle_WhenWifiOn() throws Exception {
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(true);
+ testVoiceCallSar_enabledTxPowerScenario_WifiOn();
mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
mLooper.dispatchAll();
- verify(mWifiNative).resetTxPowerLimit();
+ verify(mWifiNative, atLeastOnce())
+ .selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ }
+
+ /**
+ * Test that we invoke the corresponding WifiNative method when
+ * {@link PhoneStateListener#onCallStateChanged(int, String)} is invoked with state
+ * {@link TelephonyManager#CALL_STATE_OFFHOOK}. This test checks if the
+ * {@link WifiNative#selectTxPowerScenario(int)} failure is handled correctly.
+ */
+ @Test
+ public void testVoiceCallSar_enabledTxPowerScenarioCallStateOffHook_WhenWifiOn_Fails()
+ throws Exception {
+ when(mWifiNative.selectTxPowerScenario(anyInt())).thenReturn(false);
+ testVoiceCallSar_enabledTxPowerScenario_WifiOn();
+
+ mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
+ mLooper.dispatchAll();
+ verify(mWifiNative).selectTxPowerScenario(eq(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
}
/**
@@ -2014,18 +2052,18 @@
* wifi is off (state machine is not in SupplicantStarted state).
*/
@Test
- public void testVoiceCallSar_enabledTxPowerLimitCallState_WhenWifiOff() throws Exception {
+ public void testVoiceCallSar_enabledTxPowerScenarioCallState_WhenWifiOff() throws Exception {
mResources.setBoolean(
R.bool.config_wifi_framework_enable_voice_call_sar_tx_power_limit, true);
initializeWsm();
mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK, "");
mLooper.dispatchAll();
- verify(mWifiNative, never()).setTxPowerLimit(anyInt());
+ verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
mPhoneStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE, "");
mLooper.dispatchAll();
- verify(mWifiNative, never()).resetTxPowerLimit();
+ verify(mWifiNative, never()).selectTxPowerScenario(anyInt());
}
/**
@@ -2103,4 +2141,20 @@
currentConfig.networkId = lastSelectedNetworkId - 1;
assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
}
+
+ /**
+ * Test that {@link WifiStateMachine#syncRequestConnectionInfo()} always returns a copy of
+ * WifiInfo.
+ */
+ @Test
+ public void testSyncRequestConnectionInfoDoesNotReturnLocalReference() {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+ wifiInfo.setBSSID(sBSSID);
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
+
+ WifiInfo syncWifiInfo = mWsm.syncRequestConnectionInfo();
+ assertEquals(wifiInfo.getSSID(), syncWifiInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), syncWifiInfo.getBSSID());
+ assertFalse(wifiInfo == syncWifiInfo);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 3f2f389..84de9d2 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
@@ -1844,48 +1844,67 @@
}
/**
- * Test the new setTxPowerLimit HIDL method invocation. This should return failure if the
+ * Test the new selectTxPowerScenario HIDL method invocation. This should return failure if the
* HAL service is exposing the 1.0 interface.
*/
@Test
- public void testSetTxPowerLimit() throws RemoteException {
- int powerLevelInDbm = -45;
-
+ public void testSelectTxPowerScenario() throws RemoteException {
assertTrue(mWifiVendorHal.startVendorHal(true));
// Should fail because we exposed the 1.0 IWifiChip.
- assertFalse(mWifiVendorHal.setTxPowerLimit(powerLevelInDbm));
- verify(mIWifiChipV11, never()).setTxPowerLimit(eq(powerLevelInDbm));
+ assertFalse(
+ mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
mWifiVendorHal.stopVendorHal();
// Now expose the 1.1 IWifiChip.
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
- when(mIWifiChipV11.setTxPowerLimit(anyInt())).thenReturn(mWifiStatusSuccess);
+ when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHal(true));
- assertTrue(mWifiVendorHal.setTxPowerLimit(powerLevelInDbm));
- verify(mIWifiChipV11).setTxPowerLimit(eq(powerLevelInDbm));
+ assertTrue(
+ mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
+ verify(mIWifiChipV11).selectTxPowerScenario(
+ eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL));
+ verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
}
/**
- * Test the new setTxPowerLimit HIDL method invocation. This should return failure if the
+ * Test the new resetTxPowerScenario HIDL method invocation. This should return failure if the
* HAL service is exposing the 1.0 interface.
*/
@Test
- public void testResetTxPowerLimit() throws RemoteException {
+ public void testResetTxPowerScenario() throws RemoteException {
assertTrue(mWifiVendorHal.startVendorHal(true));
// Should fail because we exposed the 1.0 IWifiChip.
- assertFalse(mWifiVendorHal.resetTxPowerLimit());
- verify(mIWifiChipV11, never()).resetTxPowerLimit();
+ assertFalse(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
// Now expose the 1.1 IWifiChip.
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
- when(mIWifiChipV11.resetTxPowerLimit()).thenReturn(mWifiStatusSuccess);
+ when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHal(true));
- assertTrue(mWifiVendorHal.resetTxPowerLimit());
- verify(mIWifiChipV11).resetTxPowerLimit();
+ assertTrue(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
+ verify(mIWifiChipV11).resetTxPowerScenario();
+ verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
+ mWifiVendorHal.stopVendorHal();
+ }
+
+ /**
+ * Test the new selectTxPowerScenario HIDL method invocation with a bad scenario index.
+ */
+ @Test
+ public void testInvalidSelectTxPowerScenario() throws RemoteException {
+ // Expose the 1.1 IWifiChip.
+ mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
+ when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
+
+ assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.selectTxPowerScenario(-6));
+ verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
+ verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
index 3a5f6b9..ed7c582 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
@@ -37,8 +37,12 @@
import org.junit.Test;
import org.mockito.InOrder;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Set;
+import java.util.regex.Pattern;
/**
* Unit tests for {@link com.android.server.wifi.scanner.WificondScannerImpl}.
@@ -554,6 +558,28 @@
}
/**
+ * Test that dump() of WificondScannerImpl dumps native scan results.
+ */
+ @Test
+ public void dumpContainsNativeScanResults() {
+ assertDumpContainsRequestLog("Latest native scan results:");
+ }
+
+ private void assertDumpContainsRequestLog(String log) {
+ String objectDump = dumpObject();
+ Pattern logLineRegex = Pattern.compile(".*" + log + ".*");
+ assertTrue("dump did not contain log = " + log + "\n " + objectDump + "\n",
+ logLineRegex.matcher(objectDump).find());
+ }
+
+ private String dumpObject() {
+ StringWriter stringWriter = new StringWriter();
+ mScanner.dump(new FileDescriptor(), new PrintWriter(stringWriter),
+ new String[0]);
+ return stringWriter.toString();
+ }
+
+ /**
* Run a test with the given settings where all native scans succeed
* This will execute expectedPeriods.length scan periods by first
* starting the scan settings and then dispatching the scan period alarm to start the