diff options
7 files changed, 115 insertions, 8 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 90c7f42c2..0fb7745f2 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -52,6 +52,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.hotspot2.PasspointManager; +import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.util.LruConnectionTracker; import com.android.server.wifi.util.MissingCounterTimerLockList; import com.android.server.wifi.util.WifiPermissionsUtil; @@ -1183,6 +1184,25 @@ public class WifiConfigManager { return newInternalConfig; } + private void logUserActionEvents(WifiConfiguration before, WifiConfiguration after) { + // Logs changes in meteredOverride. + if (before.meteredOverride != after.meteredOverride) { + mWifiInjector.getWifiMetrics().logUserActionEvent( + WifiMetrics.convertMeteredOverrideEnumToUserActionEventType( + after.meteredOverride), + after.networkId); + } + + // Logs changes in macRandomizationSetting. + if (before.macRandomizationSetting != after.macRandomizationSetting) { + mWifiInjector.getWifiMetrics().logUserActionEvent( + after.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE + ? UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF + : UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON, + after.networkId); + } + } + /** * Add a network or update a network configuration to our database. * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty @@ -1228,6 +1248,10 @@ public class WifiConfigManager { + config.getKey()); return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); } + if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) + && !config.isPasspoint()) { + logUserActionEvents(existingInternalConfig, config); + } newInternalConfig = updateExistingInternalWifiConfigurationFromExternal( existingInternalConfig, config, uid, packageName); diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 5ceee3f37..cd36f8565 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import static android.net.wifi.WifiConfiguration.MeteredOverride; + import static java.lang.StrictMath.toIntExact; import android.content.Context; @@ -77,6 +79,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.PnoScanMetrics; import com.android.server.wifi.proto.nano.WifiMetricsProto.SoftApConnectedClientsEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent.ConfigInfo; +import com.android.server.wifi.proto.nano.WifiMetricsProto.TargetNetworkInfo; import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLinkLayerUsageStats; @@ -732,6 +735,14 @@ public class WifiMetrics { private UserActionEvent mUserActionEvent; private long mWallClockTimeMs = 0; // wall clock time for debugging only + UserActionEventWithTime(int eventType, TargetNetworkInfo targetNetworkInfo) { + mUserActionEvent = new UserActionEvent(); + mUserActionEvent.eventType = eventType; + mUserActionEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); + mWallClockTimeMs = mClock.getWallClockMillis(); + mUserActionEvent.targetNetworkInfo = targetNetworkInfo; + } + UserActionEventWithTime(int eventType, int targetNetId) { mUserActionEvent = new UserActionEvent(); mUserActionEvent.eventType = eventType; @@ -740,8 +751,7 @@ public class WifiMetrics { if (targetNetId >= 0) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(targetNetId); if (config != null) { - WifiMetricsProto.TargetNetworkInfo networkInfo = - new WifiMetricsProto.TargetNetworkInfo(); + TargetNetworkInfo networkInfo = new TargetNetworkInfo(); networkInfo.isEphemeral = config.isEphemeral(); networkInfo.isPasspoint = config.isPasspoint(); mUserActionEvent.targetNetworkInfo = networkInfo; @@ -768,6 +778,9 @@ public class WifiMetrics { case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED: eventType = "EVENT_CONFIGURE_METERED_STATUS_UNMETERED"; break; + case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO: + eventType = "EVENT_CONFIGURE_METERED_STATUS_AUTO"; + break; case UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON: eventType = "EVENT_CONFIGURE_MAC_RANDOMIZATION_ON"; break; @@ -792,7 +805,7 @@ public class WifiMetrics { } sb.append(" eventType=").append(eventType); sb.append(" startTimeMillis=").append(mUserActionEvent.startTimeMillis); - WifiMetricsProto.TargetNetworkInfo networkInfo = mUserActionEvent.targetNetworkInfo; + TargetNetworkInfo networkInfo = mUserActionEvent.targetNetworkInfo; if (networkInfo != null) { sb.append(" isEphemeral=").append(networkInfo.isEphemeral); sb.append(" isPasspoint=").append(networkInfo.isPasspoint); @@ -5096,6 +5109,25 @@ public class WifiMetrics { } /** + * Converts MeteredOverride enum to UserActionEvent type. + * @param value + */ + public static int convertMeteredOverrideEnumToUserActionEventType(@MeteredOverride int value) { + int result = UserActionEvent.EVENT_UNKNOWN; + switch(value) { + case WifiConfiguration.METERED_OVERRIDE_NONE: + result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO; + break; + case WifiConfiguration.METERED_OVERRIDE_METERED: + result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED; + break; + case WifiConfiguration.METERED_OVERRIDE_NOT_METERED: + result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED; + break; + } + return result; + } + /** * Logs a UserActionEvent without a target network. * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType) */ @@ -5118,6 +5150,24 @@ public class WifiMetrics { } /** + * Logs a UserActionEvent, directly specifying the target network's properties. + * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType) + * @param isEphemeral true if the target network is ephemeral. + * @param isPasspoint true if the target network is passpoint. + */ + public void logUserActionEvent(int eventType, boolean isEphemeral, boolean isPasspoint) { + synchronized (mLock) { + TargetNetworkInfo networkInfo = new TargetNetworkInfo(); + networkInfo.isEphemeral = isEphemeral; + networkInfo.isPasspoint = isPasspoint; + mUserActionEventList.add(new UserActionEventWithTime(eventType, networkInfo)); + if (mUserActionEventList.size() > MAX_USER_ACTION_EVENTS) { + mUserActionEventList.remove(); + } + } + } + + /** * Update the difference between the last two WifiLinkLayerStats for WifiIsUnusableEvent */ public void updateWifiIsUnusableLinkLayerStats(long txSuccessDelta, long txRetriesDelta, diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java index b60ef3f63..ba89bce2c 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java @@ -65,6 +65,7 @@ import com.android.server.wifi.hotspot2.anqp.ANQPElement; import com.android.server.wifi.hotspot2.anqp.Constants; import com.android.server.wifi.hotspot2.anqp.HSOsuProvidersElement; import com.android.server.wifi.hotspot2.anqp.OsuProviderInfo; +import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.util.InformationElementUtil; import java.io.IOException; @@ -664,6 +665,10 @@ public class PasspointManager { if (TextUtils.equals(provider.getConfig().getHomeSp().getFqdn(), fqdn)) { boolean settingChanged = provider.setMacRandomizationEnabled(enable); if (settingChanged) { + mWifiMetrics.logUserActionEvent(enable + ? UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON + : UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF, + provider.isFromSuggestion(), true); mWifiConfigManager.removePasspointConfiguredNetwork( provider.getWifiConfig().getKey()); } @@ -689,7 +694,12 @@ public class PasspointManager { // Loop through all profiles with matching FQDN for (PasspointProvider provider : passpointProviders) { if (TextUtils.equals(provider.getConfig().getHomeSp().getFqdn(), fqdn)) { - provider.setMeteredOverride(meteredOverride); + if (provider.setMeteredOverride(meteredOverride)) { + mWifiMetrics.logUserActionEvent( + WifiMetrics.convertMeteredOverrideEnumToUserActionEventType( + meteredOverride), + provider.isFromSuggestion(), true); + } found = true; } } diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java index 006b8eaef..45fa39502 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java @@ -241,9 +241,13 @@ public class PasspointProvider { /** * Get the metered override for this passpoint profile. + * + * @return true if the setting has changed */ - public void setMeteredOverride(@MeteredOverride int meteredOverride) { + public boolean setMeteredOverride(@MeteredOverride int meteredOverride) { + boolean changed = mConfig.getMeteredOverride() != meteredOverride; mConfig.setMeteredOverride(meteredOverride); + return changed; } /** diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index c60508607..475ec01b9 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -3079,6 +3079,8 @@ message UserActionEvent { EVENT_TOGGLE_WIFI_OFF = 10; // User manually connects to a network EVENT_MANUAL_CONNECT = 11; + // User changes the metered setting to "detect automatically" + EVENT_CONFIGURE_METERED_STATUS_AUTO = 12; } // The type of user action diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index 8e199ec00..5f8fe98f7 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -51,6 +51,7 @@ import androidx.test.filters.SmallTest; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.wifi.WifiScoreCard.PerNetwork; +import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.util.LruConnectionTracker; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; @@ -142,6 +143,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { @Mock private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; @Mock private WifiScoreCard mWifiScoreCard; @Mock private PerNetwork mPerNetwork; + @Mock private WifiMetrics mWifiMetrics; private LruConnectionTracker mLruConnectionTracker; private MockResources mResources; @@ -222,6 +224,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { when(mWifiInjector.getWifiLastResortWatchdog().shouldIgnoreSsidUpdate()) .thenReturn(false); when(mWifiInjector.getMacAddressUtil()).thenReturn(mMacAddressUtil); + when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(TEST_RANDOMIZED_MAC); when(mWifiScoreCard.lookupNetwork(any())).thenReturn(mPerNetwork); @@ -634,6 +637,8 @@ public class WifiConfigManagerTest extends WifiBaseTest { networks.add(openNetwork); verifyAddNetworkToWifiConfigManager(openNetwork); + // Verify user action event is not logged when the network is added + verify(mWifiMetrics, never()).logUserActionEvent(anyInt(), anyBoolean(), anyBoolean()); verify(mWcmListener).onNetworkAdded(wifiConfigCaptor.capture()); assertEquals(openNetwork.networkId, wifiConfigCaptor.getValue().networkId); reset(mWcmListener); @@ -642,6 +647,8 @@ public class WifiConfigManagerTest extends WifiBaseTest { openNetwork.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; NetworkUpdateResult networkUpdateResult = updateNetworkToWifiConfigManager(openNetwork); assertNotEquals(WifiConfiguration.INVALID_NETWORK_ID, networkUpdateResult.getNetworkId()); + verify(mWifiMetrics).logUserActionEvent( + UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF, openNetwork.networkId); List<WifiConfiguration> retrievedNetworks = mWifiConfigManager.getConfiguredNetworksWithPasswords(); diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java index 861aa94ff..4a4c0e460 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java @@ -108,6 +108,7 @@ import com.android.server.wifi.hotspot2.anqp.DomainNameElement; import com.android.server.wifi.hotspot2.anqp.HSOsuProvidersElement; import com.android.server.wifi.hotspot2.anqp.I18Name; import com.android.server.wifi.hotspot2.anqp.OsuProviderInfo; +import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.util.InformationElementUtil; import com.android.server.wifi.util.InformationElementUtil.RoamingConsortium; @@ -678,7 +679,7 @@ public class PasspointManagerTest extends WifiBaseTest { } verify(provider).uninstallCertsAndKeys(); - verify(mWifiConfigManager, times(2)).removePasspointConfiguredNetwork( + verify(mWifiConfigManager, times(3)).removePasspointConfiguredNetwork( provider.getWifiConfig().getKey()); /** * 1 from |removeProvider| + 2 from |setAutojoinEnabled| + 2 from @@ -750,26 +751,35 @@ public class PasspointManagerTest extends WifiBaseTest { * @param provider a mock provider that is already added into the PasspointManager */ private void verifyEnableMacRandomization(PasspointProvider provider) { + when(provider.setMacRandomizationEnabled(anyBoolean())).thenReturn(true); assertTrue(mManager.enableMacRandomization(provider.getConfig().getHomeSp().getFqdn(), false)); verify(provider).setMacRandomizationEnabled(false); - when(provider.setMacRandomizationEnabled(true)).thenReturn(true); + verify(mWifiMetrics).logUserActionEvent( + UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF, false, true); assertTrue(mManager.enableMacRandomization(provider.getConfig().getHomeSp().getFqdn(), true)); - verify(mWifiConfigManager).removePasspointConfiguredNetwork( + verify(mWifiConfigManager, times(2)).removePasspointConfiguredNetwork( provider.getWifiConfig().getKey()); + verify(mWifiMetrics).logUserActionEvent( + UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON, false, true); verify(provider).setMacRandomizationEnabled(true); assertFalse(mManager.enableMacRandomization(provider.getConfig().getHomeSp().getFqdn() + "-XXXX", false)); } private void verifySetMeteredOverride(PasspointProvider provider) { + when(provider.setMeteredOverride(anyInt())).thenReturn(true); assertTrue(mManager.setMeteredOverride(provider.getConfig().getHomeSp().getFqdn(), METERED_OVERRIDE_METERED)); verify(provider).setMeteredOverride(METERED_OVERRIDE_METERED); + verify(mWifiMetrics).logUserActionEvent( + UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED, false, true); assertTrue(mManager.setMeteredOverride(provider.getConfig().getHomeSp().getFqdn(), METERED_OVERRIDE_NOT_METERED)); verify(provider).setMeteredOverride(METERED_OVERRIDE_NOT_METERED); + verify(mWifiMetrics).logUserActionEvent( + UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED, false, true); assertFalse(mManager.setMeteredOverride(provider.getConfig().getHomeSp().getFqdn() + "-XXXX", METERED_OVERRIDE_METERED)); } |