Enhance global settings for carrier-specific "avoid bad WiFi" behavior

Previously, the "avoid bad WiFi" global setting was limited to a single boolean value (0 or 1),
preventing granular control for multiple carriers.
This commit introduces support for carrier-aware "avoid bad WiFi" configurations using a new,
extensible format: "subId1,value1;subId2,value2;...".
This allows different `subId`s (carriers) to have their own specific "avoid bad WiFi" settings.

Flag: EXEMPT mainline
Bug: 410976315
Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.connectivity.MultinetworkPolicyTrackerTest
Change-Id: I118cff67c0c632778f73649999ee63e6f0e6fb17
This commit is contained in:
Jimi Chen 2025-06-04 09:50:03 +00:00
commit cbdfd9f54b
2 changed files with 99 additions and 13 deletions

View file

@ -20,6 +20,10 @@ import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
import static android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
import static com.android.net.module.util.ConnectivitySettingsUtils.convertCarrierAwareSettingsStringToMap;
import static com.android.net.module.util.ConnectivitySettingsUtils.getNetworkAvoidBadWifiSetting;
import static com.android.net.module.util.ConnectivitySettingsUtils.getNetworkLegacyGlobalAvoidBadWifiSetting;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@ -57,6 +61,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
@ -508,6 +513,54 @@ public class MultinetworkPolicyTracker {
mHandler.post(() -> updateAvoidBadWifiFromCarrierConfig(subId, config));
}
/**
* Determines whether the device should avoid bad Wi-Fi connections based on a hierarchical
* preference for settings.
*
* This method checks for the "avoid bad Wi-Fi" setting by first looking for a
* **carrier-aware setting** via {@code NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI}.
* If this setting is present and contains a value for the {@code mActiveSubId},
* that value is used.
* If {@code mActiveSubId} isn't explicitly found in the map, then fall back to the
* **legacy global setting** {@code NETWORK_AVOID_BAD_WIFI}.
*
* If the carrier-aware setting isn't available (i.e., it's {@code null}), the method then
* falls back to the **legacy global setting** {@code NETWORK_AVOID_BAD_WIFI}.
* This setting is considered {@code true} if its value is anything other than "0",
* and {@code false} if it is "0".
*
* Finally, if neither of the above settings is available (meaning both are {@code null}),
* the method retrieves the setting from a **local cache** using
* {@code readAvoidBadWifiFromCache(mActiveSubId)}.
* This is done to avoid potential IPC issues or blocking.
*
* @return {@code true} if the device should avoid bad Wi-Fi based on the highest priority
* available setting, {@code false} otherwise.
*/
private boolean getAvoidBadWifiInternal() {
final String carrierAwareSetting =
getNetworkAvoidBadWifiSetting(mContext);
if (carrierAwareSetting != null) {
final Map<Integer, Boolean> settingMap =
convertCarrierAwareSettingsStringToMap(carrierAwareSetting);
if (settingMap.containsKey(mActiveSubId)) {
return settingMap.get(mActiveSubId);
}
}
// if NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI is not set,
// check NETWORK_AVOID_BAD_WIFI setting for backward compatible
final String setting =
getNetworkLegacyGlobalAvoidBadWifiSetting(mContext);
if (setting != null) {
return !setting.equals("0");
}
// Retrieve the avoid bad Wi-Fi setting from the local cache to avoid potential
// issues or blocking from the IPC call getAvoidBadWifiCarrierConfigForSubId().
return readAvoidBadWifiFromCache(mActiveSubId);
}
/**
* Updates the "avoid bad Wi-Fi" setting.
* Depending on whether the carrier config feature is enabled, this method uses different logic:
@ -535,14 +588,7 @@ public class MultinetworkPolicyTracker {
// and mAvoidBadWifiFromCarrierConfigFeature is a trunk stable flag
// that only exists in 25Q4+
mActivelyPreferBadWifi = true;
final String settingAvoidBadWifiStr = readAvoidBadWifiFromSettings();
if (settingAvoidBadWifiStr != null) {
mAvoidBadWifi = "1".equals(settingAvoidBadWifiStr);
} else {
// Retrieve the avoid bad Wi-Fi setting from the local cache to avoid potential
// issues or blocking from the IPC call getAvoidBadWifiCarrierConfigForSubId().
mAvoidBadWifi = readAvoidBadWifiFromCache(mActiveSubId);
}
mAvoidBadWifi = getAvoidBadWifiInternal();
return mAvoidBadWifi != prevAvoid;
case FROM_RESOURCE:
final boolean settingAvoidBadWifi = "1".equals(readAvoidBadWifiFromSettings());

View file

@ -23,6 +23,7 @@ import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
import android.net.ConnectivitySettingsManager.NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI
import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.net.platform.flags.Flags.FLAG_AVOID_BAD_WIFI_FROM_CARRIER_CONFIG
import android.os.Build
@ -310,8 +311,8 @@ class MultinetworkPolicyTrackerTest(private val supportCarrierConfigManager: Boo
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testAvoidBadWifiWithGlobalSetting() {
val activeSubId = 1000
// Mock the initial global setting to false
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
// Mock the initial NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI setting to false
Settings.Global.putString(resolver, NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, "$activeSubId,0")
// Mock the initial carrier configuration to return true
trackerDependencies.setAvoidBadWifiCarrierConfigForSubId(activeSubId, true)
@ -330,12 +331,51 @@ class MultinetworkPolicyTrackerTest(private val supportCarrierConfigManager: Boo
assertFalse(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)
// Mock the initial global setting to true
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
// Mock the NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI setting to true
Settings.Global.putString(resolver, NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, "$activeSubId,1")
// Mock the initial carrier configuration to return false
trackerDependencies.setAvoidBadWifiCarrierConfigForSubId(activeSubId, false)
// Assert that the tracker's avoidBadWifi flag is true based on global setting
// Assert that the tracker's avoidBadWifi flag is true based on carrier aware setting
assertTrue(tracker.updateAvoidBadWifi())
assertTrue(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)
val testSubId = 1001
// Mock the NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI setting to multiple carrier setting
Settings.Global.putString(
resolver,
NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI,
"$activeSubId, 0;$testSubId, 1"
)
// Assert that the tracker's avoidBadWifi flag is false based on carrier aware setting
assertTrue(tracker.updateAvoidBadWifi())
assertFalse(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)
// Simulate a change in the active data subscription ID to testSubId.
listener.onActiveDataSubscriptionIdChanged(testSubId)
// Assert that the tracker's avoidBadWifi flag is true based on carrier aware setting
assertTrue(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)
// Unset NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI setting,
// it check NETWORK_AVOID_BAD_WIFI setting for backward compatible
Settings.Global.putString(resolver, NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, null)
// Mock the NETWORK_AVOID_BAD_WIFI setting to setting
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
// Assert that the tracker's avoidBadWifi flag is true based on setting
assertTrue(tracker.updateAvoidBadWifi())
assertFalse(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)
// Mock the NETWORK_AVOID_BAD_WIFI setting to setting
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
// Assert that the tracker's avoidBadWifi flag is true based on setting
assertTrue(tracker.updateAvoidBadWifi())
assertTrue(tracker.avoidBadWifi)
assertTrue(tracker.activelyPreferBadWifi)