Loading services/core/java/com/android/server/connectivity/KeepaliveTracker.java +7 −3 Original line number Diff line number Diff line Loading @@ -367,6 +367,13 @@ public class KeepaliveTracker { Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network); } } // Ignore the case when the network disconnects immediately after stop() has been // called and the keepalive code is waiting for the response from the modem. This // might happen when the caller listens for a lower-layer network disconnect // callback and stop the keepalive at that time. But the stop() races with the // stop() generated in ConnectivityService network disconnection code path. if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return; // Store the reason of stopping, and report it after the keepalive is fully stopped. if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) { throw new IllegalStateException("Unexpected stop reason: " + mStopReason); Loading @@ -380,9 +387,6 @@ public class KeepaliveTracker { // e.g. invalid parameter. cleanupStoppedKeepalive(mNai, mSlot); break; case STOPPING: // Keepalive is already in stopping state, ignore. return; default: mStartedState = STOPPING; switch (mType) { Loading tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +14 −2 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { private NetworkAgent mNetworkAgent; private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; // Controls how test network agent is going to wait before responding to keepalive // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem. private long mKeepaliveResponseDelay = 0L; private Integer mExpectedKeepaliveSlot = null; public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context) Loading Loading @@ -134,12 +137,17 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { if (mWrapper.mExpectedKeepaliveSlot != null) { assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot); } onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError); mWrapper.mHandlerThread.getThreadHandler().postDelayed( () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError), mWrapper.mKeepaliveResponseDelay); } @Override public void stopSocketKeepalive(Message msg) { onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError); final int slot = msg.arg1; mWrapper.mHandlerThread.getThreadHandler().postDelayed( () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError), mWrapper.mKeepaliveResponseDelay); } @Override Loading Loading @@ -248,6 +256,10 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { mStopKeepaliveError = reason; } public void setKeepaliveResponseDelay(long delay) { mKeepaliveResponseDelay = delay; } public void setExpectedKeepaliveSlot(Integer slot) { mExpectedKeepaliveSlot = slot; } Loading tests/net/java/com/android/server/ConnectivityServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -4292,6 +4292,32 @@ public class ConnectivityServiceTest { myNet = connectKeepaliveNetwork(lp); mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that a stop followed by network disconnects does not result in crash. try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); // Delay the response of keepalive events in networkAgent long enough to make sure // the follow-up network disconnection will be processed first. mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS); ka.stop(); // Make sure the stop has been processed. Wait for executor idle is needed to prevent // flaky since the actual stop call to the service is delegated to executor thread. waitForIdleSerialExecutor(executor, TIMEOUT_MS); waitForIdle(); mWiFiNetworkAgent.disconnect(); mWiFiNetworkAgent.expectDisconnected(); callback.expectStopped(); callback.assertNoCallback(); } // Reconnect. waitForIdle(); myNet = connectKeepaliveNetwork(lp); mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); int srcPort2 = 0; Loading Loading
services/core/java/com/android/server/connectivity/KeepaliveTracker.java +7 −3 Original line number Diff line number Diff line Loading @@ -367,6 +367,13 @@ public class KeepaliveTracker { Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network); } } // Ignore the case when the network disconnects immediately after stop() has been // called and the keepalive code is waiting for the response from the modem. This // might happen when the caller listens for a lower-layer network disconnect // callback and stop the keepalive at that time. But the stop() races with the // stop() generated in ConnectivityService network disconnection code path. if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return; // Store the reason of stopping, and report it after the keepalive is fully stopped. if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) { throw new IllegalStateException("Unexpected stop reason: " + mStopReason); Loading @@ -380,9 +387,6 @@ public class KeepaliveTracker { // e.g. invalid parameter. cleanupStoppedKeepalive(mNai, mSlot); break; case STOPPING: // Keepalive is already in stopping state, ignore. return; default: mStartedState = STOPPING; switch (mType) { Loading
tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +14 −2 Original line number Diff line number Diff line Loading @@ -67,6 +67,9 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { private NetworkAgent mNetworkAgent; private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED; private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE; // Controls how test network agent is going to wait before responding to keepalive // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem. private long mKeepaliveResponseDelay = 0L; private Integer mExpectedKeepaliveSlot = null; public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context) Loading Loading @@ -134,12 +137,17 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { if (mWrapper.mExpectedKeepaliveSlot != null) { assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot); } onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError); mWrapper.mHandlerThread.getThreadHandler().postDelayed( () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError), mWrapper.mKeepaliveResponseDelay); } @Override public void stopSocketKeepalive(Message msg) { onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError); final int slot = msg.arg1; mWrapper.mHandlerThread.getThreadHandler().postDelayed( () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError), mWrapper.mKeepaliveResponseDelay); } @Override Loading Loading @@ -248,6 +256,10 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { mStopKeepaliveError = reason; } public void setKeepaliveResponseDelay(long delay) { mKeepaliveResponseDelay = delay; } public void setExpectedKeepaliveSlot(Integer slot) { mExpectedKeepaliveSlot = slot; } Loading
tests/net/java/com/android/server/ConnectivityServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -4292,6 +4292,32 @@ public class ConnectivityServiceTest { myNet = connectKeepaliveNetwork(lp); mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that a stop followed by network disconnects does not result in crash. try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); callback.expectStarted(); // Delay the response of keepalive events in networkAgent long enough to make sure // the follow-up network disconnection will be processed first. mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS); ka.stop(); // Make sure the stop has been processed. Wait for executor idle is needed to prevent // flaky since the actual stop call to the service is delegated to executor thread. waitForIdleSerialExecutor(executor, TIMEOUT_MS); waitForIdle(); mWiFiNetworkAgent.disconnect(); mWiFiNetworkAgent.expectDisconnected(); callback.expectStopped(); callback.assertNoCallback(); } // Reconnect. waitForIdle(); myNet = connectKeepaliveNetwork(lp); mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS); // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); int srcPort2 = 0; Loading