Tethering: Enable TETHERING_AND_P2P_GO_LOCAL_AGENT for 25Q4+

This change enables the TETHERING_AND_P2P_GO_LOCAL_AGENT feature
on devices running Android 25Q4 or newer, in addition to being
controlled by the existing feature flag.

A new SdkUtil.isAtLeast25Q4() method is introduced to check for
the specific SDK version.

Flag: com.android.tethering.mainline.beta.tethering_and_p2p_go_local_agent
Test: atest ConnectivityCoverageTests --update-device \
      --test-filter '.*Tethering.*'
Test: TH
Bug: 420590461
Fix: 428098654
Fix: 420592689
Change-Id: I7ef79a201116de84f2c4973c4c360fd3d1ef0c4c
This commit is contained in:
Junyu Lai 2025-08-27 03:39:05 -07:00
commit bf75afdcd1
5 changed files with 54 additions and 7 deletions

View file

@ -42,6 +42,7 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.networkstack.tethering.TetheringConfiguration.USE_SYNC_SM;
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
import static com.android.networkstack.tethering.util.TetheringMessageBase.BASE_IPSERVER;
import static com.android.networkstack.tethering.util.TetheringUtils.getTransportTypeForTetherableType;
@ -84,10 +85,12 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.State;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.IIpv4PrefixRequest;
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.RoutingCoordinatorManager;
import com.android.net.module.util.SdkUtil;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.SyncStateMachine.StateInfo;
import com.android.net.module.util.ip.InterfaceController;
@ -215,8 +218,17 @@ public class IpServer extends StateMachineShim {
public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb);
/** Get whether TETHERING_AND_P2P_GO_LOCAL_AGENT feature is enabled. */
public boolean isTetheringAndP2pGoLocalAgentEnabled() {
/**
* Get whether a tethering feature flag is enabled via chickened out.
* @param name the name of the feature.
*/
public boolean isTetheringFeatureNotChickenedOut(@NonNull Context context,
@NonNull String name) {
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name);
}
/** Get whether tethering and P2P GO local agent flag is enabled via beta flags. */
public boolean isTetheringAndP2pGoLocalAgentBetaFlagEnabled() {
return Flags.tetheringAndP2pGoLocalAgent();
}
@ -377,9 +389,16 @@ public class IpServer extends StateMachineShim {
mLastError = TETHER_ERROR_NO_ERROR;
mServingMode = STATE_AVAILABLE;
// Tethering network agent is supported on V+, and will be adopting mainline beta program.
// Determines support for the Tethering/P2P GO local network agent. This feature is
// gated on Android V+ because it requires NET_CAPABILITY_LOCAL_NETWORK.
// For 25Q4+, it is enabled by default with a kill switch to prevent impacting
// existing devices if issues arise. For older V+ devices, rollout is controlled
// by a mainline beta flag.
mSupportTetheringAndP2pGoLocalAgent = SdkLevel.isAtLeastV()
&& mDeps.isTetheringAndP2pGoLocalAgentEnabled();
&& (SdkUtil.isAtLeast25Q4()
? mDeps.isTetheringFeatureNotChickenedOut(mContext,
TETHERING_AND_P2P_GO_LOCAL_AGENT)
: mDeps.isTetheringAndP2pGoLocalAgentBetaFlagEnabled());
mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState();

View file

@ -59,4 +59,10 @@ public class TetheringFeatureFlags {
* Disabled by default.
*/
public static final String TETHER_ACTIVE_SESSIONS_METRICS = "tether_active_sessions_metrics";
/**
* A kill switch to control whether the TETHERING_AND_P2P_GO_LOCAL_AGENT is enabled.
*/
public static final String TETHERING_AND_P2P_GO_LOCAL_AGENT =
"tethering_and_p2p_go_local_agent";
}

View file

@ -40,6 +40,7 @@ import static android.net.ip.IpServer.getTetherableIpv6Prefixes;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.modules.utils.build.SdkLevel.isAtLeastV;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -227,8 +228,12 @@ public class IpServerTest {
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
when(mDependencies.getInterfaceParams(IPSEC_IFACE)).thenReturn(IPSEC_IFACE_PARAMS);
doReturn(mFeatureFlags.getOrDefault(Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, false))
.when(mDependencies).isTetheringAndP2pGoLocalAgentEnabled();
final boolean agentFeatureEnabled = mFeatureFlags.getOrDefault(
Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, false);
doReturn(agentFeatureEnabled).when(mDependencies).isTetheringFeatureNotChickenedOut(any(),
eq(TETHERING_AND_P2P_GO_LOCAL_AGENT));
doReturn(agentFeatureEnabled).when(mDependencies)
.isTetheringAndP2pGoLocalAgentBetaFlagEnabled();
if (isAtLeastV()) {
when(mDependencies.makeNetworkAgent(any(), any(), anyString(), anyInt(), any()))
.thenReturn(mNetworkAgent);

View file

@ -88,6 +88,7 @@ import static com.android.networkstack.tethering.Tethering.UserRestrictionAction
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS;
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION;
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION;
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES;
import static com.android.testutils.TestPermissionUtil.runAsShell;
@ -479,7 +480,18 @@ public class TetheringTest {
}
@Override
public boolean isTetheringAndP2pGoLocalAgentEnabled() {
public boolean isTetheringFeatureNotChickenedOut(@NonNull Context context,
@NonNull String name) {
return switch (name) {
// Use one flag for mocking to reduce test complexity.
case TETHERING_AND_P2P_GO_LOCAL_AGENT -> mFeatureFlags.getOrDefault(
Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, false);
default -> throw new IllegalArgumentException("Unknown flag " + name);
};
}
@Override
public boolean isTetheringAndP2pGoLocalAgentBetaFlagEnabled() {
return mFeatureFlags.getOrDefault(Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, false);
}
}

View file

@ -54,4 +54,9 @@ public class SdkUtil {
public static boolean isAtLeast25Q2() {
return SDK_INT >= 36 || (SDK_INT == 35 && "Baklava".equals(Build.VERSION.CODENAME));
}
/** Checks if the device is running on a release version of Android 25Q4 or newer */
public static boolean isAtLeast25Q4() {
return Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1;
}
}