summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--WifiDialog/AndroidManifest.xml1
-rw-r--r--WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java28
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java130
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java34
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java8
-rw-r--r--service/java/com/android/server/wifi/WifiBlocklistMonitor.java20
-rw-r--r--service/java/com/android/server/wifi/WifiDialogManager.java19
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java1
-rw-r--r--service/java/com/android/server/wifi/WifiMonitor.java21
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java72
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java93
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java25
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java39
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java6
14 files changed, 414 insertions, 83 deletions
diff --git a/WifiDialog/AndroidManifest.xml b/WifiDialog/AndroidManifest.xml
index 66132822c6..dfeafabda0 100644
--- a/WifiDialog/AndroidManifest.xml
+++ b/WifiDialog/AndroidManifest.xml
@@ -42,6 +42,7 @@
android:configChanges="keyboardHidden|screenSize"
android:hardwareAccelerated="true"
android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight" />
</application>
</manifest>
diff --git a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
index 5afd315036..c73afa9134 100644
--- a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
+++ b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
@@ -37,7 +37,6 @@ import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
-import android.os.Process;
import android.os.SystemClock;
import android.os.Vibrator;
import android.text.Editable;
@@ -72,8 +71,6 @@ import java.util.Set;
* Main Activity of the WifiDialog application. All dialogs should be created and managed from here.
*/
public class WifiDialogActivity extends Activity {
- private static int sNumActiveInstances = 0;
-
private static final String TAG = "WifiDialog";
private static final String KEY_DIALOG_INTENTS = "KEY_DIALOG_INTENTS";
private static final String EXTRA_DIALOG_EXPIRATION_TIME_MS =
@@ -213,10 +210,6 @@ public class WifiDialogActivity extends Activity {
@Override
protected void onStart() {
super.onStart();
- sNumActiveInstances++;
- if (mIsVerboseLoggingEnabled) {
- Log.v(TAG, "onStart() incrementing sActiveInstances to " + sNumActiveInstances);
- }
registerReceiver(
mCloseSystemDialogsReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
ArraySet<Integer> invalidDialogIds = new ArraySet<>();
@@ -260,10 +253,6 @@ public class WifiDialogActivity extends Activity {
@Override
protected void onStop() {
super.onStop();
- sNumActiveInstances--;
- if (mIsVerboseLoggingEnabled) {
- Log.v(TAG, "onStop() decrementing sActiveInstances to " + sNumActiveInstances);
- }
unregisterReceiver(mCloseSystemDialogsReceiver);
if (isChangingConfigurations()) {
@@ -328,23 +317,6 @@ public class WifiDialogActivity extends Activity {
}
}
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (isFinishing()) {
- if (sNumActiveInstances > 0) {
- if (mIsVerboseLoggingEnabled) {
- Log.v(TAG, "Finished with sNumActiveInstances: " + sNumActiveInstances);
- }
- return;
- }
- if (mIsVerboseLoggingEnabled) {
- Log.v(TAG, "Finished with no active instances left. Killing process.");
- }
- Process.killProcess(android.os.Process.myPid());
- }
- }
-
/**
* Creates and shows a dialog for the given dialogId and Intent.
* Returns {@code true} if the dialog was successfully created, {@code false} otherwise.
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 0c8d70453a..8fd71c5fb7 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -37,6 +37,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.BroadcastOptions;
import android.app.admin.SecurityLog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -2755,10 +2756,18 @@ public class ClientModeImpl extends StateMachine implements ClientMode {
Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
+ final BroadcastOptions opts;
+ if (SdkLevel.isAtLeastU()) {
+ opts = BroadcastOptions.makeBasic();
+ opts.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+ } else {
+ opts = null;
+ }
mBroadcastQueue.queueOrSendBroadcast(
mClientModeManager,
() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.ACCESS_WIFI_STATE));
+ android.Manifest.permission.ACCESS_WIFI_STATE,
+ opts == null ? null : opts.toBundle()));
}
private void sendLinkConfigurationChangedBroadcast() {
@@ -2999,6 +3008,69 @@ public class ClientModeImpl extends StateMachine implements ClientMode {
updateCurrentConnectionInfo();
}
+ /**
+ * Update mapping of affiliated BSSID in blocklist. Called when there is a change in MLO links.
+ */
+ private void updateBlockListAffiliatedBssids() {
+ /**
+ * getAffiliatedMloLinks() returns a list of MloLink objects for all the links
+ * advertised by AP-MLD including the associated link. Update mWifiBlocklistMonitor
+ * with all affiliated AP link MAC addresses, excluding the associated link, indexed
+ * with associated AP link MAC address (BSSID).
+ * For e.g.
+ * link1_bssid -> affiliated {link2_bssid, link3_bssid}
+ * Above mapping is used to block list all affiliated links when associated link is
+ * block listed.
+ */
+ List<String> affiliatedBssids = new ArrayList<>();
+ for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) {
+ if (!Objects.equals(mWifiInfo.getBSSID(), link.getApMacAddress().toString())) {
+ affiliatedBssids.add(link.getApMacAddress().toString());
+ }
+ }
+ mWifiBlocklistMonitor.setAffiliatedBssids(mWifiInfo.getBSSID(), affiliatedBssids);
+ }
+
+ /**
+ * Clear MLO link states to UNASSOCIATED.
+ */
+ private void clearMloLinkStates() {
+ for (MloLink link : mWifiInfo.getAffiliatedMloLinks()) {
+ link.setState(MloLink.MLO_LINK_STATE_UNASSOCIATED);
+ }
+ }
+
+ /**
+ * Update the MLO link states to ACTIVE or IDLE depending on any traffic stream is mapped to the
+ * link.
+ *
+ * @param info MLO link object from HAL.
+ */
+ private void updateMloLinkStates(@Nullable WifiNative.ConnectionMloLinksInfo info) {
+ if (info == null) return;
+ for (int i = 0; i < info.links.length; i++) {
+ mWifiInfo.updateMloLinkState(info.links[i].getLinkId(),
+ info.links[i].isAnyTidMapped() ? MloLink.MLO_LINK_STATE_ACTIVE
+ : MloLink.MLO_LINK_STATE_IDLE);
+ }
+ }
+ /**
+ * Update the MLO link states to ACTIVE or IDLE depending on any traffic stream is mapped to the
+ * link. Also, update the link MAC address.
+ *
+ * @param info MLO link object from HAL.
+ */
+ private void updateMloLinkAddrAndStates(@Nullable WifiNative.ConnectionMloLinksInfo info) {
+ if (info == null) return;
+ for (int i = 0; i < info.links.length; i++) {
+ mWifiInfo.updateMloLinkStaAddress(info.links[i].getLinkId(),
+ info.links[i].getMacAddress());
+ mWifiInfo.updateMloLinkState(info.links[i].getLinkId(),
+ info.links[i].isAnyTidMapped() ? MloLink.MLO_LINK_STATE_ACTIVE
+ : MloLink.MLO_LINK_STATE_IDLE);
+ }
+ }
+
private void updateWifiInfoLinkParamsAfterAssociation() {
mLastConnectionCapabilities = mWifiNative.getConnectionCapabilities(mInterfaceName);
int maxTxLinkSpeedMbps = mThroughputPredictor.predictMaxTxThroughput(
@@ -3011,34 +3083,8 @@ public class ClientModeImpl extends StateMachine implements ClientMode {
mWifiMetrics.setConnectionMaxSupportedLinkSpeedMbps(mInterfaceName,
maxTxLinkSpeedMbps, maxRxLinkSpeedMbps);
if (mLastConnectionCapabilities.wifiStandard == ScanResult.WIFI_STANDARD_11BE) {
- WifiNative.ConnectionMloLinksInfo info =
- mWifiNative.getConnectionMloLinksInfo(mInterfaceName);
- if (info != null) {
- for (int i = 0; i < info.links.length; i++) {
- mWifiInfo.updateMloLinkStaAddress(info.links[i].linkId,
- info.links[i].staMacAddress);
- mWifiInfo.updateMloLinkState(
- info.links[i].linkId, MloLink.MLO_LINK_STATE_ACTIVE);
- }
- /**
- * getAffiliatedMloLinks() returns a list of MloLink objects for all the links
- * advertised by AP-MLD including the associated link. Update mWifiBlocklistMonitor
- * with all affiliated AP link MAC addresses, excluding the associated link, indexed
- * with associated AP link MAC address (BSSID).
- * For e.g.
- * link1_bssid -> affiliated {link2_bssid, link3_bssid}
- * Above mapping is used to block list all affiliated links when associated link is
- * block listed.
- */
- List<MloLink> links = mWifiInfo.getAffiliatedMloLinks();
- List<String> affiliatedBssids = new ArrayList<>();
- for (MloLink link: links) {
- if (!Objects.equals(mWifiInfo.getBSSID(), link.getApMacAddress().toString())) {
- affiliatedBssids.add(link.getApMacAddress().toString());
- }
- }
- mWifiBlocklistMonitor.setAffiliatedBssids(mWifiInfo.getBSSID(), affiliatedBssids);
- }
+ updateMloLinkAddrAndStates(mWifiNative.getConnectionMloLinksInfo(mInterfaceName));
+ updateBlockListAffiliatedBssids();
}
if (mVerboseLoggingEnabled) {
StringBuilder sb = new StringBuilder();
@@ -6128,6 +6174,32 @@ public class ClientModeImpl extends StateMachine implements ClientMode {
}
break;
}
+ case WifiMonitor.MLO_LINKS_INFO_CHANGED:
+ WifiMonitor.MloLinkInfoChangeReason reason =
+ (WifiMonitor.MloLinkInfoChangeReason) message.obj;
+ WifiNative.ConnectionMloLinksInfo newInfo =
+ mWifiNative.getConnectionMloLinksInfo(mInterfaceName);
+ if (reason == WifiMonitor.MloLinkInfoChangeReason.TID_TO_LINK_MAP) {
+ // Traffic stream mapping changed. Update link states.
+ updateMloLinkStates(newInfo);
+ // There is a change in link capabilities. Will trigger android.net
+ // .ConnectivityManager.NetworkCallback.onCapabilitiesChanged().
+ updateCapabilities();
+ } else if (reason
+ == WifiMonitor.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL) {
+ // Link is removed. Set removed link state to MLO_LINK_STATE_UNASSOCIATED.
+ // Also update block list mapping, as there is a change in affiliated
+ // BSSIDs.
+ clearMloLinkStates();
+ updateMloLinkStates(newInfo);
+ updateBlockListAffiliatedBssids();
+ // There is a change in link capabilities. Will trigger android.net
+ // .ConnectivityManager.NetworkCallback.onCapabilitiesChanged().
+ updateCapabilities();
+ } else {
+ logw("MLO_LINKS_INFO_CHANGED with UNKNOWN reason");
+ }
+ break;
default: {
handleStatus = NOT_HANDLED;
break;
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java
index b9e4112d4f..09a37c9473 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackAidlImpl.java
@@ -1221,4 +1221,38 @@ class SupplicantStaIfaceCallbackAidlImpl extends ISupplicantStaIfaceCallback.Stu
public int getInterfaceVersion() {
return ISupplicantStaIfaceCallback.VERSION;
}
+
+ private String getMloLinksInfoChangedReasonStr(int reason) {
+ switch (reason) {
+ case ISupplicantStaIfaceCallback.MloLinkInfoChangeReason.TID_TO_LINK_MAP:
+ return "TID_TO_LINK_MAP";
+ case ISupplicantStaIfaceCallback.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL:
+ return "MULTI_LINK_RECONFIG_AP_REMOVAL";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private WifiMonitor.MloLinkInfoChangeReason convertMloLinkInfoChangedReason(int reason) {
+ switch (reason) {
+ case ISupplicantStaIfaceCallback.MloLinkInfoChangeReason.TID_TO_LINK_MAP:
+ return WifiMonitor.MloLinkInfoChangeReason.TID_TO_LINK_MAP;
+ case ISupplicantStaIfaceCallback.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL:
+ return WifiMonitor.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL;
+ default:
+ return WifiMonitor.MloLinkInfoChangeReason.UNKNOWN;
+ }
+ }
+
+ @Override
+ public void onMloLinksInfoChanged(int reason)
+ throws android.os.RemoteException {
+ synchronized (mLock) {
+ mStaIfaceHal.logCallback(
+ "onMloLinksInfoChanged: reason " + Integer.toString(reason) + " ("
+ + getMloLinksInfoChangedReasonStr(reason) + ")");
+ mWifiMonitor.broadcastMloLinksInfoChanged(mIfaceName,
+ convertMloLinkInfoChangedReason(reason));
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java
index ab592635d4..02a62cbff9 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java
@@ -2898,10 +2898,10 @@ public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal {
nativeInfo.links = new WifiNative.ConnectionMloLink[halInfo.links.length];
for (int i = 0; i < halInfo.links.length; i++) {
- nativeInfo.links[i] = new WifiNative.ConnectionMloLink();
- nativeInfo.links[i].linkId = halInfo.links[i].linkId;
- nativeInfo.links[i].staMacAddress = MacAddress.fromBytes(
- halInfo.links[i].staLinkMacAddress);
+ nativeInfo.links[i] = new WifiNative.ConnectionMloLink(
+ halInfo.links[i].linkId,
+ MacAddress.fromBytes(halInfo.links[i].staLinkMacAddress),
+ halInfo.links[i].tidsUplinkMap, halInfo.links[i].tidsDownlinkMap);
}
return nativeInfo;
} catch (RemoteException e) {
diff --git a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
index 346223b4f9..0c362a636f 100644
--- a/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
+++ b/service/java/com/android/server/wifi/WifiBlocklistMonitor.java
@@ -131,6 +131,7 @@ public class WifiBlocklistMonitor {
private final ScoringParams mScoringParams;
private final WifiMetrics mWifiMetrics;
private final WifiPermissionsUtil mWifiPermissionsUtil;
+ private ScanRequestProxy mScanRequestProxy;
private final Map<Integer, BssidDisableReason> mBssidDisableReasons =
buildBssidDisableReasons();
private final SparseArray<DisableReasonInfo> mDisableReasonInfo;
@@ -239,6 +240,11 @@ public class WifiBlocklistMonitor {
mAffiliatedBssidMap.clear();
}
+ /** Sets the ScanRequestProxy **/
+ public void setScanRequestProxy(ScanRequestProxy scanRequestProxy) {
+ mScanRequestProxy = scanRequestProxy;
+ }
+
/**
* Create a new instance of WifiBlocklistMonitor
*/
@@ -479,6 +485,20 @@ public class WifiBlocklistMonitor {
localLog("Ignoring failure to wait for watchdog to trigger first.");
return false;
}
+ // rssi may be unavailable for the first ever connection to a newly added network
+ // because it hasn't been cached inside the ScanDetailsCache yet. In this case, try to
+ // read the RSSI from the latest scan results.
+ if (rssi == WifiConfiguration.INVALID_RSSI && bssid != null) {
+ if (mScanRequestProxy != null) {
+ ScanResult scanResult = mScanRequestProxy.getScanResult(bssid);
+ if (scanResult != null) {
+ rssi = scanResult.level;
+ }
+ } else {
+ localLog("mScanRequestProxy is null");
+ Log.w(TAG, "mScanRequestProxy is null");
+ }
+ }
int baseBlockDurationMs = getBaseBlockDurationForReason(reasonCode);
long expBackoff = getBlocklistDurationWithExponentialBackoff(currentStreak,
baseBlockDurationMs);
diff --git a/service/java/com/android/server/wifi/WifiDialogManager.java b/service/java/com/android/server/wifi/WifiDialogManager.java
index 80e66907b1..73e5c5c39e 100644
--- a/service/java/com/android/server/wifi/WifiDialogManager.java
+++ b/service/java/com/android/server/wifi/WifiDialogManager.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -331,7 +332,8 @@ public class WifiDialogManager {
mActiveDialogIds.add(mDialogId);
mActiveDialogHandles.put(mDialogId, this);
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "Registered dialog with id=" + mDialogId);
+ Log.v(TAG, "Registered dialog with id=" + mDialogId
+ + ". Active dialogs ids: " + mActiveDialogIds);
}
}
@@ -347,9 +349,22 @@ public class WifiDialogManager {
mActiveDialogIds.remove(mDialogId);
mActiveDialogHandles.remove(mDialogId);
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "Unregistered dialog with id=" + mDialogId);
+ Log.v(TAG, "Unregistered dialog with id=" + mDialogId
+ + ". Active dialogs ids: " + mActiveDialogIds);
}
mDialogId = WifiManager.INVALID_DIALOG_ID;
+ if (mActiveDialogIds.isEmpty()) {
+ String wifiDialogApkPkgName = mContext.getWifiDialogApkPkgName();
+ if (wifiDialogApkPkgName == null) {
+ Log.wtf(TAG, "Could not get WifiDialog APK package name to force stop!");
+ return;
+ }
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Force stopping WifiDialog app");
+ }
+ mContext.getSystemService(ActivityManager.class)
+ .forceStopPackage(wifiDialogApkPkgName);
+ }
}
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index c5dc263b88..c2afbd9cdd 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -407,6 +407,7 @@ public class WifiInjector {
mContext.getSystemService(ActivityManager.class),
this, mWifiConfigManager,
mWifiPermissionsUtil, mWifiMetrics, mClock, wifiHandler, mSettingsConfigStore);
+ mWifiBlocklistMonitor.setScanRequestProxy(mScanRequestProxy);
mSarManager = new SarManager(mContext, makeTelephonyManager(), wifiLooper,
mWifiNative);
mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiScoreCard, mScoringParams,
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 45aab62b84..63b1eeb27a 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -120,6 +120,9 @@ public class WifiMonitor {
public static final int QOS_POLICY_RESET_EVENT = BASE + 75;
public static final int QOS_POLICY_REQUEST_EVENT = BASE + 76;
+ /* MLO links change event */
+ public static final int MLO_LINKS_INFO_CHANGED = BASE + 77;
+
/* WPS config errrors */
private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12;
private static final int CONFIG_AUTH_FAILURE = 18;
@@ -143,6 +146,13 @@ public class WifiMonitor {
@Retention(RetentionPolicy.SOURCE)
@interface TransitionDisableIndication{}
+ /* MLO links change event reason codes */
+ public enum MloLinkInfoChangeReason {
+ UNKNOWN,
+ TID_TO_LINK_MAP,
+ MULTI_LINK_RECONFIG_AP_REMOVAL,
+ }
+
/**
* Use this key to get the interface name of the message sent by WifiMonitor,
* or null if not available.
@@ -678,4 +688,15 @@ public class WifiMonitor {
List<QosPolicyRequest> qosPolicyData) {
sendMessage(iface, QOS_POLICY_REQUEST_EVENT, qosPolicyRequestId, 0, qosPolicyData);
}
+
+ /**
+ * Broadcast the MLO link changes with reason code to all handlers registered for this event.
+ *
+ * @param iface Name of the iface on which this occurred.
+ * @param reason Reason code for the MLO link info change.
+ */
+ public void broadcastMloLinksInfoChanged(String iface,
+ WifiMonitor.MloLinkInfoChangeReason reason) {
+ sendMessage(iface, MLO_LINKS_INFO_CHANGED, reason);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 26eb029f00..cbaa2f2337 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -79,6 +79,7 @@ import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -3533,12 +3534,73 @@ public class WifiNative {
* Class to represent a connection MLO Link
*/
public static class ConnectionMloLink {
- public int linkId;
- public MacAddress staMacAddress;
-
- ConnectionMloLink() {
- // Nothing for now
+ private int mLinkId;
+ private MacAddress mStaMacAddress;
+ private BitSet mTidsUplinkMap;
+ private BitSet mTidsDownlinkMap;
+
+ ConnectionMloLink(int id, MacAddress mac, byte tidsUplink, byte tidsDownlink) {
+ mLinkId = id;
+ mStaMacAddress = mac;
+ mTidsDownlinkMap = BitSet.valueOf(new byte[] { tidsDownlink });
+ mTidsUplinkMap = BitSet.valueOf(new byte[] { tidsUplink });
};
+
+ /**
+ * Check if there is any TID mapped to this link in uplink of downlink direction.
+ *
+ * @return true if there is any TID mapped to this link, otherwise false.
+ */
+ public boolean isAnyTidMapped() {
+ if (mTidsDownlinkMap.isEmpty() && mTidsUplinkMap.isEmpty()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check if a TID is mapped to this link in uplink direction.
+ *
+ * @param tid TID value.
+ * @return true if the TID is mapped in uplink direction. Otherwise, false.
+ */
+ public boolean isTidMappedToUplink(byte tid) {
+ if (tid < mTidsUplinkMap.length()) {
+ return mTidsUplinkMap.get(tid);
+ }
+ return false;
+ }
+
+ /**
+ * Check if a TID is mapped to this link in downlink direction. Otherwise, false.
+ *
+ * @param tid TID value
+ * @return true if the TID is mapped in downlink direction. Otherwise, false.
+ */
+ public boolean isTidMappedtoDownlink(byte tid) {
+ if (tid < mTidsDownlinkMap.length()) {
+ return mTidsDownlinkMap.get(tid);
+ }
+ return false;
+ }
+
+ /**
+ * Get link id for the link.
+ *
+ * @return link id.
+ */
+ public int getLinkId() {
+ return mLinkId;
+ }
+
+ /**
+ * Get link address.
+ *
+ * @return link mac address.
+ */
+ public MacAddress getMacAddress() {
+ return mStaMacAddress;
+ }
}
/**
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 54713f561b..f5b31023c3 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -76,6 +76,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -143,6 +144,7 @@ import android.os.Looper;
import android.os.Messenger;
import android.os.PowerManager;
import android.os.Process;
+import android.os.UserHandle;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -3424,6 +3426,7 @@ public class ClientModeImplTest extends WifiBaseTest {
mCmi.enableRssiPolling(true);
connect();
mLooper.dispatchAll();
+ assertRssiChangeBroadcastSent();
when(mClock.getWallClockMillis()).thenReturn(startMillis + 3333);
mLooper.dispatchAll();
WifiInfo wifiInfo = mWifiInfo;
@@ -5249,6 +5252,26 @@ public class ClientModeImplTest extends WifiBaseTest {
}
return null;
}).when(mContext).sendBroadcastAsUser(any(), any(), anyString());
+
+ doAnswer(invocation -> {
+ final Intent intent = invocation.getArgument(0);
+ if (WifiManager.RSSI_CHANGED_ACTION.equals(intent.getAction())) {
+ fail("Should not send RSSI_CHANGED broadcast!");
+ }
+ return null;
+ }).when(mContext).sendBroadcastAsUser(any(), any(), anyString(), any());
+ }
+
+ /**
+ * Verifies that RSSI change broadcast is sent.
+ */
+ private void assertRssiChangeBroadcastSent() throws Exception {
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL), eq(Manifest.permission.ACCESS_WIFI_STATE), any());
+ Intent intent = intentCaptor.getValue();
+ assertNotNull(intent);
+ assertEquals(WifiManager.RSSI_CHANGED_ACTION, intent.getAction());
}
/**
@@ -8774,15 +8797,10 @@ public class ClientModeImplTest extends WifiBaseTest {
mConnectionCapabilities.wifiStandard = ScanResult.WIFI_STANDARD_11BE;
WifiNative.ConnectionMloLinksInfo info = new WifiNative.ConnectionMloLinksInfo();
info.links = new WifiNative.ConnectionMloLink[2];
-
- info.links[0] = new WifiNative.ConnectionMloLink();
- info.links[0].linkId = TEST_MLO_LINK_ID;
- info.links[0].staMacAddress = TEST_MLO_LINK_ADDR;
-
- info.links[1] = new WifiNative.ConnectionMloLink();
- info.links[1].linkId = TEST_MLO_LINK_ID_1;
- info.links[1].staMacAddress = TEST_MLO_LINK_ADDR_1;
-
+ info.links[0] = new WifiNative.ConnectionMloLink(TEST_MLO_LINK_ID,
+ TEST_MLO_LINK_ADDR, Byte.MIN_VALUE, Byte.MAX_VALUE);
+ info.links[1] = new WifiNative.ConnectionMloLink(TEST_MLO_LINK_ID_1, TEST_MLO_LINK_ADDR_1,
+ Byte.MAX_VALUE, Byte.MIN_VALUE);
when(mWifiNative.getConnectionMloLinksInfo(WIFI_IFACE_NAME)).thenReturn(info);
}
@@ -8884,6 +8902,63 @@ public class ClientModeImplTest extends WifiBaseTest {
verify(mWifiBlocklistMonitor).removeAffiliatedBssids(eq(TEST_BSSID_STR));
}
+ private void configureMloLinksInfoWithIdleLinks() {
+ mConnectionCapabilities.wifiStandard = ScanResult.WIFI_STANDARD_11BE;
+ WifiNative.ConnectionMloLinksInfo info = new WifiNative.ConnectionMloLinksInfo();
+ info.links = new WifiNative.ConnectionMloLink[2];
+ info.links[0] = new WifiNative.ConnectionMloLink(TEST_MLO_LINK_ID,
+ TEST_MLO_LINK_ADDR, (byte) 0xFF, (byte) 0xFF);
+ info.links[1] = new WifiNative.ConnectionMloLink(TEST_MLO_LINK_ID_1, TEST_MLO_LINK_ADDR_1,
+ (byte) 0, (byte) 0);
+ when(mWifiNative.getConnectionMloLinksInfo(WIFI_IFACE_NAME)).thenReturn(info);
+ }
+
+ private void reconfigureMloLinksInfoWithOneLink() {
+ mConnectionCapabilities.wifiStandard = ScanResult.WIFI_STANDARD_11BE;
+ WifiNative.ConnectionMloLinksInfo info = new WifiNative.ConnectionMloLinksInfo();
+ info.links = new WifiNative.ConnectionMloLink[1];
+ info.links[0] = new WifiNative.ConnectionMloLink(TEST_MLO_LINK_ID,
+ TEST_MLO_LINK_ADDR, (byte) 0xFF, (byte) 0xFF);
+ when(mWifiNative.getConnectionMloLinksInfo(WIFI_IFACE_NAME)).thenReturn(info);
+ }
+
+ @Test
+ public void verifyMloLinkChangeTidToLinkMapping() throws Exception {
+ // Initialize
+ connect();
+ setScanResultWithMloInfo();
+ setConnectionMloLinksInfo();
+ mLooper.dispatchAll();
+
+ // Association
+ mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(FRAMEWORK_NETWORK_ID, TEST_WIFI_SSID, TEST_BSSID_STR,
+ SupplicantState.ASSOCIATED));
+ mLooper.dispatchAll();
+ // Make sure all links are active
+ for (MloLink link: mWifiInfo.getAffiliatedMloLinks()) {
+ assertEquals(link.getState(), MloLink.MLO_LINK_STATE_ACTIVE);
+ }
+
+ // TID to link mapping. Make sure one link is IDLE.
+ configureMloLinksInfoWithIdleLinks();
+ mCmi.sendMessage(WifiMonitor.MLO_LINKS_INFO_CHANGED,
+ WifiMonitor.MloLinkInfoChangeReason.TID_TO_LINK_MAP);
+ mLooper.dispatchAll();
+ List<MloLink> links = mWifiInfo.getAffiliatedMloLinks();
+ assertEquals(links.get(0).getState(), MloLink.MLO_LINK_STATE_ACTIVE);
+ assertEquals(links.get(1).getState(), MloLink.MLO_LINK_STATE_IDLE);
+
+ // LInk Removal. Make sure removed link is UNASSOCIATED.
+ reconfigureMloLinksInfoWithOneLink();
+ mCmi.sendMessage(WifiMonitor.MLO_LINKS_INFO_CHANGED,
+ WifiMonitor.MloLinkInfoChangeReason.MULTI_LINK_RECONFIG_AP_REMOVAL);
+ mLooper.dispatchAll();
+ links = mWifiInfo.getAffiliatedMloLinks();
+ assertEquals(links.get(0).getState(), MloLink.MLO_LINK_STATE_ACTIVE);
+ assertEquals(links.get(1).getState(), MloLink.MLO_LINK_STATE_UNASSOCIATED);
+ }
+
/**
* Verify that an event that occurs on a managed network is handled by
* logEventIfManagedNetwork.
diff --git a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java
index 498bdce35b..4f44d4a2b1 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalAidlImplTest.java
@@ -2843,18 +2843,26 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest {
*/
@Test
public void testGetConnectionMloLinksInfo() throws Exception {
+ final int mDownlinkTid = 3;
+ final int mUplinkTid = 6;
// initialize MLO Links
MloLinksInfo info = new MloLinksInfo();
MloLink[] links = new MloLink[3];
links[0] = new android.hardware.wifi.supplicant.MloLink();
links[0].linkId = 1;
links[0].staLinkMacAddress = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x01};
+ links[0].tidsDownlinkMap = Byte.MAX_VALUE;
+ links[0].tidsDownlinkMap = Byte.MIN_VALUE;
links[1] = new android.hardware.wifi.supplicant.MloLink();
links[1].linkId = 2;
links[1].staLinkMacAddress = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x02};
+ links[1].tidsDownlinkMap = 1 << mDownlinkTid;
+ links[1].tidsUplinkMap = 1 << mUplinkTid;
links[2] = new android.hardware.wifi.supplicant.MloLink();
links[2].linkId = 3;
links[2].staLinkMacAddress = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x03};
+ links[2].tidsDownlinkMap = 0;
+ links[2].tidsUplinkMap = 0;
info.links = links;
executeAndValidateInitializationSequence();
// Mock MloLinksInfo as null.
@@ -2873,14 +2881,19 @@ public class SupplicantStaIfaceHalAidlImplTest extends WifiBaseTest {
// Check all return values.
assertNotNull(nativeInfo);
assertEquals(nativeInfo.links.length, info.links.length);
- assertEquals(nativeInfo.links[0].linkId, info.links[0].linkId);
- assertEquals(nativeInfo.links[0].staMacAddress,
+ assertEquals(nativeInfo.links[0].getLinkId(), info.links[0].linkId);
+ assertEquals(nativeInfo.links[0].getMacAddress(),
MacAddress.fromBytes(info.links[0].staLinkMacAddress));
- assertEquals(nativeInfo.links[1].linkId, info.links[1].linkId);
- assertEquals(nativeInfo.links[1].staMacAddress,
+ assertTrue(nativeInfo.links[0].isAnyTidMapped());
+ assertEquals(nativeInfo.links[1].getLinkId(), info.links[1].linkId);
+ assertEquals(nativeInfo.links[1].getMacAddress(),
MacAddress.fromBytes(info.links[1].staLinkMacAddress));
- assertEquals(nativeInfo.links[2].linkId, info.links[2].linkId);
- assertEquals(nativeInfo.links[2].staMacAddress,
+ assertTrue(nativeInfo.links[1].isAnyTidMapped());
+ assertTrue(nativeInfo.links[1].isTidMappedtoDownlink((byte) mDownlinkTid));
+ assertTrue(nativeInfo.links[1].isTidMappedToUplink((byte) mUplinkTid));
+ assertEquals(nativeInfo.links[2].getLinkId(), info.links[2].linkId);
+ assertEquals(nativeInfo.links[2].getMacAddress(),
MacAddress.fromBytes(info.links[2].staLinkMacAddress));
+ assertFalse(nativeInfo.links[2].isAnyTidMapped());
}
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java
index 0d04fdf511..5b9faf9844 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiBlocklistMonitorTest.java
@@ -138,6 +138,7 @@ public class WifiBlocklistMonitorTest {
@Mock private ScoringParams mScoringParams;
@Mock private WifiMetrics mWifiMetrics;
@Mock private WifiPermissionsUtil mWifiPermissionsUtil;
+ @Mock private ScanRequestProxy mScanRequestProxy;
@Mock private WifiScoreCard.PerNetwork mPerNetwork;
@Mock private WifiScoreCard.NetworkConnectionStats mRecentStats;
@@ -248,6 +249,7 @@ public class WifiBlocklistMonitorTest {
mWifiBlocklistMonitor = new WifiBlocklistMonitor(mContext, mWifiConnectivityHelper,
mWifiLastResortWatchdog, mClock, mLocalLog, mWifiScoreCard, mScoringParams,
mWifiMetrics, mWifiPermissionsUtil);
+ mWifiBlocklistMonitor.setScanRequestProxy(mScanRequestProxy);
}
private void verifyAddTestBssidToBlocklist() {
@@ -1135,6 +1137,42 @@ public class WifiBlocklistMonitorTest {
WifiBlocklistMonitor.REASON_DHCP_FAILURE);
}
+ @Test
+ public void testReadRssiFromLatestScanResultsWhenInvalid() {
+ // mock latest scan results with GOOD RSSI for TEST_BSSID_1
+ ScanResult fakeScanResult = mock(ScanResult.class);
+ fakeScanResult.level = TEST_GOOD_RSSI;
+ when(mScanRequestProxy.getScanResult(TEST_BSSID_1)).thenReturn(fakeScanResult);
+
+ // verify TEST_BSSID_1, 2 and 3 are block listed after connection failure using
+ // INVALID RSSI.
+ WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork(TEST_SSID_1);
+ when(mClock.getWallClockMillis()).thenReturn(0L);
+ mWifiBlocklistMonitor.handleBssidConnectionFailure(
+ TEST_BSSID_1, config, WifiBlocklistMonitor.REASON_EAP_FAILURE,
+ WifiConfiguration.INVALID_RSSI);
+ mWifiBlocklistMonitor.handleBssidConnectionFailure(
+ TEST_BSSID_2, config, WifiBlocklistMonitor.REASON_EAP_FAILURE,
+ WifiConfiguration.INVALID_RSSI);
+ mWifiBlocklistMonitor.handleBssidConnectionFailure(
+ TEST_BSSID_3, config, WifiBlocklistMonitor.REASON_EAP_FAILURE,
+ WifiConfiguration.INVALID_RSSI);
+ assertTrue(mWifiBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1));
+ assertTrue(mWifiBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_2));
+ assertTrue(mWifiBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_3));
+ assertEquals(3, mWifiBlocklistMonitor.updateAndGetBssidBlocklist().size());
+
+ // Simulate both TEST_BSSID_1 and TEST_BSSID_2 improving RSSI, but only TEST_BSSID_2 should
+ // be removed from blocklist.
+ List<ScanDetail> enabledDetails = simulateRssiUpdate(TEST_BSSID_1, TEST_GOOD_RSSI);
+ assertEquals(0, enabledDetails.size());
+ assertEquals(3, mWifiBlocklistMonitor.updateAndGetBssidBlocklist().size());
+
+ enabledDetails = simulateRssiUpdate(TEST_BSSID_2, TEST_GOOD_RSSI);
+ assertEquals(1, enabledDetails.size());
+ assertEquals(2, mWifiBlocklistMonitor.updateAndGetBssidBlocklist().size());
+ }
+
/**
* Verify that if the RSSI is low when the BSSID is blocked, a RSSI improvement to sufficient
* RSSI will remove the BSSID from blocklist along with affiliated BSSIDs.
@@ -1640,6 +1678,7 @@ public class WifiBlocklistMonitorTest {
mWifiBlocklistMonitor = new WifiBlocklistMonitor(mContext, mWifiConnectivityHelper,
mWifiLastResortWatchdog, mClock, mLocalLog, mWifiScoreCard, mScoringParams,
mWifiMetrics, mWifiPermissionsUtil);
+ mWifiBlocklistMonitor.setScanRequestProxy(mScanRequestProxy);
// Verify that the threshold is updated in the copied version
assertEquals(newThreshold, mWifiBlocklistMonitor.getNetworkSelectionDisableThreshold(
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java
index c5b3d06b54..fca154f2bc 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -82,12 +83,14 @@ public class WifiDialogManagerTest extends WifiBaseTest {
@Mock FrameworkFacade mFrameworkFacade;
@Mock Resources mResources;
@Mock PowerManager mPowerManager;
+ @Mock ActivityManager mActivityManager;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mWifiContext.getWifiDialogApkPkgName()).thenReturn(WIFI_DIALOG_APK_PKG_NAME);
when(mWifiContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
+ when(mWifiContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
when(mWifiContext.getResources()).thenReturn(mResources);
when(mPowerManager.isInteractive()).thenReturn(true);
doThrow(SecurityException.class).when(mWifiContext).startActivityAsUser(any(), any(),
@@ -326,6 +329,7 @@ public class WifiDialogManagerTest extends WifiBaseTest {
dismissDialogSynchronous(dialogHandle, mWifiThreadRunner);
intent = verifyStartActivityAsUser(2, mWifiContext);
verifyDismissIntent(intent);
+ verify(mActivityManager).forceStopPackage(WIFI_DIALOG_APK_PKG_NAME);
// A reply to the same dialog id should not trigger callback
wifiDialogManager.replyToSimpleDialog(dialogId, WifiManager.DIALOG_REPLY_POSITIVE);
@@ -1004,6 +1008,7 @@ public class WifiDialogManagerTest extends WifiBaseTest {
dismissDialogSynchronous(dialogHandle, mWifiThreadRunner);
intent = verifyStartActivityAsUser(2, mWifiContext);
verifyDismissIntent(intent);
+ verify(mActivityManager).forceStopPackage(WIFI_DIALOG_APK_PKG_NAME);
// A reply to the same dialog id should not trigger callback
wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, null);
@@ -1119,6 +1124,7 @@ public class WifiDialogManagerTest extends WifiBaseTest {
TEST_DEVICE_NAME, null);
dismissDialogSynchronous(dialogHandle, mWifiThreadRunner);
verifyDismissIntent(verifyStartActivityAsUser(2, mWifiContext));
+ verify(mActivityManager).forceStopPackage(WIFI_DIALOG_APK_PKG_NAME);
// Another call to dismiss should not send another dismiss intent.
dismissDialogSynchronous(dialogHandle, mWifiThreadRunner);