Snap for 7716385 from 6f35a068d028a304267594576c53805e93c71d0c to mainline-resolv-release
Change-Id: I0875cedcb5f73e99eb92cab6f663854f0632a8a2
diff --git a/framework/java/android/net/wifi/ScanResult.java b/framework/java/android/net/wifi/ScanResult.java
index efdf09b..fb831d9 100644
--- a/framework/java/android/net/wifi/ScanResult.java
+++ b/framework/java/android/net/wifi/ScanResult.java
@@ -908,6 +908,8 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int EID_TIM = 5;
/** @hide */
+ public static final int EID_COUNTRY = 7;
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int EID_BSS_LOAD = 11;
/** @hide */
diff --git a/service/ServiceWifiResources/res/values-te/strings.xml b/service/ServiceWifiResources/res/values-te/strings.xml
index 966f002..98a2bad 100644
--- a/service/ServiceWifiResources/res/values-te/strings.xml
+++ b/service/ServiceWifiResources/res/values-te/strings.xml
@@ -65,7 +65,7 @@
<string name="wifi_cannot_connect_with_randomized_mac_title" msgid="2344570489693915253">"<xliff:g id="SSID">%1$s</xliff:g>కు కనెక్ట్ చేయడం సాధ్యపడదు"</string>
<string name="wifi_cannot_connect_with_randomized_mac_message" msgid="4834133226521813352">"మీ గోప్యతా సెట్టింగ్లను మార్చడానికి నొక్కి, మళ్లీ ప్రయత్నించండి"</string>
<string name="wifi_disable_mac_randomization_dialog_title" msgid="2054540994993681606">"గోప్యతా సెట్టింగ్ను మార్చాలా?"</string>
- <string name="wifi_disable_mac_randomization_dialog_message" msgid="8874064864332248988">"కనెక్ట్ చేయడానికి, <xliff:g id="SSID">%1$s</xliff:g> అనేది ప్రత్యేకమైన ఐడెంటిఫయర్ అయిన మీ పరికరం యొక్క MAC చిరునామాను ఉపయోగించాల్సి ఉంటుంది. ప్రస్తుతం, ఈ నెట్వర్క్ కోసం మీ గోప్యతా సెట్టింగ్ యాదృచ్ఛిక ఐడెంటిఫయర్ను ఉపయోగిస్తుంది. \n\nఈ మార్పు వలన మీ పరికర లొకేషన్ను ట్రాక్ చేయడానికి సమీప పరికరాలకు అనుమతి లభించవచ్చు."</string>
+ <string name="wifi_disable_mac_randomization_dialog_message" msgid="8874064864332248988">"కనెక్ట్ చేయడానికి, <xliff:g id="SSID">%1$s</xliff:g> అనేది ప్రత్యేకమైన ఐడెంటిఫయర్ అయిన మీ పరికరం యొక్క MAC అడ్రస్ను ఉపయోగించాల్సి ఉంటుంది. ప్రస్తుతం, ఈ నెట్వర్క్ కోసం మీ గోప్యతా సెట్టింగ్ యాదృచ్ఛిక ఐడెంటిఫయర్ను ఉపయోగిస్తుంది. \n\nఈ మార్పు వలన మీ పరికర లొకేషన్ను ట్రాక్ చేయడానికి సమీప పరికరాలకు అనుమతి లభించవచ్చు."</string>
<string name="wifi_disable_mac_randomization_dialog_confirm_text" msgid="6954419863076751626">"సెట్టింగ్ను మార్చండి"</string>
<string name="wifi_disable_mac_randomization_dialog_success" msgid="5849155828154391387">"సెట్టింగ్ అప్డేట్ చేయబడింది. మళ్లీ కనెక్ట్ చేయడానికి ట్రై చేయండి."</string>
<string name="wifi_disable_mac_randomization_dialog_failure" msgid="2894643619143813096">"గోప్యతా సెట్టింగ్లను మార్చడం సాధ్యం కాదు"</string>
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index 1686d70..b2e1ef5 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -1935,6 +1935,13 @@
requestInfo.listener.onAnswer(cmmForSameBssid);
return;
}
+ // The CMM having BSSID conflict is exactly the one being requested.
+ // Simply return the CMM in this case. The requestor will be responsible to
+ // make sure it does not trigger the connection again when already connected.
+ if (cmmForSameBssid.getRole() == requestInfo.clientRole) {
+ requestInfo.listener.onAnswer(cmmForSameBssid);
+ return;
+ }
// Existing secondary CMM connected to the same ssid/bssid.
if (!canRequestMoreClientModeManagersInRole(
requestInfo.requestorWs, requestInfo.clientRole)) {
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index e85db36..d0e36bb 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -3271,6 +3271,8 @@
// Block to make sure IpClient has really shut down, lest cleanup
// race with, say, bringup code over in tethering.
mIpClientCallbacks.awaitShutdown();
+ mIpClientCallbacks = null;
+ mIpClient = null;
}
deregisterForWifiMonitorEvents(); // uses mInterfaceName, must call before nulling out
// TODO: b/79504296 This broadcast has been deprecated and should be removed
@@ -3600,6 +3602,7 @@
boolean isIpClientStarted = startIpClient(config, true);
if (isIpClientStarted) {
mIpClientWithPreConnection = true;
+ transitionTo(mL2ConnectingState);
break;
}
}
@@ -6329,6 +6332,7 @@
.withPreconnection()
.withApfCapabilities(
mWifiNative.getApfCapabilities(mInterfaceName))
+ .withDisplayName(config.SSID)
.withLayer2Information(layer2Info);
if (isUsingMacRandomization) {
// Use EUI64 address generation for link-local IPv6 addresses.
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index aa9c7a9..e648923 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -858,19 +858,33 @@
if (isBridgedMode()) {
boolean isFallbackToSingleAp = false;
int newSingleApBand = 0;
- for (ClientModeManager cmm
- : mActiveModeWarden.getClientModeManagers()) {
- WifiInfo wifiConnectedInfo = cmm.syncRequestConnectionInfo();
- int wifiFrequency = wifiConnectedInfo.getFrequency();
- if (wifiFrequency > 0
- && !mSafeChannelFrequencyList.contains(
- wifiFrequency)) {
- Log.d(getTag(), "Wifi connected to unavailable freq: "
- + wifiFrequency);
+ final List<ClientModeManager> cmms =
+ mActiveModeWarden.getClientModeManagers();
+ if (cmms.size() != 0) {
+ if (ApConfigUtil.isStaWithBridgedModeSupported(mContext)) {
+ for (ClientModeManager cmm
+ : mActiveModeWarden.getClientModeManagers()) {
+ WifiInfo wifiConnectedInfo =
+ cmm.syncRequestConnectionInfo();
+ int wifiFrequency = wifiConnectedInfo.getFrequency();
+ if (wifiFrequency > 0
+ && !mSafeChannelFrequencyList.contains(
+ wifiFrequency)) {
+ Log.d(getTag(), "Wifi connected to unavailable freq: "
+ + wifiFrequency);
+ isFallbackToSingleAp = true;
+ break;
+ }
+ }
+ } else {
+ // The client mode exist but DUT doesn't support
+ // STA + bridged AP, we should fallback to single AP mode.
+ Log.d(getTag(), " STA iface exist but device doesn't support"
+ + " STA + Bridged AP");
isFallbackToSingleAp = true;
- break;
}
}
+
for (int configuredBand : mCurrentSoftApConfiguration.getBands()) {
int availableBand = ApConfigUtil.removeUnavailableBands(
mCurrentSoftApCapability,
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java
index 4949972..55d83ce 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java
@@ -318,8 +318,13 @@
.getCandidateSecurityParams();
if (params != null
&& params.getSecurityType() == WifiConfiguration.SECURITY_TYPE_SAE) {
- mStaIfaceHal.logCallback("SAE incorrect password");
- isWrongPwd = true;
+ // If this is ever connected, the password should be correct.
+ isWrongPwd = !curConfiguration.getNetworkSelectionStatus().hasEverConnected();
+ if (isWrongPwd) {
+ mStaIfaceHal.logCallback("SAE incorrect password");
+ } else {
+ mStaIfaceHal.logCallback("SAE association rejection");
+ }
}
} else if (assocRejectInfo.statusCode == StatusCode.CHALLENGE_FAIL
&& WifiConfigurationUtil.isConfigForWepNetwork(curConfiguration)) {
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index e8507ce..7712693 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -457,7 +457,8 @@
mNetworkSelector.selectNetwork(secondaryCmmCandidates);
// No oem paid/private selected, fallback to legacy flow (should never happen!).
if (secondaryCmmCandidate == null
- || secondaryCmmCandidate.getNetworkSelectionStatus().getCandidate() == null) {
+ || secondaryCmmCandidate.getNetworkSelectionStatus().getCandidate() == null
+ || (!secondaryCmmCandidate.oemPaid && !secondaryCmmCandidate.oemPrivate)) {
localLog(listenerName + ": No secondary candidate");
handleCandidatesFromScanResultsForPrimaryCmmUsingMbbIfAvailable(
listenerName,
@@ -468,20 +469,15 @@
}
String secondaryCmmCandidateBssid =
secondaryCmmCandidate.getNetworkSelectionStatus().getCandidate().BSSID;
- WorkSource secondaryRequestorWs = null;
+
+ // At this point secondaryCmmCandidate must be either oemPaid, oemPrivate, or both.
// OEM_PAID takes precedence over OEM_PRIVATE, so attribute to OEM_PAID requesting app.
- if (secondaryCmmCandidate.oemPaid
- && mActiveModeWarden.canRequestMoreClientModeManagersInRole(
- mOemPaidConnectionRequestorWs, ROLE_CLIENT_SECONDARY_LONG_LIVED)) {
- secondaryRequestorWs = mOemPaidConnectionRequestorWs;
- } else if (secondaryCmmCandidate.oemPrivate
- && mActiveModeWarden.canRequestMoreClientModeManagersInRole(
- mOemPrivateConnectionRequestorWs, ROLE_CLIENT_SECONDARY_LONG_LIVED)) {
- secondaryRequestorWs = mOemPrivateConnectionRequestorWs;
- }
- // Secondary STA not available, fallback to legacy flow.
+ WorkSource secondaryRequestorWs = secondaryCmmCandidate.oemPaid
+ ? mOemPaidConnectionRequestorWs : mOemPrivateConnectionRequestorWs;
+
if (secondaryRequestorWs == null) {
- localLog(listenerName + ": No secondary STA available");
+ localLog(listenerName + ": Requestor worksource is null in long live STA use-case,"
+ + " falling back to single client mode manager flow.");
handleCandidatesFromScanResultsForPrimaryCmmUsingMbbIfAvailable(
listenerName,
Stream.concat(primaryCmmCandidates.stream(), secondaryCmmCandidates.stream())
@@ -489,6 +485,7 @@
handleScanResultsListener);
return;
}
+
WifiConfiguration primaryCmmCandidate =
mNetworkSelector.selectNetwork(primaryCmmCandidates);
// Request for a new client mode manager to spin up concurrent connection
@@ -2278,12 +2275,12 @@
* @param bssid the failed network.
* @param ssid identifies the failed network.
*/
- public void handleConnectionAttemptEnded(@NonNull ActiveModeManager activeModeManager,
+ public void handleConnectionAttemptEnded(@NonNull ClientModeManager clientModeManager,
int failureCode, @NonNull String bssid, @NonNull String ssid) {
List<ClientModeManager> internetConnectivityCmms =
mActiveModeWarden.getInternetConnectivityClientModeManagers();
- if (!(internetConnectivityCmms.contains(activeModeManager))) {
- Log.w(TAG, "Ignoring call from non primary Mode Manager " + activeModeManager,
+ if (!internetConnectivityCmms.contains(clientModeManager)) {
+ Log.w(TAG, "Ignoring call from non primary Mode Manager " + clientModeManager,
new Throwable());
return;
}
@@ -2295,11 +2292,16 @@
mOpenNetworkNotifier.handleWifiConnected(ssidUnquoted);
} else {
mOpenNetworkNotifier.handleConnectionFailure();
- retryConnectionOnLatestCandidates(bssid, ssid);
+ // Only attempt to reconnect when connection on the primary CMM fails, since MBB
+ // CMM will be destroyed after the connection failure.
+ if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) {
+ retryConnectionOnLatestCandidates(clientModeManager, bssid, ssid);
+ }
}
}
- private void retryConnectionOnLatestCandidates(String bssid, String ssid) {
+ private void retryConnectionOnLatestCandidates(@NonNull ClientModeManager clientModeManager,
+ String bssid, String ssid) {
try {
if (mLatestCandidates == null || mLatestCandidates.size() == 0
|| mClock.getElapsedSinceBootMillis() - mLatestCandidatesTimestampMs
@@ -2333,7 +2335,12 @@
mWifiBlocklistMonitor.blockBssidForDurationMs(bssid, ssid,
TEMP_BSSID_BLOCK_DURATION,
WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT, 0);
- connectToNetworkForPrimaryCmmUsingMbbIfAvailable(candidate);
+ triggerConnectToNetworkUsingCmm(clientModeManager, candidate,
+ ClientModeImpl.SUPPLICANT_BSSID_ANY);
+ // since using primary manager to connect, stop any existing managers in the
+ // secondary transient role since they are no longer needed.
+ mActiveModeWarden.stopAllClientModeManagersInRole(
+ ROLE_CLIENT_SECONDARY_TRANSIENT);
}
} catch (IllegalArgumentException e) {
localLog("retryConnectionOnLatestCandidates: failed to create MacAddress from bssid="
diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java
index 0398200..6edf9f1 100644
--- a/service/java/com/android/server/wifi/WifiCountryCode.java
+++ b/service/java/com/android/server/wifi/WifiCountryCode.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.wifi.WifiInfo;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -50,6 +51,9 @@
public class WifiCountryCode {
private static final String TAG = "WifiCountryCode";
private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
+ private static final int PKT_COUNT_HIGH_PKT_PER_SEC = 16;
+ private static final int DISCONNECT_WIFI_COUNT_MAX = 1;
+ private static final String COUNTRY_CODE_WORLD = "00";
private final Context mContext;
private final TelephonyManager mTelephonyManager;
private final ActiveModeWarden mActiveModeWarden;
@@ -79,6 +83,7 @@
private String mTelephonyCountryTimestamp = null;
private String mDriverCountryTimestamp = null;
private String mReadyTimestamp = null;
+ private int mDisconnectWifiToForceUpdateCount = 0;
private class ModeChangeCallbackInternal implements ActiveModeWarden.ModeChangeCallback {
@Override
@@ -315,7 +320,7 @@
// Empty country code.
if (TextUtils.isEmpty(countryCode)) {
if (mContext.getResources()
- .getBoolean(R.bool.config_wifi_revert_country_code_on_cellular_loss)) {
+ .getBoolean(R.bool.config_wifi_revert_country_code_on_cellular_loss)) {
Log.d(TAG, "Received empty country code, reset to default country code");
mTelephonyCountryCode = null;
}
@@ -343,11 +348,54 @@
updateCountryCode();
} else {
Log.d(TAG, "skip update supplicant not ready yet");
+ disconnectWifiToForceUpdateIfNeeded();
}
return true;
}
+ private void disconnectWifiToForceUpdateIfNeeded() {
+ if (shouldDisconnectWifiToForceUpdate()) {
+ Log.d(TAG, "Disconnect wifi to force update");
+ for (ClientModeManager cmm :
+ mActiveModeWarden.getInternetConnectivityClientModeManagers()) {
+ if (!cmm.isConnected()) {
+ continue;
+ }
+ cmm.disconnect();
+ }
+ mDisconnectWifiToForceUpdateCount++;
+ }
+ }
+
+ private boolean shouldDisconnectWifiToForceUpdate() {
+ if (mTelephonyCountryCode == null || mTelephonyCountryCode.equals(mDriverCountryCode)) {
+ return false;
+ }
+
+ if (mDisconnectWifiToForceUpdateCount >= DISCONNECT_WIFI_COUNT_MAX) {
+ return false;
+ }
+
+ if (mDriverCountryCode != null
+ && !mDriverCountryCode.equalsIgnoreCase(COUNTRY_CODE_WORLD)) {
+ return false;
+ }
+
+ for (ClientModeManager cmm :
+ mActiveModeWarden.getInternetConnectivityClientModeManagers()) {
+ if (!cmm.isConnected()) {
+ continue;
+ }
+ WifiInfo wifiInfo = cmm.syncRequestConnectionInfo();
+ if (wifiInfo.getSuccessfulTxPacketsPerSecond() < PKT_COUNT_HIGH_PKT_PER_SEC
+ && wifiInfo.getSuccessfulRxPacketsPerSecond() < PKT_COUNT_HIGH_PKT_PER_SEC) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Method to get the Country Code that was sent to wpa_supplicant.
*
@@ -399,12 +447,12 @@
}
/**
- * Method to dump the current state of this WifiCounrtyCode object.
+ * Method to dump the current state of this WifiCountryCode object.
*/
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("mRevertCountryCodeOnCellularLoss: "
+ mContext.getResources().getBoolean(
- R.bool.config_wifi_revert_country_code_on_cellular_loss));
+ R.bool.config_wifi_revert_country_code_on_cellular_loss));
pw.println("DefaultCountryCode(system property): " + getOemDefaultCountryCode());
pw.println("DefaultCountryCode(config store): "
+ mSettingsConfigStore.get(WIFI_DEFAULT_COUNTRY_CODE));
@@ -416,6 +464,7 @@
pw.println("mReadyTimestamp: " + mReadyTimestamp);
pw.println("isReady: " + isReady());
pw.println("mAmmToReadyForChangeMap: " + mAmmToReadyForChangeMap);
+ pw.println("mDisconnectWifiToForceUpdateCount: " + mDisconnectWifiToForceUpdateCount);
}
private void updateCountryCode() {
@@ -426,7 +475,7 @@
// There are two reasons:
// 1. Wpa supplicant may silently modify the country code.
// 2. If Wifi restarted therefore wpa_supplicant also restarted,
- // the country code counld be reset to '00' by wpa_supplicant.
+ // the country code could be reset to '00' by wpa_supplicant.
if (country != null) {
setCountryCodeNative(country);
}
@@ -497,4 +546,3 @@
}
}
}
-
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 3445b76..3affdef 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -210,6 +210,9 @@
public static final int MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS = 1000 * 3600; // 1 hour
public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_ESS = 0;
public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_BSS = 1;
+ public static final int COUNTRY_CODE_CONFLICT_WIFI_SCAN = -1;
+ public static final int COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY = -2;
+ public static final int MAX_COUNTRY_CODE_COUNT = 4;
// Histogram for WifiConfigStore IO duration times. Indicates the following 5 buckets (in ms):
// < 50
// [50, 100)
@@ -237,6 +240,7 @@
private RttMetrics mRttMetrics;
private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
private final WifiLinkLayerUsageStats mWifiLinkLayerUsageStats = new WifiLinkLayerUsageStats();
+ private final TelephonyManager mTelephonyManager;
/** Mapping of radio id values to RadioStats objects. */
private final SparseArray<RadioStats> mRadioStats = new SparseArray<>();
private final ExperimentValues mExperimentValues = new ExperimentValues();
@@ -394,6 +398,7 @@
private final SparseIntArray mObservedHotspotR3ApsPerEssInScanHistogram = new SparseIntArray();
private final SparseIntArray mObserved80211mcApInScanHistogram = new SparseIntArray();
+ private final IntCounter mCountryCodeScanHistogram = new IntCounter();
// link probing stats
private final IntCounter mLinkProbeSuccessRssiCounts = new IntCounter(-85, -65);
@@ -1525,6 +1530,7 @@
setScreenState(context.getSystemService(PowerManager.class).isInteractive());
mScanMetrics = new ScanMetrics(context, clock);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
}
/** Sets internal ScoringParams member */
@@ -3409,6 +3415,8 @@
mWifiLogProto.partialAllSingleScanListenerResults++;
return;
}
+ updateCountryCodeScanStats(scanDetails);
+
Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>();
int bssids = 0;
Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>();
@@ -3547,6 +3555,35 @@
}
}
+ private void updateCountryCodeScanStats(List<ScanDetail> scanDetails) {
+ String countryCode = null;
+ int countryCodeCount = 0;
+ for (ScanDetail scanDetail : scanDetails) {
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+ String countryCodeCurr = networkDetail.getCountryCode();
+ if (countryCodeCurr == null) {
+ continue;
+ }
+ if (countryCode == null) {
+ countryCode = countryCodeCurr;
+ countryCodeCount = 1;
+ continue;
+ }
+ if (!countryCodeCurr.equalsIgnoreCase(countryCode)) {
+ mCountryCodeScanHistogram.increment(COUNTRY_CODE_CONFLICT_WIFI_SCAN);
+ return;
+ }
+ countryCodeCount++;
+ }
+ String countryCodeTelephony = mTelephonyManager.getNetworkCountryIso();
+ if (countryCodeCount > 0 && !TextUtils.isEmpty(countryCodeTelephony)
+ && !countryCodeTelephony.equalsIgnoreCase(countryCode)) {
+ mCountryCodeScanHistogram.increment(COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY);
+ return;
+ }
+ mCountryCodeScanHistogram.increment(Math.min(countryCodeCount, MAX_COUNTRY_CODE_COUNT));
+ }
+
/** Increments the occurence of a "Connect to Network" notification. */
public void incrementConnectToNetworkNotification(String notifierTag, int notificationType) {
synchronized (mLock) {
@@ -4094,6 +4131,8 @@
pw.println("mWifiLogProto.observed80211mcSupportingApsInScanHistogram"
+ mObserved80211mcApInScanHistogram);
+ pw.println("mWifiLogProto.CountryCodeScanHistogram="
+ + mCountryCodeScanHistogram.toString());
pw.println("mWifiLogProto.bssidBlocklistStats:");
pw.println(mBssidBlocklistStats.toString());
@@ -5057,6 +5096,7 @@
mWifiLogProto.passpointDeauthImminentScope = mPasspointDeauthImminentScope.toProto();
mWifiLogProto.recentFailureAssociationStatus =
mRecentFailureAssociationStatus.toProto();
+ mWifiLogProto.countryCodeScanHistogram = mCountryCodeScanHistogram.toProto();
}
}
@@ -5216,6 +5256,7 @@
mObservedHotspotR1ApsPerEssInScanHistogram.clear();
mObservedHotspotR2ApsPerEssInScanHistogram.clear();
mObservedHotspotR3ApsPerEssInScanHistogram.clear();
+ mCountryCodeScanHistogram.clear();
mSoftApEventListTethered.clear();
mSoftApEventListLocalOnly.clear();
mWifiWakeMetrics.clear();
diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java
index b5d8b75..493f339 100644
--- a/service/java/com/android/server/wifi/WifiScoreCard.java
+++ b/service/java/com/android/server/wifi/WifiScoreCard.java
@@ -1340,13 +1340,19 @@
long txBytesDelta = txBytes - mLastTxBytes;
long rxBytesDelta = rxBytes - mLastRxBytes;
+ int txLinkSpeedMbps = wifiInfo.getTxLinkSpeedMbps();
+ int txBandwidthCapMbps = (txLinkSpeedMbps == LINK_SPEED_UNKNOWN)
+ ? wifiInfo.getMaxSupportedTxLinkSpeedMbps() : txLinkSpeedMbps;
if (txBytesDelta * RX_OVER_TX_BYTE_RATIO_MAX >= rxBytesDelta) {
- updateBandwidthSample(txBytesDelta, LINK_TX, onTimeMs,
- wifiInfo.getMaxSupportedTxLinkSpeedMbps());
+ updateBandwidthSample(txBytesDelta, LINK_TX, onTimeMs, txBandwidthCapMbps);
}
- updateBandwidthSample(rxBytesDelta, LINK_RX, onTimeMs,
- wifiInfo.getMaxSupportedRxLinkSpeedMbps());
+ int rxLinkSpeedMbps = wifiInfo.getRxLinkSpeedMbps();
+ // Rx link speed is not available in many devices. In these cases, fall back to Tx link
+ // speed which is available in most devices.
+ int rxBandwidthCapMbps = (rxLinkSpeedMbps == LINK_SPEED_UNKNOWN)
+ ? txBandwidthCapMbps : rxLinkSpeedMbps;
+ updateBandwidthSample(rxBytesDelta, LINK_RX, onTimeMs, rxBandwidthCapMbps);
if (!mBandwidthSampleValid[LINK_RX] && !mBandwidthSampleValid[LINK_TX]) {
return;
@@ -1380,13 +1386,12 @@
}
private void updateBandwidthSample(long bytesDelta, int link, int onTimeMs,
- int maxSupportedLinkSpeedMbps) {
- checkAndPossiblyResetBandwidthStats(link, maxSupportedLinkSpeedMbps);
+ int bandwidthCapMbps) {
if (bytesDelta < mByteDeltaAccThr[link]) {
return;
}
long speedKbps = bytesDelta / onTimeMs * 8;
- if (speedKbps > (maxSupportedLinkSpeedMbps * 1000)) {
+ if (speedKbps > (bandwidthCapMbps * 1000)) {
return;
}
int linkBandwidthKbps = (int) speedKbps;
@@ -1405,26 +1410,6 @@
}
}
- private void checkAndPossiblyResetBandwidthStats(int link, int maxSupportedLinkSpeedMbps) {
- if (getAvgUsedLinkBandwidthKbps(link) > (maxSupportedLinkSpeedMbps * 1000)) {
- resetBandwidthStats(link);
- }
- }
-
- private void resetBandwidthStats(int link) {
- changed = true;
- // Reset SSID level stats
- mBandwidthStatsValue[mBandIdx][link][mSignalLevel] = 0;
- mBandwidthStatsCount[mBandIdx][link][mSignalLevel] = 0;
- // Reset BSSID level stats
- PerBssid perBssid = lookupBssid(ssid, mBssid);
- if (perBssid != mPlaceholderPerBssid) {
- perBssid.changed = true;
- perBssid.bandwidthStatsValue[mBandIdx][link][mSignalLevel] = 0;
- perBssid.bandwidthStatsCount[mBandIdx][link][mSignalLevel] = 0;
- }
- }
-
private int getByteDeltaAccThr(int link) {
int maxTimeDeltaMs = mContext.getResources().getInteger(
R.integer.config_wifiPollRssiIntervalMilliseconds);
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index d433787..4fb8cbf 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1180,7 +1180,8 @@
mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush();
- if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
+ if (!mWifiThreadRunner.call(
+ () -> mTetheredSoftApTracker.setEnablingIfAllowed(), false)) {
mLog.err("Tethering is already active.").flush();
return false;
}
@@ -4380,8 +4381,7 @@
// It doesn't relate the vendor HAL, set if overlay enables it.
supportedFeatureSet |= WifiManager.WIFI_FEATURE_BRIDGED_AP;
}
- if (mContext.getResources().getBoolean(
- R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported)) {
+ if (ApConfigUtil.isStaWithBridgedModeSupported(mContext)) {
// The bridged mode requires the kernel network modules support.
// It doesn't relate the vendor HAL, set if overlay enables it.
supportedFeatureSet |= WifiManager.WIFI_FEATURE_STA_BRIDGED_AP;
diff --git a/service/java/com/android/server/wifi/coex/CoexManager.java b/service/java/com/android/server/wifi/coex/CoexManager.java
index 326bb85..2bfcf13 100644
--- a/service/java/com/android/server/wifi/coex/CoexManager.java
+++ b/service/java/com/android/server/wifi/coex/CoexManager.java
@@ -309,6 +309,11 @@
Log.e(TAG, "setCoexUnsafeChannels called with undefined restriction flags");
return;
}
+ if (new HashSet(mCurrentCoexUnsafeChannels).equals(new HashSet(coexUnsafeChannels))
+ && mCoexRestrictions == coexRestrictions) {
+ // Do not update if the unsafe channels haven't changed since the last time
+ return;
+ }
mCurrentCoexUnsafeChannels.clear();
mCurrentCoexUnsafeChannels.addAll(coexUnsafeChannels);
mCoexRestrictions = coexRestrictions;
diff --git a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
index 22e8554..b43a00b 100644
--- a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
+++ b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
@@ -115,6 +115,7 @@
private final int mAnqpOICount;
private final long[] mRoamingConsortiums;
private int mDtimInterval = -1;
+ private String mCountryCode;
private final InformationElementUtil.ExtendedCapabilities mExtendedCapabilities;
@@ -167,6 +168,9 @@
InformationElementUtil.ExtendedCapabilities extendedCapabilities =
new InformationElementUtil.ExtendedCapabilities();
+ InformationElementUtil.Country country =
+ new InformationElementUtil.Country();
+
InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
new InformationElementUtil.TrafficIndicationMap();
@@ -212,6 +216,9 @@
case ScanResult.InformationElement.EID_EXTENDED_CAPS:
extendedCapabilities.from(ie);
break;
+ case ScanResult.InformationElement.EID_COUNTRY:
+ country.from(ie);
+ break;
case ScanResult.InformationElement.EID_TIM:
trafficIndicationMap.from(ie);
break;
@@ -348,6 +355,10 @@
mCenterfreq0 = centerFreq0;
mCenterfreq1 = centerFreq1;
+ if (country.isValid()) {
+ mCountryCode = country.getCountryCode();
+ }
+
// If trafficIndicationMap is not valid, mDtimPeriod will be negative
if (trafficIndicationMap.isValid()) {
mDtimInterval = trafficIndicationMap.mDtimPeriod;
@@ -426,6 +437,7 @@
mCenterfreq0 = base.mCenterfreq0;
mCenterfreq1 = base.mCenterfreq1;
mDtimInterval = base.mDtimInterval;
+ mCountryCode = base.mCountryCode;
mWifiMode = base.mWifiMode;
mMaxRate = base.mMaxRate;
mMaxNumberSpatialStreams = base.mMaxNumberSpatialStreams;
@@ -552,6 +564,10 @@
return mDtimInterval;
}
+ public String getCountryCode() {
+ return mCountryCode;
+ }
+
public boolean is80211McResponderSupport() {
return mExtendedCapabilities.is80211McRTTResponder();
}
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index c0bdd66..62f8feb 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -966,6 +966,18 @@
}
}
+ // Clear internal data when P2P is shut down due to wifi off or no client.
+ // For idle shutdown case, there are clients and data should be restored when
+ // P2P goes back P2pEnabledState.
+ // For a real shutdown case which caused by wifi off or no client, those internal
+ // data should be cleared because the caller might not clear them, ex. WFD app
+ // enables WFD, but does not disable it after leaving the app.
+ private void clearP2pInternalDataIfNecessary() {
+ if (mIsWifiEnabled && !mDeathDataByBinder.isEmpty()) return;
+
+ mThisDevice.wfdInfo = null;
+ }
+
boolean isP2pDisabled() {
return getCurrentState() == mP2pDisabledState;
}
@@ -1178,12 +1190,16 @@
WifiP2pManager.BUSY);
break;
case WifiP2pManager.SET_WFD_INFO:
+ WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
if (!getWfdPermission(message.sendingUid)) {
replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
WifiP2pManager.ERROR);
+ } else if (d != null) {
+ mThisDevice.wfdInfo = d;
+ replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
- WifiP2pManager.BUSY);
+ WifiP2pManager.ERROR);
}
break;
case WifiP2pManager.REQUEST_PEERS:
@@ -1517,6 +1533,7 @@
public void enter() {
if (mVerboseLoggingEnabled) logd(getName());
mInterfaceName = null; // reset iface name on disable.
+ clearP2pInternalDataIfNecessary();
}
private void setupInterfaceFeatures(String interfaceName) {
@@ -1581,7 +1598,8 @@
// which require P2P to be active.
if (message.what < Protocol.BASE_WIFI_P2P_MANAGER
|| Protocol.BASE_WIFI_P2P_SERVICE <= message.what
- || message.what == WifiP2pManager.UPDATE_CHANNEL_INFO) {
+ || message.what == WifiP2pManager.UPDATE_CHANNEL_INFO
+ || message.what == WifiP2pManager.SET_WFD_INFO) {
return NOT_HANDLED;
}
// If P2P is not ready, it might be disabled due
@@ -3738,11 +3756,7 @@
}
config.groupOwnerIntent = selectGroupOwnerIntentIfNecessary(config);
boolean action;
- if (triggerType == P2P_CONNECT_TRIGGER_GROUP_NEG_REQ) {
- // If this is called from the GO negotiation path, the sender initiated
- // a group negotiation.
- action = FORM_GROUP;
- } else if (triggerType == P2P_CONNECT_TRIGGER_INVITATION_REQ) {
+ if (triggerType == P2P_CONNECT_TRIGGER_INVITATION_REQ) {
// The group owner won't report it is a Group Owner always.
// If this is called from the invitation path, the sender should be in
// a group, and the target should be a group owner.
@@ -4070,6 +4084,10 @@
mServiceTransactionId = 0;
mServiceDiscReqId = null;
+ if (null != mThisDevice.wfdInfo) {
+ setWfdInfo(mThisDevice.wfdInfo);
+ }
+
updatePersistentNetworks(RELOAD);
enableVerboseLogging(mSettingsConfigStore.get(WIFI_VERBOSE_LOGGING_ENABLED));
}
diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java
index d09e798..4f881e1 100644
--- a/service/java/com/android/server/wifi/util/ApConfigUtil.java
+++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java
@@ -713,6 +713,17 @@
}
/**
+ * Helper function to get HAL support STA + bridged AP or not.
+ *
+ * @param context the caller context used to get value from resource file.
+ * @return true if supported, false otherwise.
+ */
+ public static boolean isStaWithBridgedModeSupported(@NonNull Context context) {
+ return SdkLevel.isAtLeastS() && context.getResources().getBoolean(
+ R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported);
+ }
+
+ /**
* Helper function to get HAL support client force disconnect or not.
*
* @param context the caller context used to get value from resource file.
diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java
index 92e5d35..ebcf379 100644
--- a/service/java/com/android/server/wifi/util/InformationElementUtil.java
+++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java
@@ -36,6 +36,7 @@
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
+import java.util.Locale;
public class InformationElementUtil {
private static final String TAG = "InformationElementUtil";
@@ -1704,4 +1705,58 @@
return sbuf.toString();
}
}
+
+ /**
+ * This util class determines country related information in beacon/probe response
+ */
+ public static class Country {
+ private boolean mValid = false;
+ public String mCountryCode = "00";
+
+ /**
+ * Parse the Information Element Country Information field. Note that element ID and length
+ * fields are already removed.
+ *
+ * Country IE format (size unit: byte)
+ *
+ * ElementID | Length | country string | triplet | padding
+ * 1 1 3 Q*x 0 or 1
+ * First two bytes of country string are country code
+ * See 802.11 spec dot11CountryString definition.
+ */
+ public void from(InformationElement ie) {
+ mValid = false;
+ if (ie == null || ie.bytes == null || ie.bytes.length < 3) return;
+ ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN);
+ try {
+ char letter1 = (char) (data.get() & Constants.BYTE_MASK);
+ char letter2 = (char) (data.get() & Constants.BYTE_MASK);
+ char letter3 = (char) (data.get() & Constants.BYTE_MASK);
+ // See 802.11 spec dot11CountryString definition.
+ // ' ', 'O', 'I' are for all operation, outdoor, indoor environments, respectively.
+ mValid = (letter3 == ' ' || letter3 == 'O' || letter3 == 'I')
+ && Character.isLetterOrDigit((int) letter1)
+ && Character.isLetterOrDigit((int) letter2);
+ if (mValid) {
+ mCountryCode = (String.valueOf(letter1) + letter2).toUpperCase(Locale.US);
+ }
+ } catch (BufferUnderflowException e) {
+ return;
+ }
+ }
+
+ /**
+ * Is this a valid country information element.
+ */
+ public boolean isValid() {
+ return mValid;
+ }
+
+ /**
+ * @return country code indicated in beacon/probe response frames
+ */
+ public String getCountryCode() {
+ return mCountryCode;
+ }
+ }
}
diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto
index 35db206..cc8b154 100644
--- a/service/proto/src/metrics.proto
+++ b/service/proto/src/metrics.proto
@@ -767,6 +767,13 @@
// Histogram corresponding to the number of times recent connection failure status are reported
// per WifiConfiguration.RecentFailureReason
repeated Int32Count recent_failure_association_status = 218;
+
+ // Histogram of country codes observed from scan results.
+ // Bucket WifiMetrics.COUNTRY_CODE_CONFLICT_WIFI_SCAN for the code conflict within scan results.
+ // Bucket WifiMetrics.COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY for the code conflict between wifi
+ // and telephony.
+ // Bucket value is capped to WifiMetrics.MAX_COUNTRY_CODE_COUNT.
+ repeated Int32Count country_code_scan_histogram = 219;
}
// Information that gets logged for every WiFi connection.
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
index 1b32b8d..d694d8a 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -2799,6 +2799,47 @@
assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
}
+ public void requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
+ ClientConnectivityRole role) throws Exception {
+ ConcreteClientModeManager additionalClientModeManager =
+ mock(ConcreteClientModeManager.class);
+ ExternalClientModeManagerRequestListener externalRequestListener = mock(
+ ExternalClientModeManagerRequestListener.class);
+ requestAdditionalClientModeManager(role, additionalClientModeManager,
+ externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
+
+ ArgumentCaptor<ClientModeManager> requestedClientModeManager =
+ ArgumentCaptor.forClass(ClientModeManager.class);
+ verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
+ assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
+
+ // set additional CMM connected to ssid2/bssid2
+ WifiConfiguration config2 = new WifiConfiguration();
+ config2.SSID = TEST_SSID_2;
+ when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
+ when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
+
+ // request for the same SSID/BSSID and expect the existing CMM to get returned twice.
+ if (role == ROLE_CLIENT_LOCAL_ONLY) {
+ mActiveModeWarden.requestLocalOnlyClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
+ } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
+ mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
+ } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
+ mActiveModeWarden.requestSecondaryTransientClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
+ }
+ mLooper.dispatchAll();
+
+ // Don't make another client mode manager.
+ verify(mWifiInjector, times(1))
+ .makeClientModeManager(any(), any(), eq(role), anyBoolean());
+ // Returns the existing client mode manager.
+ verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
+ assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
+ }
+
private void requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
ClientConnectivityRole role) throws Exception {
enterClientModeActiveState();
@@ -2900,6 +2941,18 @@
}
@Test
+ public void requestLocalOnlyClientModeManagerWhenAlreadyPresentSameBssid() throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
+ .thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
+ TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
+
+ requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(ROLE_CLIENT_LOCAL_ONLY);
+ }
+
+ @Test
public void requestLocalOnlyClientModeManagerWhenConnectingToPrimaryBssid() throws Exception {
// Ensure that we can create more client ifaces.
when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
@@ -3002,6 +3055,20 @@
}
@Test
+ public void requestSecondaryLongLivedClientModeManagerWhenAlreadyPresentSameBssid()
+ throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
+ .thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
+ TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
+
+ requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
+ ROLE_CLIENT_SECONDARY_LONG_LIVED);
+ }
+
+ @Test
public void requestSecondaryLongLivedClientModeManagerWhenConnectingToPrimaryBssid()
throws Exception {
// Ensure that we can create more client ifaces.
@@ -3078,6 +3145,21 @@
}
@Test
+ public void requestSecondaryTransientClientModeManagerWhenAlreadyPresentSameBssid()
+ throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ when(mResources.getBoolean(
+ R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
+ .thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
+ TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
+
+ requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
+ ROLE_CLIENT_SECONDARY_TRANSIENT);
+ }
+
+ @Test
public void requestSecondaryTransientClientModeManagerWhenConnectingToPrimaryBssid()
throws Exception {
// Ensure that we can create more client ifaces.
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 3d6fa8f..6d913a1 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -5171,6 +5171,7 @@
mCmi.sendMessage(ClientModeImpl.CMD_START_FILS_CONNECTION, 0, 0,
Collections.singletonList(l2Packet));
mLooper.dispatchAll();
+ assertEquals("L2ConnectingState", mCmi.getCurrentState().getName());
}
/**
@@ -5278,6 +5279,7 @@
mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, TEST_BSSID_STR);
mLooper.dispatchAll();
+ assertEquals("L2ConnectingState", mCmi.getCurrentState().getName());
prepareFilsHlpPktAndSendStartConnect();
diff --git a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index 5006fc9..a0c4bf1 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -269,6 +269,9 @@
when(mWifiNative.getApFactoryMacAddress(any())).thenReturn(TEST_INTERFACE_MAC_ADDRESS);
when(mWifiApConfigStore.randomizeBssidIfUnset(any(), any())).thenAnswer(
(invocation) -> invocation.getArgument(1));
+ // Default init STA enabled
+ when(mResources.getBoolean(R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported))
+ .thenReturn(true);
when(mActiveModeWarden.getClientModeManagers())
.thenReturn(mTestClientModeManagers);
mTestClientModeManagers.add(mPrimaryConcreteClientModeManager);
@@ -2861,7 +2864,6 @@
@Test
public void testBridgedModeFallbackToSingleModeDueToCoexIsHardUnsafe()
throws Exception {
- //leslee
assumeTrue(SdkLevel.isAtLeastS());
int[] dual_bands = {SoftApConfiguration.BAND_2GHZ,
SoftApConfiguration.BAND_5GHZ};
@@ -3147,4 +3149,24 @@
mLooper.dispatchAll();
verify(mWifiNative, never()).setApCountryCode(any(), any());
}
+
+ @Test
+ public void testFallbackToSingleModeDueToStaExistButStaWithBridgedApNotSupported()
+ throws Exception {
+ assumeTrue(SdkLevel.isAtLeastS());
+ when(mResources.getBoolean(R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported))
+ .thenReturn(false);
+ int[] dual_bands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ};
+ Builder configBuilder = new SoftApConfiguration.Builder();
+ configBuilder.setSsid(TEST_SSID);
+ configBuilder.setBands(dual_bands);
+
+ SoftApModeConfiguration apConfig = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(),
+ mTestSoftApCapability);
+ // Reset band to 2.4G | 5G to generate expected configuration since it should fallback to
+ // single AP mode
+ configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
+ startSoftApAndVerifyEnabled(apConfig, TEST_COUNTRY_CODE, configBuilder.build());
+ }
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
index 7d429b3..6ef8b54 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
@@ -1266,6 +1266,42 @@
}
/**
+ * Tests the handling of association rejection for WPA3-Personal networks
+ */
+ @Test
+ public void testWpa3AuthRejectionEverConnected() throws Exception {
+ executeAndValidateInitializationSequence();
+ assertNotNull(mISupplicantStaIfaceCallback);
+
+ WifiConfiguration config = executeAndValidateConnectSequenceWithKeyMgmt(
+ SUPPLICANT_NETWORK_ID, false,
+ WifiConfiguration.SECURITY_TYPE_SAE, null, true);
+ mISupplicantStaIfaceCallback.onStateChanged(
+ ISupplicantStaIfaceCallback.State.ASSOCIATING,
+ NativeUtil.macAddressToByteArray(BSSID),
+ SUPPLICANT_NETWORK_ID,
+ NativeUtil.decodeSsid(SUPPLICANT_SSID));
+ int statusCode = ISupplicantStaIfaceCallback.StatusCode.UNSPECIFIED_FAILURE;
+ mISupplicantStaIfaceCallback.onAssociationRejected(
+ NativeUtil.macAddressToByteArray(BSSID), statusCode, false);
+ verify(mWifiMonitor, never()).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME),
+ anyInt(), anyInt());
+ ArgumentCaptor<AssocRejectEventInfo> assocRejectEventInfoCaptor =
+ ArgumentCaptor.forClass(AssocRejectEventInfo.class);
+ verify(mWifiMonitor).broadcastAssociationRejectionEvent(
+ eq(WLAN0_IFACE_NAME), assocRejectEventInfoCaptor.capture());
+ AssocRejectEventInfo assocRejectEventInfo =
+ (AssocRejectEventInfo) assocRejectEventInfoCaptor.getValue();
+ assertNotNull(assocRejectEventInfo);
+ assertEquals(SUPPLICANT_SSID, assocRejectEventInfo.ssid);
+ assertEquals(BSSID, assocRejectEventInfo.bssid);
+ assertEquals(statusCode, assocRejectEventInfo.statusCode);
+ assertFalse(assocRejectEventInfo.timedOut);
+ assertNull(assocRejectEventInfo.oceRssiBasedAssocRejectInfo);
+ assertNull(assocRejectEventInfo.mboAssocDisallowedInfo);
+ }
+
+ /**
* Tests the handling of incorrect network passwords for WEP networks.
*/
@Test
@@ -2926,11 +2962,12 @@
* @param haveExistingNetwork Removes the existing network.
* @param securityType The security type.
* @param wepKey if configurations are for a WEP network else null.
+ * @param hasEverConnected indicate that this configuration is ever connected or not.
* @return the WifiConfiguration object of the new network to connect.
*/
private WifiConfiguration executeAndValidateConnectSequenceWithKeyMgmt(
final int newFrameworkNetworkId, final boolean haveExistingNetwork,
- int securityType, String wepKey) throws Exception {
+ int securityType, String wepKey, boolean hasEverConnected) throws Exception {
setupMocksForConnectSequence(haveExistingNetwork);
WifiConfiguration config = new WifiConfiguration();
config.setSecurityParams(securityType);
@@ -2940,6 +2977,7 @@
WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
new WifiConfiguration.NetworkSelectionStatus();
networkSelectionStatus.setCandidateSecurityParams(config.getSecurityParams(securityType));
+ networkSelectionStatus.setHasEverConnected(hasEverConnected);
config.setNetworkSelectionStatus(networkSelectionStatus);
assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
validateConnectSequence(haveExistingNetwork, 1);
@@ -2947,6 +2985,23 @@
}
/**
+ * Helper function to execute all the actions to perform connection to the network.
+ *
+ * @param newFrameworkNetworkId Framework Network Id of the new network to connect.
+ * @param haveExistingNetwork Removes the existing network.
+ * @param securityType The security type.
+ * @param wepKey if configurations are for a WEP network else null.
+ * @return the WifiConfiguration object of the new network to connect.
+ */
+ private WifiConfiguration executeAndValidateConnectSequenceWithKeyMgmt(
+ final int newFrameworkNetworkId, final boolean haveExistingNetwork,
+ int securityType, String wepKey) throws Exception {
+ return executeAndValidateConnectSequenceWithKeyMgmt(
+ newFrameworkNetworkId, haveExistingNetwork,
+ securityType, wepKey, false);
+ }
+
+ /**
* Setup mocks for roam sequence.
*/
private void setupMocksForRoamSequence(String roamBssid) throws Exception {
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index d2acbae..0606093 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -41,6 +41,7 @@
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
@@ -867,31 +868,6 @@
}
@Test
- public void secondaryLongLived_noSecondaryStaAvailable() {
- setupMocksForSecondaryLongLivedTests();
-
- // Set screen to on
- setScreenState(true);
-
- // OEM paid connection allowed.
- mWifiConnectivityManager.setOemPaidConnectionAllowed(true, new WorkSource());
-
- // STA + STA is supported, but not available.
- when(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
- any(), eq(ROLE_CLIENT_SECONDARY_LONG_LIVED))).thenReturn(false);
-
- // Set WiFi to disconnected state
- mWifiConnectivityManager.handleConnectionStateChanged(
- mPrimaryClientModeManager,
- WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
-
- verify(mPrimaryClientModeManager).startConnectToNetwork(
- CANDIDATE_NETWORK_ID, Process.WIFI_UID, "any");
- verify(mActiveModeWarden, never()).requestSecondaryLongLivedClientModeManager(
- any(), any(), any(), any());
- }
-
- @Test
public void secondaryLongLived_secondaryStaRequestReturnsNull() {
setupMocksForSecondaryLongLivedTests();
@@ -932,7 +908,7 @@
// OEM paid connection allowed.
mWifiConnectivityManager.setOemPaidConnectionAllowed(true, new WorkSource());
- // STA + STA is supported, but secondary STA request returns null
+ // STA + STA is supported, but secondary STA request returns the primary
doAnswer(new AnswerWithArguments() {
public void answer(ExternalClientModeManagerRequestListener listener,
WorkSource requestorWs, String ssid, String bssid) {
@@ -981,6 +957,19 @@
CANDIDATE_NETWORK_ID, Process.WIFI_UID, "any");
verify(mActiveModeWarden).requestSecondaryLongLivedClientModeManager(
any(), any(), any(), any());
+
+ // Simulate connection failing on the secondary
+ clearInvocations(mSecondaryClientModeManager, mPrimaryClientModeManager, mWifiNS);
+ mWifiConnectivityManager.handleConnectionAttemptEnded(
+ mSecondaryClientModeManager,
+ WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, CANDIDATE_BSSID,
+ CANDIDATE_SSID);
+ // verify connection is never restarted when a connection on the secondary STA fails.
+ verify(mWifiNS, never()).selectNetwork(any());
+ verify(mSecondaryClientModeManager, never()).startConnectToNetwork(
+ anyInt(), anyInt(), any());
+ verify(mPrimaryClientModeManager, never()).startConnectToNetwork(
+ anyInt(), anyInt(), any());
}
@Test
@@ -1055,6 +1044,55 @@
}
/**
+ * Verify that when the secondary is already connecting to the selected secondary network,
+ * we only connect the primary STA.
+ */
+ @Test
+ public void secondaryLongLived_secondaryStaRequestSucceedsWhenSecondaryAlreadyConnecting() {
+ setupMocksForSecondaryLongLivedTests();
+
+ // 2 candidates - 1 oem paid, other regular.
+ // Mark the first candidate oem private only
+ when(mCandidate1.isOemPaid()).thenReturn(false);
+ when(mCandidate1.isOemPrivate()).thenReturn(true);
+ mCandidateWifiConfig1.oemPaid = false;
+ mCandidateWifiConfig1.oemPrivate = true;
+
+ // mock secondary STA to already connecting to the target OEM private network
+ when(mSecondaryClientModeManager.getConnectingWifiConfiguration()).thenReturn(
+ mCandidateWifiConfig1);
+
+ // Add the second regular candidate.
+ mCandidateList.add(mCandidate2);
+
+ // Set screen to on
+ setScreenState(true);
+
+ // OEM paid connection allowed.
+ mWifiConnectivityManager.setOemPrivateConnectionAllowed(true, new WorkSource());
+
+ // Network selection setup for primary.
+ when(mWifiNS.selectNetwork(argThat(
+ candidates -> (candidates != null && candidates.size() == 1
+ // not oem paid or oem private.
+ && !(candidates.get(0).isOemPaid() || candidates.get(0).isOemPrivate()))
+ ))).thenReturn(mCandidateWifiConfig2);
+
+ // Set WiFi to disconnected state
+ mWifiConnectivityManager.handleConnectionStateChanged(
+ mPrimaryClientModeManager,
+ WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+
+ // connection triggered on only on primary to CANDIDATE_NETWORK_ID_2.
+ verify(mPrimaryClientModeManager).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID_2, Process.WIFI_UID, "any");
+ verify(mSecondaryClientModeManager, never()).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, "any");
+ verify(mActiveModeWarden).requestSecondaryLongLivedClientModeManager(
+ any(), any(), eq(CANDIDATE_SSID), any());
+ }
+
+ /**
* Wifi enters disconnected state while screen is on.
*
* Expected behavior: WifiConnectivityManager calls
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
index fda21db..c833bf4 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiCountryCodeTest.java
@@ -26,6 +26,7 @@
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.content.Context;
+import android.net.wifi.WifiInfo;
import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
@@ -41,6 +42,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
/**
@@ -62,7 +65,9 @@
@Mock ClientModeImplMonitor mClientModeImplMonitor;
@Mock WifiNative mWifiNative;
@Mock WifiSettingsConfigStore mSettingsConfigStore;
+ @Mock WifiInfo mWifiInfo;
private WifiCountryCode mWifiCountryCode;
+ private List<ClientModeManager> mClientManagerList;
@Captor
private ArgumentCaptor<ActiveModeWarden.ModeChangeCallback> mModeChangeCallbackCaptor;
@@ -80,8 +85,16 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mClientManagerList = new ArrayList<>();
+ mClientManagerList.add(mClientModeManager);
+ when(mActiveModeWarden.getInternetConnectivityClientModeManagers())
+ .thenReturn(mClientManagerList);
when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
when(mClientModeManager.setCountryCode(anyString())).thenReturn(true);
+ when(mClientModeManager.isConnected()).thenReturn(true);
+ when(mClientModeManager.syncRequestConnectionInfo()).thenReturn(mWifiInfo);
+ when(mWifiInfo.getSuccessfulTxPacketsPerSecond()).thenReturn(10.0);
+ when(mWifiInfo.getSuccessfulRxPacketsPerSecond()).thenReturn(5.0);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE))
.thenReturn(mTelephonyManager);
@@ -233,17 +246,34 @@
*/
@Test
public void telephonyCountryCodeChangeAfterL2Connected() throws Exception {
+ mWifiCountryCode.setDefaultCountryCode("00");
// Supplicant starts.
mModeChangeCallbackCaptor.getValue().onActiveModeManagerAdded(mClientModeManager);
// Wifi get L2 connected.
mClientModeImplListenerCaptor.getValue().onConnectionStart(mClientModeManager);
+
+ // Wifi traffic is high
+ when(mWifiInfo.getSuccessfulTxPacketsPerSecond()).thenReturn(20.0);
// Telephony country code arrives.
mWifiCountryCode.setTelephonyCountryCodeAndUpdate(mTelephonyCountryCode);
- // Telephony coutry code won't be applied at this time.
- assertEquals(mDefaultCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
+ // Telephony country code won't be applied at this time.
+ assertEquals("00", mWifiCountryCode.getCountryCodeSentToDriver());
+ // Wifi is not forced to disconnect
+ verify(mClientModeManager, times(0)).disconnect();
+
+ // Wifi traffic is low
+ when(mWifiInfo.getSuccessfulTxPacketsPerSecond()).thenReturn(10.0);
+ // Telephony country code arrives for multiple times
+ for (int i = 0; i < 3; i++) {
+ mWifiCountryCode.setTelephonyCountryCodeAndUpdate(mTelephonyCountryCode);
+ }
+ // Telephony country code still won't be applied.
+ assertEquals("00", mWifiCountryCode.getCountryCodeSentToDriver());
+ // Wifi is forced to disconnect
+ verify(mClientModeManager, times(1)).disconnect();
mClientModeImplListenerCaptor.getValue().onConnectionEnd(mClientModeManager);
- // Telephony coutry is applied after supplicant is ready.
+ // Telephony country is applied after supplicant is ready.
verify(mClientModeManager, times(2)).setCountryCode(anyString());
assertEquals(mTelephonyCountryCode, mWifiCountryCode.getCountryCodeSentToDriver());
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index abb08fa..6084a6c 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -196,6 +196,7 @@
@Mock PowerManager mPowerManager;
@Mock WifiMonitor mWifiMonitor;
@Mock ActiveModeWarden mActiveModeWarden;
+ @Mock TelephonyManager mTelephonyManager;
@Captor ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
@Captor ArgumentCaptor<ActiveModeWarden.ModeChangeCallback> mModeChangeCallbackArgumentCaptor;
@@ -211,6 +212,8 @@
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mTelephonyManager.getNetworkCountryIso()).thenReturn("US");
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
mWifiMetrics = new WifiMetrics(mContext, mFacade, mClock, mTestLooper.getLooper(),
new WifiAwareMetrics(mClock), new RttMetrics(mClock), mWifiPowerMetrics,
mWifiP2pMetrics, mDppMetrics, mWifiMonitor);
@@ -3218,6 +3221,46 @@
}
/**
+ * Test that country code stats are collected correctly
+ */
+ @Test
+ public void testCountryCodeStats() throws Exception {
+ ScanDetail mockScanDetailUs = mock(ScanDetail.class);
+ ScanDetail mockScanDetailNonUs = mock(ScanDetail.class);
+ NetworkDetail mockNetworkDetailUs = mock(NetworkDetail.class);
+ NetworkDetail mockNetworkDetailNonUs = mock(NetworkDetail.class);
+ when(mockNetworkDetailUs.getCountryCode()).thenReturn("US");
+ when(mockNetworkDetailNonUs.getCountryCode()).thenReturn("CA");
+ ScanResult mockScanResult = mock(ScanResult.class);
+ mockScanResult.capabilities = "";
+ when(mockScanDetailUs.getScanResult()).thenReturn(mockScanResult);
+ when(mockScanDetailNonUs.getScanResult()).thenReturn(mockScanResult);
+ when(mockScanDetailUs.getNetworkDetail()).thenReturn(mockNetworkDetailUs);
+ when(mockScanDetailNonUs.getNetworkDetail()).thenReturn(mockNetworkDetailNonUs);
+ List<ScanDetail> scan = new ArrayList<ScanDetail>();
+
+ for (int i = 0; i < (WifiMetrics.MAX_COUNTRY_CODE_COUNT + 1); i++) {
+ scan.add(mockScanDetailUs);
+ }
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+ when(mTelephonyManager.getNetworkCountryIso()).thenReturn("CA");
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+ scan.add(mockScanDetailNonUs);
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+
+ dumpProtoAndDeserialize();
+
+ Int32Count[] expectedCountryCodeScanHistogram = {
+ buildInt32Count(WifiMetrics.COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY, 1),
+ buildInt32Count(WifiMetrics.COUNTRY_CODE_CONFLICT_WIFI_SCAN, 1),
+ buildInt32Count(WifiMetrics.MAX_COUNTRY_CODE_COUNT, 1),
+ };
+ assertKeyCountsEqual(expectedCountryCodeScanHistogram,
+ mDecodedProto.countryCodeScanHistogram);
+ }
+
+
+ /**
* Test Open Network Notification blocklist size and feature state are not cleared when proto
* is dumped.
*/
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
index d48d72a..0df19c0 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
@@ -144,6 +144,8 @@
mWifiInfo.setSSID(TEST_SSID_1);
mWifiInfo.setBSSID(TEST_BSSID_1.toString());
mWifiInfo.setNetworkId(TEST_NETWORK_CONFIG_ID);
+ mWifiInfo.setTxLinkSpeedMbps(866);
+ mWifiInfo.setRxLinkSpeedMbps(866);
mWifiInfo.setMaxSupportedTxLinkSpeedMbps(866);
mWifiInfo.setMaxSupportedRxLinkSpeedMbps(866);
millisecondsPass(0);
@@ -1785,7 +1787,7 @@
@Test
public void testLinkBandwidthLargeByteCountReturnNonNegativeValue() {
mWifiInfo.setRssi(-70);
- mWifiInfo.setMaxSupportedRxLinkSpeedMbps(200_000);
+ mWifiInfo.setRxLinkSpeedMbps(200_000);
mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
mWifiInfo.setFrequency(5210);
@@ -1816,7 +1818,7 @@
}
// Report cold start BW for Tx because the calculated value is higher than
- // maxSupportedTxLinkSpeedMbps.
+ // txLinkSpeedMbps.
assertEquals(10_000, perNetwork.getTxLinkBandwidthKbps());
assertEquals(128_000_000, perNetwork.getRxLinkBandwidthKbps());
@@ -1841,9 +1843,8 @@
}
@Test
- public void testLinkBandwidthResetInvalidStats() {
+ public void testLinkBandwidthInvalidBytes() {
mWifiInfo.setRssi(-70);
- mWifiInfo.setMaxSupportedRxLinkSpeedMbps(200_000);
mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
mWifiScoreCard.noteIpConfiguration(mWifiInfo);
@@ -1858,16 +1859,8 @@
millisecondsPass(3_000);
perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo);
}
- assertEquals(128_000_000, perNetwork.getRxLinkBandwidthKbps());
- // Reduce max supported Rx link speed so that stats in the memory become invalid
- // and fall back to cold start values
- mWifiInfo.setMaxSupportedRxLinkSpeedMbps(100);
- for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
- addTotalBytes(txBytes, rxBytes);
- millisecondsPass(3_000);
- perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo);
- }
- assertEquals(10_070, perNetwork.getRxLinkBandwidthKbps());
+ assertEquals(10_000, perNetwork.getTxLinkBandwidthKbps());
+ assertEquals(10_000, perNetwork.getRxLinkBandwidthKbps());
}
@Test
diff --git a/service/tests/wifitests/src/com/android/server/wifi/coex/CoexManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/coex/CoexManagerTest.java
index fbddee8..18ee415 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/coex/CoexManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/coex/CoexManagerTest.java
@@ -867,4 +867,34 @@
// The remote callback has an extra call since it was notified on registration.
verify(remoteCallback, times(4)).onCoexUnsafeChannelsChanged(any(), anyInt());
}
+
+ /**
+ * Verify that multiple calls to setCoexUnsafeChannels with the same unsafe channels will only
+ * update the driver the first time.
+ */
+ @Test
+ public void testSetCoexUnsafeChannels_multipleSameChannels_updatesDriverOnce() {
+ CoexManager coexManager = createCoexManager();
+
+ coexManager.setCoexUnsafeChannels(new ArrayList<>(), 0);
+ coexManager.setCoexUnsafeChannels(new ArrayList<>(), 0);
+ coexManager.setCoexUnsafeChannels(new ArrayList<>(), 0);
+ // Default state after initialization is no channels and no restrictions, so no update to
+ // the driver is necessary
+ verify(mMockWifiNative, times(0)).setCoexUnsafeChannels(any(), anyInt());
+
+ coexManager.setCoexUnsafeChannels(
+ Arrays.asList(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)), COEX_RESTRICTION_SOFTAP);
+ coexManager.setCoexUnsafeChannels(
+ Arrays.asList(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)), COEX_RESTRICTION_SOFTAP);
+ coexManager.setCoexUnsafeChannels(
+ Arrays.asList(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)), COEX_RESTRICTION_SOFTAP);
+ // Driver should be updated only once for the same unsafe channels
+ verify(mMockWifiNative, times(1)).setCoexUnsafeChannels(any(), anyInt());
+
+ // Change in restrictions with same unsafe channels should trigger an update
+ coexManager.setCoexUnsafeChannels(
+ Arrays.asList(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)), 0);
+ verify(mMockWifiNative, times(2)).setCoexUnsafeChannels(any(), anyInt());
+ }
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
index 69413ab..20eeea8 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
@@ -3285,25 +3285,6 @@
}
/**
- * Verify WifiP2pManager.SET_WFD_INFO_FAILED is returned when p2p is disabled.
- */
- @Test
- public void testSetWfdInfoFailureWhenP2pDisabled() throws Exception {
- mTestThisDevice.wfdInfo = new WifiP2pWfdInfo();
- when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
- when(mWifiPermissionsWrapper.getUidPermission(anyString(), anyInt()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
- sendSetWfdInfoMsg(mClientMessenger, mTestThisDevice.wfdInfo);
- verify(mWifiInjector).getWifiPermissionsWrapper();
- verify(mWifiPermissionsWrapper).getUidPermission(
- eq(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY), anyInt());
- verify(mClientHandler).sendMessage(mMessageCaptor.capture());
- Message message = mMessageCaptor.getValue();
- assertEquals(WifiP2pManager.SET_WFD_INFO_FAILED, message.what);
- assertEquals(WifiP2pManager.BUSY, message.arg1);
- }
-
- /**
* Verify WifiP2pManager.SET_WFD_INFO_FAILED is returned when wfd permission denied
* and p2p is disabled.
*/
@@ -4529,4 +4510,109 @@
verify(mWifiNative).teardownInterface();
verify(mWifiMonitor).stopMonitoring(anyString());
}
+
+ /**
+ * Verify the WFD info is set again on going back to P2pEnabledState
+ * for the IdleShutdown case.
+ */
+ @Test
+ public void testWfdInfoIsSetAtP2pEnabledStateForIdleShutdown() throws Exception {
+ // Move to enabled state
+ forceP2pEnabled(mClient1);
+ mTestThisDevice.status = mTestThisDevice.AVAILABLE;
+
+ mTestThisDevice.wfdInfo = new WifiP2pWfdInfo();
+ mTestThisDevice.wfdInfo.setEnabled(true);
+ when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+ when(mWifiPermissionsWrapper.getUidPermission(anyString(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mWifiNative.setWfdEnable(anyBoolean())).thenReturn(true);
+ when(mWifiNative.setWfdDeviceInfo(anyString())).thenReturn(true);
+ sendSetWfdInfoMsg(mClientMessenger, mTestThisDevice.wfdInfo);
+
+ // P2P is off due to IDLE and data should be kept for the resume.
+ mWifiP2pServiceImpl.mP2pIdleShutdownMessage.onAlarm();
+ mLooper.dispatchAll();
+ verify(mWifiNative).teardownInterface();
+ verify(mWifiMonitor).stopMonitoring(anyString());
+ sendSimpleMsg(null, WifiP2pMonitor.SUP_DISCONNECTION_EVENT);
+
+ reset(mWifiNative);
+ when(mWifiNative.setupInterface(any(), any(), any())).thenReturn(IFACE_NAME_P2P);
+ when(mWifiNative.setWfdEnable(anyBoolean())).thenReturn(true);
+ when(mWifiNative.setWfdDeviceInfo(anyString())).thenReturn(true);
+
+ // send a command to resume P2P
+ sendSimpleMsg(mClientMessenger, WifiP2pManager.REQUEST_P2P_STATE);
+
+ // Restore data for resuming from idle shutdown.
+ verify(mWifiNative).setWfdEnable(eq(true));
+ verify(mWifiNative).setWfdDeviceInfo(eq(mTestThisDevice.wfdInfo.getDeviceInfoHex()));
+ }
+
+ /**
+ * Verify the WFD info is set again on going back to P2pEnabledState
+ * for the normal shutdown case.
+ */
+ @Test
+ public void testWfdInfoIsSetAtP2pEnabledStateForNormalShutdown() throws Exception {
+ // Move to enabled state
+ forceP2pEnabled(mClient1);
+ mTestThisDevice.status = mTestThisDevice.AVAILABLE;
+
+ mTestThisDevice.wfdInfo = new WifiP2pWfdInfo();
+ mTestThisDevice.wfdInfo.setEnabled(true);
+ when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+ when(mWifiPermissionsWrapper.getUidPermission(anyString(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mWifiNative.setWfdEnable(anyBoolean())).thenReturn(true);
+ when(mWifiNative.setWfdDeviceInfo(anyString())).thenReturn(true);
+ sendSetWfdInfoMsg(mClientMessenger, mTestThisDevice.wfdInfo);
+
+ // P2P is really disabled when wifi is off.
+ simulateWifiStateChange(false);
+ mLooper.dispatchAll();
+ verify(mWifiNative).teardownInterface();
+ verify(mWifiMonitor).stopMonitoring(anyString());
+
+ reset(mWifiNative);
+ when(mWifiNative.setupInterface(any(), any(), any())).thenReturn(IFACE_NAME_P2P);
+ when(mWifiNative.setWfdEnable(anyBoolean())).thenReturn(true);
+ when(mWifiNative.setWfdDeviceInfo(anyString())).thenReturn(true);
+
+ // send a command to resume P2P
+ sendSimpleMsg(mClientMessenger, WifiP2pManager.REQUEST_P2P_STATE);
+ mLooper.dispatchAll();
+
+ // In normal case, wfd info is cleared.
+ verify(mWifiNative, never()).setWfdEnable(anyBoolean());
+ verify(mWifiNative, never()).setWfdDeviceInfo(anyString());
+ }
+
+ /**
+ * Verify the WFD info is set if WFD info is set at P2pDisabledState.
+ */
+ @Test
+ public void testWfdInfoIsSetAtP2pEnabledWithPreSetWfdInfo() throws Exception {
+ mTestThisDevice.wfdInfo = new WifiP2pWfdInfo();
+ mTestThisDevice.wfdInfo.setEnabled(true);
+ when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+ when(mWifiPermissionsWrapper.getUidPermission(anyString(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mWifiNative.setWfdEnable(anyBoolean())).thenReturn(true);
+ when(mWifiNative.setWfdDeviceInfo(anyString())).thenReturn(true);
+ sendSetWfdInfoMsg(mClientMessenger, mTestThisDevice.wfdInfo);
+
+ // At disabled state, WFD info is stored in the service, but not set actually.
+ verify(mWifiNative, never()).setWfdEnable(anyBoolean());
+ verify(mWifiNative, never()).setWfdDeviceInfo(any());
+
+ // Move to enabled state
+ forceP2pEnabled(mClient1);
+ mTestThisDevice.status = mTestThisDevice.AVAILABLE;
+
+ // Restore data for resuming from idle shutdown.
+ verify(mWifiNative).setWfdEnable(eq(true));
+ verify(mWifiNative).setWfdDeviceInfo(eq(mTestThisDevice.wfdInfo.getDeviceInfoHex()));
+ }
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
index 942adbc..43169f1 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
@@ -1836,5 +1836,22 @@
2412, 72000000, true, true, true, false));
}
+ /**
+ * Verify that the country code is parsed correctly from country IE
+ */
+ @Test
+ public void getCountryCodeWithCountryIE() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_EXTENSION_PRESENT;
+ /** Country IE format (size unit: byte)
+ *
+ * |ElementID | Length | country string | triplet | padding
+ * 1 1 3 Q*x 0 or 1
+ */
+ ie.bytes = new byte[]{(byte) 0x75, (byte) 0x73, (byte) 0x49};
+ InformationElementUtil.Country country = new InformationElementUtil.Country();
+ country.from(ie);
+ assertEquals("US", country.getCountryCode());
+ }
// TODO: SAE, OWN, SUITE_B
}