diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index e5033121d0..9015434921 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -121,6 +121,7 @@ import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_SELF_CER import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION; import static android.os.Process.INVALID_UID; import static android.os.Process.VPN_UID; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static android.system.OsConstants.ETH_P_ALL; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -145,10 +146,12 @@ import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPer import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr; import static com.android.net.module.util.PermissionUtils.hasAnyPermissionOf; import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE; +import static com.android.server.connectivity.ConnectivityFlags.CELLULAR_DATA_INACTIVITY_TIMEOUT; import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS; import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING; import static com.android.server.connectivity.ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS; import static com.android.server.connectivity.ConnectivityFlags.REQUEST_RESTRICTED_WIFI; +import static com.android.server.connectivity.ConnectivityFlags.WIFI_DATA_INACTIVITY_TIMEOUT; import android.Manifest; import android.annotation.CheckResult; @@ -1610,6 +1613,18 @@ public class ConnectivityService extends IConnectivityManager.Stub connectivityServiceInternalHandler); } + /** Returns the data inactivity timeout to be used for cellular networks */ + public int getDefaultCellularDataInactivityTimeout() { + return DeviceConfigUtils.getDeviceConfigPropertyInt(NAMESPACE_TETHERING, + CELLULAR_DATA_INACTIVITY_TIMEOUT, 10); + } + + /** Returns the data inactivity timeout to be used for WiFi networks */ + public int getDefaultWifiDataInactivityTimeout() { + return DeviceConfigUtils.getDeviceConfigPropertyInt(NAMESPACE_TETHERING, + WIFI_DATA_INACTIVITY_TIMEOUT, 15); + } + /** * @see DeviceConfigUtils#isTetheringFeatureEnabled */ @@ -1958,8 +1973,13 @@ public class ConnectivityService extends IConnectivityManager.Stub // But reading the trunk stable flags from mainline modules is not supported yet. // So enabling this feature on V+ release. mTrackMultiNetworkActivities = mDeps.isAtLeastV(); + final int defaultCellularDataInactivityTimeout = + mDeps.getDefaultCellularDataInactivityTimeout(); + final int defaultWifiDataInactivityTimeout = + mDeps.getDefaultWifiDataInactivityTimeout(); mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNetd, mHandler, - mTrackMultiNetworkActivities); + mTrackMultiNetworkActivities, defaultCellularDataInactivityTimeout, + defaultWifiDataInactivityTimeout); final NetdCallback netdCallback = new NetdCallback(); try { @@ -13027,6 +13047,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // Key is netId. Value is configured idle timer information. private final SparseArray mActiveIdleTimers = new SparseArray<>(); private final boolean mTrackMultiNetworkActivities; + private final int mDefaultCellularDataInactivityTimeout; + private final int mDefaultWifiDataInactivityTimeout; // Store netIds of Wi-Fi networks whose idletimers report that they are active private final Set mActiveWifiNetworks = new ArraySet<>(); // Store netIds of cellular networks whose idletimers report that they are active @@ -13043,11 +13065,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } LegacyNetworkActivityTracker(@NonNull Context context, @NonNull INetd netd, - @NonNull Handler handler, boolean trackMultiNetworkActivities) { + @NonNull Handler handler, boolean trackMultiNetworkActivities, + int defaultCellularDataInactivityTimeout, int defaultWifiDataInactivityTimeout) { mContext = context; mNetd = netd; mHandler = handler; mTrackMultiNetworkActivities = trackMultiNetworkActivities; + mDefaultCellularDataInactivityTimeout = defaultCellularDataInactivityTimeout; + mDefaultWifiDataInactivityTimeout = defaultWifiDataInactivityTimeout; } private void ensureRunningOnConnectivityServiceThread() { @@ -13247,13 +13272,13 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkCapabilities.TRANSPORT_CELLULAR)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE, - 10); + mDefaultCellularDataInactivityTimeout); type = NetworkCapabilities.TRANSPORT_CELLULAR; } else if (networkAgent.networkCapabilities.hasTransport( NetworkCapabilities.TRANSPORT_WIFI)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI, - 15); + mDefaultWifiDataInactivityTimeout); type = NetworkCapabilities.TRANSPORT_WIFI; } else { return false; // do not track any other networks @@ -13377,6 +13402,12 @@ public class ConnectivityService extends IConnectivityManager.Stub public void dump(IndentingPrintWriter pw) { pw.print("mTrackMultiNetworkActivities="); pw.println(mTrackMultiNetworkActivities); + + pw.print("mDefaultCellularDataInactivityTimeout="); + pw.println(mDefaultCellularDataInactivityTimeout); + pw.print("mDefaultWifiDataInactivityTimeout="); + pw.println(mDefaultWifiDataInactivityTimeout); + pw.print("mIsDefaultNetworkActive="); pw.println(mIsDefaultNetworkActive); pw.print("mDefaultNetwork="); pw.println(mDefaultNetwork); pw.println("Idle timers:"); diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java index df8731619a..93335f15f5 100644 --- a/service/src/com/android/server/connectivity/ConnectivityFlags.java +++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java @@ -44,6 +44,11 @@ public final class ConnectivityFlags { public static final String BACKGROUND_FIREWALL_CHAIN = "background_firewall_chain"; + public static final String CELLULAR_DATA_INACTIVITY_TIMEOUT = + "cellular_data_inactivity_timeout"; + + public static final String WIFI_DATA_INACTIVITY_TIMEOUT = "wifi_data_inactivity_timeout"; + public static final String DELAY_DESTROY_SOCKETS = "delay_destroy_sockets"; public static final String USE_DECLARED_METHODS_FOR_CALLBACKS = diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 999d17d7b0..f7d7c87882 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -2369,6 +2369,18 @@ public class ConnectivityServiceTest { mScheduledEvaluationTimeouts.add(new Pair<>(network.netId, delayMs)); super.scheduleEvaluationTimeout(handler, network, delayMs); } + + @Override + public int getDefaultCellularDataInactivityTimeout() { + // Needed to mock out the dependency on DeviceConfig + return 10; + } + + @Override + public int getDefaultWifiDataInactivityTimeout() { + // Needed to mock out the dependency on DeviceConfig + return 15; + } } private class AutomaticOnOffKeepaliveTrackerDependencies diff --git a/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt index df0a2cc97b..ccbd6b3370 100644 --- a/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt @@ -21,6 +21,7 @@ import android.net.ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE import android.net.ConnectivityManager.EXTRA_DEVICE_TYPE import android.net.ConnectivityManager.EXTRA_IS_ACTIVE import android.net.ConnectivityManager.EXTRA_REALTIME_NS +import android.net.ConnectivitySettingsManager import android.net.LinkProperties import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_IMS @@ -41,12 +42,14 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.TestableNetworkCallback +import java.time.Duration import kotlin.test.assertNotNull import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.anyInt import org.mockito.Mockito.anyLong @@ -69,6 +72,18 @@ private const val TIMEOUT_MS = 250L @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) class CSNetworkActivityTest : CSTest() { + private fun setMobileDataActivityTimeout(timeoutSeconds: Int) { + ConnectivitySettingsManager.setMobileDataActivityTimeout( + context, Duration.ofSeconds(timeoutSeconds.toLong()) + ) + } + + private fun setWifiDataActivityTimeout(timeoutSeconds: Int) { + ConnectivitySettingsManager.setWifiDataActivityTimeout( + context, Duration.ofSeconds(timeoutSeconds.toLong()) + ) + } + private fun getRegisteredNetdUnsolicitedEventListener(): BaseNetdUnsolicitedEventListener { val captor = ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener::class.java) verify(netd).registerUnsolicitedEventListener(captor.capture()) @@ -252,8 +267,122 @@ class CSNetworkActivityTest : CSTest() { cm.unregisterNetworkCallback(dataNetworkCb) cm.unregisterNetworkCallback(imsNetworkCb) } + + @Test + fun testCellularIdleTimerSettingsTimeout() { + val cellNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val cellLp = LinkProperties().apply { + interfaceName = DATA_CELL_IFNAME + } + + val settingsTimeout: Int = deps.defaultCellDataInactivityTimeoutForTest + 432 + // DATA_ACTIVITY_TIMEOUT_MOBILE is set, so the default should be ignored. + setMobileDataActivityTimeout(settingsTimeout) + val cellAgent = Agent(nc = cellNc, lp = cellLp) + cellAgent.connect() + + verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), eq(settingsTimeout), anyString()) + } + + @Test + fun testCellularIdleTimerDefaultTimeout() { + val cellNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val cellLp = LinkProperties().apply { + interfaceName = DATA_CELL_IFNAME + } + + val testTimeout: Int = deps.defaultCellDataInactivityTimeoutForTest + // DATA_ACTIVITY_TIMEOUT_MOBILE is not set, so the default should be used. + val cellAgent = Agent(nc = cellNc, lp = cellLp) + cellAgent.connect() + + verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), eq(testTimeout), anyString()) + } + + @Test + fun testCellularIdleTimerDisabled() { + val cellNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val cellLp = LinkProperties().apply { + interfaceName = DATA_CELL_IFNAME + } + setMobileDataActivityTimeout(0) + val cellAgent = Agent(nc = cellNc, lp = cellLp) + cellAgent.connect() + + verify(netd, never()).idletimerAddInterface(eq(DATA_CELL_IFNAME), anyInt(), anyString()) + } + + @Test + fun testWifiIdleTimerSettingsTimeout() { + val wifiNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val wifiLp = LinkProperties().apply { + interfaceName = WIFI_IFNAME + } + val settingsTimeout: Int = deps.defaultWifiDataInactivityTimeout + 435 + setWifiDataActivityTimeout(settingsTimeout) + // DATA_ACTIVITY_TIMEOUT_MOBILE is set, so the default should be ignored. + val wifiAgent = Agent(nc = wifiNc, lp = wifiLp) + wifiAgent.connect() + + verify(netd).idletimerAddInterface(eq(WIFI_IFNAME), eq(settingsTimeout), anyString()) + } + + @Test + fun testWifiIdleTimerDefaultTimeout() { + val wifiNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val wifiLp = LinkProperties().apply { + interfaceName = WIFI_IFNAME + } + val testTimeout: Int = deps.defaultWifiDataInactivityTimeoutForTest + // DATA_ACTIVITY_TIMEOUT_WIFI is not set, so the default should be used. + val wifiAgent = Agent(nc = wifiNc, lp = wifiLp) + wifiAgent.connect() + + verify(netd).idletimerAddInterface(eq(WIFI_IFNAME), eq(testTimeout), anyString()) + } + + @Test + fun testWifiIdleTimerDisabled() { + val wifiNc = NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .build() + val wifiLp = LinkProperties().apply { + interfaceName = WIFI_IFNAME + } + setWifiDataActivityTimeout(0) + val wifiAgent = Agent(nc = wifiNc, lp = wifiLp) + wifiAgent.connect() + + verify(netd, never()).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(), anyString()) + } } + internal fun CSContext.expectDataActivityBroadcast( deviceType: Int, isActive: Boolean, diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 46c25d2153..ae196a624b 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -341,6 +341,18 @@ open class CSTest { } } + // Need a non-zero value to avoid disarming the timer. + val defaultCellDataInactivityTimeoutForTest: Int = 81 + override fun getDefaultCellularDataInactivityTimeout(): Int { + return defaultCellDataInactivityTimeoutForTest + } + + // Need a non-zero value to avoid disarming the timer. + val defaultWifiDataInactivityTimeoutForTest: Int = 121 + override fun getDefaultWifiDataInactivityTimeout(): Int { + return defaultWifiDataInactivityTimeoutForTest + } + override fun isChangeEnabled(changeId: Long, pkg: String, user: UserHandle) = changeId in enabledChangeIds override fun isChangeEnabled(changeId: Long, uid: Int) =