diff options
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); |