diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 497c105e66..42e80c3769 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -1501,6 +1501,22 @@ public class ConnectivityManager { } } + /** + * Temporarily set automaticOnOff keeplaive TCP polling alarm timer to 1 second. + * + * TODO: Remove this when the TCP polling design is replaced with callback. + * @params timeMs The time of expiry, with System.currentTimeMillis() base. The value should be + * set no more than 5 minutes in the future. + * @hide + */ + public void setTestLowTcpPollingTimerForKeepalive(long timeMs) { + try { + mService.setTestLowTcpPollingTimerForKeepalive(timeMs); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12 diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index acbc31ef43..c8f588d1ad 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -251,4 +251,6 @@ interface IConnectivityManager IBinder getCompanionDeviceManagerProxyService(); void setVpnNetworkPreference(String session, in UidRange[] ranges); + + void setTestLowTcpPollingTimerForKeepalive(long timeMs); } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 61c4fb119d..48b182351e 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -764,6 +764,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_SET_VPN_NETWORK_PREFERENCE = 59; + /** + * Event to use low TCP polling timer used in automatic on/off keepalive temporarily. + */ + private static final int EVENT_SET_LOW_TCP_POLLING_UNTIL = 60; + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. @@ -781,6 +786,12 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L; + /** + * The maximum alive time to decrease TCP polling timer in automatic on/off keepalive for + * testing. + */ + private static final long MAX_TEST_LOW_TCP_POLLING_UNTIL_MS = 5 * 60 * 1000L; + /** * The priority of the tc police rate limiter -- smaller value is higher priority. * This value needs to be coordinated with PRIO_CLAT, PRIO_TETHER4, and PRIO_TETHER6. @@ -4998,6 +5009,22 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.obtainMessage(EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL, timeMs)); } + @Override + public void setTestLowTcpPollingTimerForKeepalive(long timeMs) { + enforceSettingsPermission(); + if (!Build.isDebuggable()) { + throw new IllegalStateException("Is not supported in non-debuggable build"); + } + + if (timeMs > System.currentTimeMillis() + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS) { + throw new IllegalArgumentException("Argument should not exceed " + + MAX_TEST_LOW_TCP_POLLING_UNTIL_MS + "ms from now"); + } + + mHandler.sendMessage( + mHandler.obtainMessage(EVENT_SET_LOW_TCP_POLLING_UNTIL, timeMs)); + } + private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) { if (DBG) log("handleSetAcceptUnvalidated network=" + network + " accept=" + accept + " always=" + always); @@ -5639,6 +5666,11 @@ public class ConnectivityService extends IConnectivityManager.Stub case EVENT_SET_VPN_NETWORK_PREFERENCE: handleSetVpnNetworkPreference((VpnNetworkPreferenceInfo) msg.obj); break; + case EVENT_SET_LOW_TCP_POLLING_UNTIL: { + final long time = ((Long) msg.obj).longValue(); + mKeepaliveTracker.handleSetTestLowTcpPollingTimer(time); + break; + } } } } diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java index 937c93b0ef..03129c1d09 100644 --- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java +++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java @@ -96,6 +96,7 @@ public class AutomaticOnOffKeepaliveTracker { "com.android.server.connectivity.KeepaliveTracker.TCP_POLLING_ALARM"; private static final String EXTRA_BINDER_TOKEN = "token"; private static final long DEFAULT_TCP_POLLING_INTERVAL_MS = 120_000L; + private static final long LOW_TCP_POLLING_INTERVAL_MS = 1_000L; private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION = "automatic_on_off_keepalive_version"; /** @@ -154,6 +155,8 @@ public class AutomaticOnOffKeepaliveTracker { * This should be only updated in ConnectivityService handler thread. */ private final ArrayList mAutomaticOnOffKeepalives = new ArrayList<>(); + // TODO: Remove this when TCP polling design is replaced with callback. + private long mTestLowTcpPollingTimerUntilMs = 0; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -242,6 +245,13 @@ public class AutomaticOnOffKeepaliveTracker { public void binderDied() { mConnectivityServiceHandler.post(() -> cleanupAutoOnOffKeepalive(this)); } + + /** Close this automatic on/off keepalive */ + public void close() { + // Close the duplicated fd that maintains the lifecycle of socket. If this fd was + // not duplicated this is a no-op. + FileUtils.closeQuietly(mFd); + } } public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler) { @@ -267,7 +277,7 @@ public class AutomaticOnOffKeepaliveTracker { private void startTcpPollingAlarm(@NonNull PendingIntent alarm) { final long triggerAtMillis = - SystemClock.elapsedRealtime() + DEFAULT_TCP_POLLING_INTERVAL_MS; + SystemClock.elapsedRealtime() + getTcpPollingInterval(); // Setup a non-wake up alarm. mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, alarm); } @@ -417,9 +427,7 @@ public class AutomaticOnOffKeepaliveTracker { private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) { ensureRunningOnHandlerThread(); - // Close the duplicated fd that maintains the lifecycle of socket. If this fd was - // not duplicated this is a no-op. - FileUtils.closeQuietly(autoKi.mFd); + autoKi.close(); if (null != autoKi.mTcpPollingAlarm) mAlarmManager.cancel(autoKi.mTcpPollingAlarm); // If the KI is not in the array, it's because it was already removed, or it was never @@ -640,6 +648,20 @@ public class AutomaticOnOffKeepaliveTracker { } } + private long getTcpPollingInterval() { + final boolean useLowTimer = mTestLowTcpPollingTimerUntilMs > System.currentTimeMillis(); + return useLowTimer ? LOW_TCP_POLLING_INTERVAL_MS : DEFAULT_TCP_POLLING_INTERVAL_MS; + } + + /** + * Temporarily use low TCP polling timer for testing. + * The value works when the time set is more than {@link System.currentTimeMillis()}. + */ + public void handleSetTestLowTcpPollingTimer(long timeMs) { + Log.d(TAG, "handleSetTestLowTcpPollingTimer: " + timeMs); + mTestLowTcpPollingTimerUntilMs = timeMs; + } + /** * Dependencies class for testing. */