diff options
author | Oscar Shu <xshu@google.com> | 2020-09-08 04:44:47 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-09-08 04:44:47 +0000 |
commit | a0d01b665d79abaeabcbddba79c46d7d3b10e168 (patch) | |
tree | e15bc0510e80e0b2a0cb45e7bd9fd17305eaf5c6 | |
parent | e4e5a49dbe4ca726c51d9350fa61088c2bb23d8a (diff) | |
parent | da1b2e9ed28829fd434cd2bedd5932961696e479 (diff) |
Merge changes from topic "additionalUserActionMetrics" into rvc-qpr-dev
* changes:
Adding network disabled status to user action metrics
Add WifiStatus to UserAction metrics
Breakdown manual connection events
8 files changed, 456 insertions, 14 deletions
diff --git a/service/java/com/android/server/wifi/BssidBlocklistMonitor.java b/service/java/com/android/server/wifi/BssidBlocklistMonitor.java index bc41aa929..d96fdb39e 100644 --- a/service/java/com/android/server/wifi/BssidBlocklistMonitor.java +++ b/service/java/com/android/server/wifi/BssidBlocklistMonitor.java @@ -37,6 +37,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -60,7 +61,7 @@ public class BssidBlocklistMonitor { public static final int REASON_EAP_FAILURE = 3; // Other association rejection failures public static final int REASON_ASSOCIATION_REJECTION = 4; - // Associated timeout failures, when the RSSI is good + // Association timeout failures. public static final int REASON_ASSOCIATION_TIMEOUT = 5; // Other authentication failures public static final int REASON_AUTHENTICATION_FAILURE = 6; @@ -528,6 +529,20 @@ public class BssidBlocklistMonitor { } /** + * Gets the list of block reasons for BSSIDs currently in the blocklist. + * @return The set of unique reasons for blocking BSSIDs with this SSID. + */ + public Set<Integer> getFailureReasonsForSsid(@NonNull String ssid) { + if (ssid == null) { + return Collections.emptySet(); + } + return mBssidStatusMap.values().stream() + .filter(entry -> entry.isInBlocklist && ssid.equals(entry.ssid)) + .map(entry -> entry.blockReason) + .collect(Collectors.toSet()); + } + + /** * Attempts to re-enable BSSIDs that likely experienced failures due to low RSSI. * @param scanDetails */ diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 6c2b5e369..1ac361ef3 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -29,6 +29,7 @@ import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -74,6 +75,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.Experi import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkSpeedCount; import com.android.server.wifi.proto.nano.WifiMetricsProto.MeteredNetworkStats; +import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions; import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProfileTypeCount; import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats; @@ -92,6 +94,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLockStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkRequestApiLog; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog.SuggestionAppCount; +import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiStatus; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToggleStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry; @@ -113,6 +116,7 @@ import org.json.JSONObject; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.Calendar; import java.util.HashMap; @@ -232,6 +236,7 @@ public class WifiMetrics { @VisibleForTesting static final int MAX_USER_ACTION_EVENTS = 200; private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<>(); private LinkedList<UserActionEventWithTime> mUserActionEventList = new LinkedList<>(); + private WifiStatusBuilder mWifiStatusBuilder = new WifiStatusBuilder(); private int mLastPollRssi = -127; private int mLastPollLinkSpeed = -1; private int mLastPollRxLinkSpeed = -1; @@ -753,6 +758,88 @@ public class WifiMetrics { } } + class WifiStatusBuilder { + private int mNetworkId = WifiConfiguration.INVALID_NETWORK_ID; + private boolean mConnected; + private boolean mValidated; + private int mRssi; + private int mEstimatedTxKbps; + private int mEstimatedRxKbps; + private boolean mIsStuckDueToUserChoice; + + public void setNetworkId(int networkId) { + mNetworkId = networkId; + } + + public int getNetworkId() { + return mNetworkId; + } + + public void setConnected(boolean connected) { + mConnected = connected; + } + + public void setValidated(boolean validated) { + mValidated = validated; + } + + public void setRssi(int rssi) { + mRssi = rssi; + } + + public void setEstimatedTxKbps(int estimatedTxKbps) { + mEstimatedTxKbps = estimatedTxKbps; + } + + public void setEstimatedRxKbps(int estimatedRxKbps) { + mEstimatedRxKbps = estimatedRxKbps; + } + + public void setUserChoice(boolean userChoice) { + mIsStuckDueToUserChoice = userChoice; + } + + public WifiStatus toProto() { + WifiStatus result = new WifiStatus(); + result.isConnected = mConnected; + result.isValidated = mValidated; + result.lastRssi = mRssi; + result.estimatedTxKbps = mEstimatedTxKbps; + result.estimatedRxKbps = mEstimatedRxKbps; + result.isStuckDueToUserConnectChoice = mIsStuckDueToUserChoice; + return result; + } + } + + private NetworkDisableReason convertToNetworkDisableReason( + WifiConfiguration config, Set<Integer> bssidBlocklistReasons) { + NetworkSelectionStatus status = config.getNetworkSelectionStatus(); + NetworkDisableReason result = new NetworkDisableReason(); + if (config.allowAutojoin) { + if (!status.isNetworkEnabled()) { + result.disableReason = + MetricsUtils.convertNetworkSelectionDisableReasonToWifiProtoEnum( + status.getNetworkSelectionDisableReason()); + if (status.isNetworkPermanentlyDisabled()) { + result.configPermanentlyDisabled = true; + } else { + result.configTemporarilyDisabled = true; + } + } + } else { + result.disableReason = NetworkDisableReason.REASON_AUTO_JOIN_DISABLED; + result.configPermanentlyDisabled = true; + } + + int[] convertedBssidBlockReasons = bssidBlocklistReasons.stream() + .mapToInt(i -> MetricsUtils.convertBssidBlocklistReasonToWifiProtoEnum(i)) + .toArray(); + if (convertedBssidBlockReasons.length > 0) { + result.bssidDisableReasons = convertedBssidBlockReasons; + } + return result; + } + class UserActionEventWithTime { private UserActionEvent mUserActionEvent; private long mWallClockTimeMs = 0; // wall clock time for debugging only @@ -763,13 +850,11 @@ public class WifiMetrics { mUserActionEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); mWallClockTimeMs = mClock.getWallClockMillis(); mUserActionEvent.targetNetworkInfo = targetNetworkInfo; + mUserActionEvent.wifiStatus = mWifiStatusBuilder.toProto(); } UserActionEventWithTime(int eventType, int targetNetId) { - mUserActionEvent = new UserActionEvent(); - mUserActionEvent.eventType = eventType; - mUserActionEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); - mWallClockTimeMs = mClock.getWallClockMillis(); + this(eventType, null); if (targetNetId >= 0) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(targetNetId); if (config != null) { @@ -777,6 +862,8 @@ public class WifiMetrics { networkInfo.isEphemeral = config.isEphemeral(); networkInfo.isPasspoint = config.isPasspoint(); mUserActionEvent.targetNetworkInfo = networkInfo; + mUserActionEvent.networkDisableReason = convertToNetworkDisableReason( + config, mBssidBlocklistMonitor.getFailureReasonsForSsid(config.SSID)); } } } @@ -824,6 +911,9 @@ public class WifiMetrics { case UserActionEvent.EVENT_MANUAL_CONNECT: eventType = "EVENT_MANUAL_CONNECT"; break; + case UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK: + eventType = "EVENT_ADD_OR_UPDATE_NETWORK"; + break; } sb.append(" eventType=").append(eventType); sb.append(" startTimeMillis=").append(mUserActionEvent.startTimeMillis); @@ -832,6 +922,27 @@ public class WifiMetrics { sb.append(" isEphemeral=").append(networkInfo.isEphemeral); sb.append(" isPasspoint=").append(networkInfo.isPasspoint); } + WifiStatus wifiStatus = mUserActionEvent.wifiStatus; + if (wifiStatus != null) { + sb.append("\nWifiStatus: isConnected=").append(wifiStatus.isConnected); + sb.append(" isValidated=").append(wifiStatus.isValidated); + sb.append(" lastRssi=").append(wifiStatus.lastRssi); + sb.append(" estimatedTxKbps=").append(wifiStatus.estimatedTxKbps); + sb.append(" estimatedRxKbps=").append(wifiStatus.estimatedRxKbps); + sb.append(" isStuckDueToUserConnectChoice=") + .append(wifiStatus.isStuckDueToUserConnectChoice); + } + NetworkDisableReason disableReason = mUserActionEvent.networkDisableReason; + if (disableReason != null) { + sb.append("\nNetworkDisableReason: DisableReason=") + .append(disableReason.disableReason); + sb.append(" configTemporarilyDisabled=") + .append(disableReason.configTemporarilyDisabled); + sb.append(" configPermanentlyDisabled=") + .append(disableReason.configPermanentlyDisabled); + sb.append(" bssidDisableReasons=") + .append(Arrays.toString(disableReason.bssidDisableReasons)); + } return sb.toString(); } @@ -1607,6 +1718,7 @@ public class WifiMetrics { if (!result) { mScanResultRssiTimestampMillis = -1; } + mWifiStatusBuilder.setConnected(result); } } } @@ -2084,6 +2196,8 @@ public class WifiMetrics { mLastPollRxLinkSpeed = wifiInfo.getRxLinkSpeedMbps(); incrementTxLinkSpeedBandCount(mLastPollLinkSpeed, mLastPollFreq); incrementRxLinkSpeedBandCount(mLastPollRxLinkSpeed, mLastPollFreq); + mWifiStatusBuilder.setRssi(mLastPollRssi); + mWifiStatusBuilder.setNetworkId(wifiInfo.getNetworkId()); } /** @@ -2259,6 +2373,8 @@ public class WifiMetrics { mRxThroughputMbpsHistogramAbove2G.increment(rxThroughputKbps / 1000); } } + mWifiStatusBuilder.setEstimatedTxKbps(txThroughputKbps); + mWifiStatusBuilder.setEstimatedRxKbps(rxThroughputKbps); } } @@ -4646,6 +4762,10 @@ public class WifiMetrics { mWifiState = wifiState; mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED); mWifiWinsUsabilityScore = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED); + if (wifiState == WifiMetricsProto.WifiLog.WIFI_DISCONNECTED + || wifiState == WifiMetricsProto.WifiLog.WIFI_DISABLED) { + mWifiStatusBuilder = new WifiStatusBuilder(); + } } } @@ -4750,6 +4870,7 @@ public class WifiMetrics { case StaEvent.TYPE_CMD_START_ROAM: case StaEvent.TYPE_CONNECT_NETWORK: case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK: + mWifiStatusBuilder.setValidated(true); case StaEvent.TYPE_FRAMEWORK_DISCONNECT: case StaEvent.TYPE_SCORE_BREACH: case StaEvent.TYPE_MAC_CHANGE: @@ -6155,6 +6276,13 @@ public class WifiMetrics { synchronized (mLock) { if (networkId == WifiConfiguration.INVALID_NETWORK_ID) return; mNetworkIdToNominatorId.put(networkId, nominatorId); + + // user connect choice is preventing switcing off from the connected network + if (nominatorId + == WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE + && mWifiStatusBuilder.getNetworkId() == networkId) { + mWifiStatusBuilder.setUserChoice(true); + } } } diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index a398eacaf..5019f54e8 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -802,8 +802,13 @@ public class WifiServiceImpl extends BaseWifiService { Binder.restoreCallingIdentity(ident); } if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) { - mWifiMetrics.logUserActionEvent(enable ? UserActionEvent.EVENT_TOGGLE_WIFI_ON - : UserActionEvent.EVENT_TOGGLE_WIFI_OFF); + if (enable) { + mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON); + } else { + WifiInfo wifiInfo = mClientModeImpl.syncRequestConnectionInfo(); + mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF, + wifiInfo == null ? -1 : wifiInfo.getNetworkId()); + } } mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable); mActiveModeWarden.wifiToggled(); @@ -4118,10 +4123,15 @@ public class WifiServiceImpl extends BaseWifiService { throw new SecurityException(TAG + ": Permission denied"); } mLog.info("connect uid=%").c(uid).flush(); - mClientModeImpl.connect(config, netId, binder, callback, callbackIdentifier, uid); if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { - mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId); + if (config == null) { + mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId); + } else { + mWifiMetrics.logUserActionEvent( + UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId); + } } + mClientModeImpl.connect(config, netId, binder, callback, callbackIdentifier, uid); } /** @@ -4135,6 +4145,10 @@ public class WifiServiceImpl extends BaseWifiService { throw new SecurityException(TAG + ": Permission denied"); } mLog.info("save uid=%").c(Binder.getCallingUid()).flush(); + if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) { + mWifiMetrics.logUserActionEvent( + UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId); + } mClientModeImpl.save( config, binder, callback, callbackIdentifier, Binder.getCallingUid()); } diff --git a/service/java/com/android/server/wifi/util/MetricsUtils.java b/service/java/com/android/server/wifi/util/MetricsUtils.java index 2c9c7f741..4c87aa237 100644 --- a/service/java/com/android/server/wifi/util/MetricsUtils.java +++ b/service/java/com/android/server/wifi/util/MetricsUtils.java @@ -16,8 +16,12 @@ package com.android.server.wifi.util; +import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.util.SparseIntArray; +import com.android.server.wifi.BssidBlocklistMonitor; +import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; + /** * Utilities for Metrics collections. */ @@ -188,4 +192,65 @@ public class MetricsUtils { return protoArray; } + + /** + * Converts NetworkSelectionStatus.NetworkSelectionDisableReason to + * WifiMetricsProto.NetworkDisableReason.DisableReason + */ + public static int convertNetworkSelectionDisableReasonToWifiProtoEnum(int reason) { + switch (reason) { + case NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION: + return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; + case NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE: + return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; + case NetworkSelectionStatus.DISABLED_DHCP_FAILURE: + return NetworkDisableReason.REASON_DHCP_FAILURE; + case NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY: + case NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT: + return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; + case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_CREDENTIALS: + return NetworkDisableReason.REASON_AUTHENTICATION_NO_CREDENTIALS; + case NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD: + return NetworkDisableReason.REASON_WRONG_PASSWORD; + case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_SUBSCRIPTION: + return NetworkDisableReason.REASON_AUTHENTICATION_NO_SUBSCRIPTION; + default: + return NetworkDisableReason.REASON_UNKNOWN; + } + } + + /** + * Converts BssidBlocklistMonitor.FailureReason to + * WifiMetricsProto.NetworkDisableReason.DisableReason + */ + public static int convertBssidBlocklistReasonToWifiProtoEnum(int reason) { + switch (reason) { + case BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA: + return NetworkDisableReason.REASON_AP_UNABLE_TO_HANDLE_NEW_STA; + case BssidBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE: + return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; + case BssidBlocklistMonitor.REASON_WRONG_PASSWORD: + return NetworkDisableReason.REASON_WRONG_PASSWORD; + case BssidBlocklistMonitor.REASON_EAP_FAILURE: + return NetworkDisableReason.REASON_EAP_FAILURE; + case BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION: + return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; + case BssidBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT: + return NetworkDisableReason.REASON_ASSOCIATION_TIMEOUT; + case BssidBlocklistMonitor.REASON_AUTHENTICATION_FAILURE: + return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; + case BssidBlocklistMonitor.REASON_DHCP_FAILURE: + return NetworkDisableReason.REASON_DHCP_FAILURE; + case BssidBlocklistMonitor.REASON_ABNORMAL_DISCONNECT: + return NetworkDisableReason.REASON_ABNORMAL_DISCONNECT; + case BssidBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_MBO_OCE: + return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_MBO_OCE; + case BssidBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT: + return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT; + case BssidBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE: + return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE; + default: + return NetworkDisableReason.REASON_UNKNOWN; + } + } } diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index 30b1690cc..a7f706fb8 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -3156,6 +3156,8 @@ message UserActionEvent { EVENT_MANUAL_CONNECT = 11; // User changes the metered setting to "detect automatically" EVENT_CONFIGURE_METERED_STATUS_AUTO = 12; + // User adds a new network or updates configurations for an existing network. + EVENT_ADD_OR_UPDATE_NETWORK = 13; } // The type of user action @@ -3167,6 +3169,34 @@ message UserActionEvent { // Additional information on the target network for the action. This is not applicable and will // be null for some actions such as EVENT_TOGGLE_WIFI_ON. optional TargetNetworkInfo target_network_info = 3; + + // Information about the currently connected network. + optional WifiStatus wifi_status = 4; + + // Reasons why the network applicable for this user action is disabled. + // Normally this should be referring to the currently connected network. + // For a manual connection, this is referring to the user selected networks. + optional NetworkDisableReason network_disable_reason = 5; +} + +message WifiStatus { + // Wifi is connected. + optional bool is_connected = 1; + + // Wifi is validated + optional bool is_validated = 2; + + // The last observed RSSI + optional sint32 last_rssi = 3; + + // Estimated TX + optional int32 estimated_tx_kbps = 4; + + // Estimated RX + optional int32 estimated_rx_kbps = 5; + + // There is another candidate with better score, but user connect choice is preventing the switch. + optional bool is_stuck_due_to_user_connect_choice = 6; } // Additional information on a network @@ -3178,6 +3208,56 @@ message TargetNetworkInfo { optional bool is_passpoint = 2; } +// Reasons why a configuration or BSSID is disabled. +message NetworkDisableReason { + enum DisableReason { + // Default value, should not be used. + REASON_UNKNOWN = 0; + // AP unable to accept more clients, a special kind of association rejection failure. + REASON_AP_UNABLE_TO_HANDLE_NEW_STA = 1; + // No internet + REASON_NETWORK_VALIDATION_FAILURE = 2; + // Password is incorrect, a special kind of authentication failure. + REASON_WRONG_PASSWORD = 3; + // Incorrect EAP credentials. + REASON_EAP_FAILURE = 4; + // Other association rejection failures. + REASON_ASSOCIATION_REJECTION = 5; + // Associated timeout failures. + REASON_ASSOCIATION_TIMEOUT = 6; + // Other authentication failures. + REASON_AUTHENTICATION_FAILURE = 7; + // DHCP failures. + REASON_DHCP_FAILURE = 8; + // Device disconnected shortly after connection. + REASON_ABNORMAL_DISCONNECT = 9; + // AP initiated disconnect for a given duration. + REASON_FRAMEWORK_DISCONNECT_MBO_OCE = 10; + // Avoid connecting to the failed AP when trying to reconnect on other available candidates. + REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT = 11; + // The connected scorer has disconnected this network. + REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE = 12; + // The network is disabled due to absence of user credentials + REASON_AUTHENTICATION_NO_CREDENTIALS = 13; + // The network is disabled because service is not subscribed, a special kind of EAP failure. + REASON_AUTHENTICATION_NO_SUBSCRIPTION = 14; + // User disabled auto-join for this network. + REASON_AUTO_JOIN_DISABLED = 15; + } + + // The reason for disabling a network. + optional DisableReason disable_reason = 1; + + // The configuration is temporarily disabled. + optional bool config_temporarily_disabled = 2; + + // The configuration is disabled until the user manually re-enables it. + optional bool config_permanently_disabled = 3; + + // Reasons why 1 or more BSSIDs are temporarily disabled. + repeated DisableReason bssid_disable_reasons = 4; +} + // Number of networks with a large change of connection/disconnection // failure rate or high failure rate at high RSSI message HealthMonitorFailureStats { diff --git a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java index e3c8d52fa..d6333b363 100644 --- a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java @@ -776,4 +776,24 @@ public class BssidBlocklistMonitorTest { simulateRssiUpdate(TEST_BSSID_1, TEST_SUFFICIENT_RSSI); assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); } + + /** + * Verify the failure reasons for all blocked BSSIDs are retrieved. + */ + @Test + public void testGetFailureReasonsForSsid() { + // Null input should not crash + mBssidBlocklistMonitor.getFailureReasonsForSsid(null).size(); + assertEquals(0, mBssidBlocklistMonitor.getFailureReasonsForSsid(TEST_SSID_1).size()); + mBssidBlocklistMonitor.blockBssidForDurationMs(TEST_BSSID_1, TEST_SSID_1, 1000, + BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA, TEST_GOOD_RSSI); + mBssidBlocklistMonitor.blockBssidForDurationMs(TEST_BSSID_2, TEST_SSID_1, 1000, + BssidBlocklistMonitor.REASON_ABNORMAL_DISCONNECT, TEST_GOOD_RSSI); + + assertEquals(2, mBssidBlocklistMonitor.getFailureReasonsForSsid(TEST_SSID_1).size()); + assertTrue(mBssidBlocklistMonitor.getFailureReasonsForSsid(TEST_SSID_1) + .contains(BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA)); + assertTrue(mBssidBlocklistMonitor.getFailureReasonsForSsid(TEST_SSID_1) + .contains(BssidBlocklistMonitor.REASON_ABNORMAL_DISCONNECT)); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index d16ef3dcf..b4cd7592c 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -60,6 +60,7 @@ import android.net.wifi.SoftApCapability; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -98,6 +99,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.Int32Count; import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts; import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; +import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions; import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProfileTypeCount; import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats; @@ -129,9 +131,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -2399,9 +2403,8 @@ public class WifiMetricsTest extends WifiBaseTest { int testNetworkId = 0; long testStartTimeMillis = 123123L; when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartTimeMillis); - WifiConfiguration config = mock(WifiConfiguration.class); - when(config.isEphemeral()).thenReturn(true); - when(config.isPasspoint()).thenReturn(true); + WifiConfiguration config = WifiConfigurationTestUtil.createPasspointNetwork(); + config.ephemeral = true; when(mWcm.getConfiguredNetwork(testNetworkId)).thenReturn(config); mWifiMetrics.logUserActionEvent(testEventType, testNetworkId); @@ -2414,6 +2417,118 @@ public class WifiMetricsTest extends WifiBaseTest { assertEquals(testStartTimeMillis, userActionEvents[0].startTimeMillis); assertEquals(true, userActionEvents[0].targetNetworkInfo.isEphemeral); assertEquals(true, userActionEvents[0].targetNetworkInfo.isPasspoint); + + // Verify that there are no disabled WifiConfiguration and BSSIDs + NetworkDisableReason networkDisableReason = userActionEvents[0].networkDisableReason; + assertEquals(NetworkDisableReason.REASON_UNKNOWN, networkDisableReason.disableReason); + assertEquals(false, networkDisableReason.configTemporarilyDisabled); + assertEquals(false, networkDisableReason.configPermanentlyDisabled); + assertEquals(0, networkDisableReason.bssidDisableReasons.length); + } + + /** + * Verify the WifiStatus field in a UserActionEvent is populated correctly. + * @throws Exception + */ + @Test + public void testLogWifiStatusInUserActionEvent() throws Exception { + // setups WifiStatus for information + int expectedRssi = -55; + int testNetworkId = 1; + int expectedTx = 1234; + int expectedRx = 2345; + + WifiInfo wifiInfo = mock(WifiInfo.class); + when(wifiInfo.getRssi()).thenReturn(expectedRssi); + when(wifiInfo.getNetworkId()).thenReturn(testNetworkId); + mWifiMetrics.handlePollResult(wifiInfo); + mWifiMetrics.incrementThroughputKbpsCount(expectedTx, expectedRx, RSSI_POLL_FREQUENCY); + mWifiMetrics.setNominatorForNetwork(testNetworkId, + WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE); + + // generate a user action event and then verify fields + int testEventType = WifiMetricsProto.UserActionEvent.EVENT_FORGET_WIFI; + mWifiMetrics.logUserActionEvent(testEventType, testNetworkId); + dumpProtoAndDeserialize(); + + WifiMetricsProto.UserActionEvent[] userActionEvents = mDecodedProto.userActionEvents; + assertEquals(1, userActionEvents.length); + assertEquals(WifiMetricsProto.UserActionEvent.EVENT_FORGET_WIFI, + userActionEvents[0].eventType); + assertEquals(expectedRssi, userActionEvents[0].wifiStatus.lastRssi); + assertEquals(expectedTx, userActionEvents[0].wifiStatus.estimatedTxKbps); + assertEquals(expectedRx, userActionEvents[0].wifiStatus.estimatedRxKbps); + assertTrue(userActionEvents[0].wifiStatus.isStuckDueToUserConnectChoice); + } + + /** + * verify NetworkDisableReason is populated properly when there exists a disabled + * WifiConfiguration and BSSID. + */ + @Test + public void testNetworkDisableReasonInUserActionEvent() throws Exception { + // Setup a temporarily blocked config due to DISABLED_ASSOCIATION_REJECTION + WifiConfiguration testConfig = WifiConfigurationTestUtil.createOpenNetwork(); + NetworkSelectionStatus status = testConfig.getNetworkSelectionStatus(); + status.setNetworkSelectionStatus( + NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED); + status.setNetworkSelectionDisableReason( + NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION); + when(mWcm.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(testConfig); + + // Also setup the same BSSID level failure + Set<Integer> testBssidBlocklistReasons = new HashSet<>(); + testBssidBlocklistReasons.add(BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION); + when(mBssidBlocklistMonitor.getFailureReasonsForSsid(anyString())) + .thenReturn(testBssidBlocklistReasons); + + // Logging the user action event + mWifiMetrics.logUserActionEvent(WifiMetricsProto.UserActionEvent.EVENT_FORGET_WIFI, + TEST_NETWORK_ID); + dumpProtoAndDeserialize(); + + WifiMetricsProto.UserActionEvent[] userActionEvents = mDecodedProto.userActionEvents; + assertEquals(1, userActionEvents.length); + assertEquals(WifiMetricsProto.UserActionEvent.EVENT_FORGET_WIFI, + userActionEvents[0].eventType); + NetworkDisableReason networkDisableReason = userActionEvents[0].networkDisableReason; + assertEquals(NetworkDisableReason.REASON_ASSOCIATION_REJECTION, + networkDisableReason.disableReason); + assertEquals(true, networkDisableReason.configTemporarilyDisabled); + assertEquals(false, networkDisableReason.configPermanentlyDisabled); + assertEquals(1, networkDisableReason.bssidDisableReasons.length); + assertEquals(NetworkDisableReason.REASON_ASSOCIATION_REJECTION, + networkDisableReason.bssidDisableReasons[0]); + } + + /** + * verify that auto-join disable overrides any other disable reasons in NetworkDisableReason. + */ + @Test + public void testNetworkDisableReasonDisableAutojoinInUserActionEvent() throws Exception { + // Setup a temporarily blocked config due to DISABLED_ASSOCIATION_REJECTION + WifiConfiguration testConfig = WifiConfigurationTestUtil.createOpenNetwork(); + NetworkSelectionStatus status = testConfig.getNetworkSelectionStatus(); + status.setNetworkSelectionStatus( + NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED); + status.setNetworkSelectionDisableReason( + NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION); + when(mWcm.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(testConfig); + + // Disable autojoin + testConfig.allowAutojoin = false; + + // Logging the user action event + mWifiMetrics.logUserActionEvent(WifiMetricsProto.UserActionEvent.EVENT_FORGET_WIFI, + TEST_NETWORK_ID); + dumpProtoAndDeserialize(); + + WifiMetricsProto.UserActionEvent[] userActionEvents = mDecodedProto.userActionEvents; + NetworkDisableReason networkDisableReason = userActionEvents[0].networkDisableReason; + assertEquals(NetworkDisableReason.REASON_AUTO_JOIN_DISABLED, + networkDisableReason.disableReason); + assertEquals(false, networkDisableReason.configTemporarilyDisabled); + assertEquals(true, networkDisableReason.configPermanentlyDisabled); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index 6d1ae2927..22561a159 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -571,7 +571,8 @@ public class WifiServiceImplTest extends WifiBaseTest { assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); inorder.verify(mWifiMetrics).logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON); inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(true), eq(true)); - inorder.verify(mWifiMetrics).logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF); + inorder.verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_TOGGLE_WIFI_OFF), + anyInt()); inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(true), eq(false)); } @@ -3621,7 +3622,8 @@ public class WifiServiceImplTest extends WifiBaseTest { mock(IActionListener.class), 0); verify(mClientModeImpl).connect(any(WifiConfiguration.class), anyInt(), any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); - verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_MANUAL_CONNECT), anyInt()); + verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), + anyInt()); } /** @@ -3632,8 +3634,11 @@ public class WifiServiceImplTest extends WifiBaseTest { public void testSaveNetworkWithPrivilegedPermission() throws Exception { when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); mWifiServiceImpl.save(mock(WifiConfiguration.class), mock(Binder.class), mock(IActionListener.class), 0); + verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), + anyInt()); verify(mClientModeImpl).save(any(WifiConfiguration.class), any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); } |