Merge "Stop TCP keepalive from CS for fd initiated stop events" am: 646715e787 am: 9243af84e8

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2604526

Change-Id: Idef492a704a2d8e8c3d446d1625085ee3e71cbad
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chiachang Wang
2023-06-09 02:42:12 +00:00
committed by Automerger Merge Worker
3 changed files with 104 additions and 29 deletions

View File

@@ -106,7 +106,12 @@ public class KeepaliveTracker {
private final int mAllowedUnprivilegedSlotsForUid; private final int mAllowedUnprivilegedSlotsForUid;
public KeepaliveTracker(Context context, Handler handler) { public KeepaliveTracker(Context context, Handler handler) {
mTcpController = new TcpKeepaliveController(handler); this(context, handler, new TcpKeepaliveController(handler));
}
@VisibleForTesting
KeepaliveTracker(Context context, Handler handler, TcpKeepaliveController tcpController) {
mTcpController = tcpController;
mContext = context; mContext = context;
mSupportedKeepalives = KeepaliveResourceUtil.getSupportedKeepalives(context); mSupportedKeepalives = KeepaliveResourceUtil.getSupportedKeepalives(context);
@@ -375,7 +380,7 @@ public class KeepaliveTracker {
break; break;
case TYPE_TCP: case TYPE_TCP:
try { try {
mTcpController.startSocketMonitor(mFd, this, mSlot); mTcpController.startSocketMonitor(mFd, mCallback, mSlot);
} catch (InvalidSocketException e) { } catch (InvalidSocketException e) {
handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET); handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
return ERROR_INVALID_SOCKET; return ERROR_INVALID_SOCKET;
@@ -455,12 +460,6 @@ public class KeepaliveTracker {
} }
} }
// TODO: This does not clean up the autoKi in AutomaticOnOffKeepaliveTracker and it is not
// possible without a big refactor.
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
}
/** /**
* Construct a new KeepaliveInfo from existing KeepaliveInfo with a new fd. * Construct a new KeepaliveInfo from existing KeepaliveInfo with a new fd.
*/ */

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.server.connectivity; package com.android.server.connectivity;
import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
import static android.net.SocketKeepalive.DATA_RECEIVED; import static android.net.SocketKeepalive.DATA_RECEIVED;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
@@ -33,6 +34,7 @@ import static android.system.OsConstants.TIOCOUTQ;
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.net.ISocketKeepaliveCallback;
import android.net.InvalidPacketException; import android.net.InvalidPacketException;
import android.net.NetworkUtils; import android.net.NetworkUtils;
import android.net.SocketKeepalive.InvalidSocketException; import android.net.SocketKeepalive.InvalidSocketException;
@@ -50,7 +52,6 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.IpUtils; import com.android.net.module.util.IpUtils;
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.net.InetAddress; import java.net.InetAddress;
@@ -88,6 +89,8 @@ public class TcpKeepaliveController {
private final MessageQueue mFdHandlerQueue; private final MessageQueue mFdHandlerQueue;
private final Handler mConnectivityServiceHandler;
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
private static final int TCP_HEADER_LENGTH = 20; private static final int TCP_HEADER_LENGTH = 20;
@@ -115,6 +118,7 @@ public class TcpKeepaliveController {
public TcpKeepaliveController(final Handler connectivityServiceHandler) { public TcpKeepaliveController(final Handler connectivityServiceHandler) {
mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue(); mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
mConnectivityServiceHandler = connectivityServiceHandler;
} }
/** Build tcp keepalive packet. */ /** Build tcp keepalive packet. */
@@ -324,12 +328,13 @@ public class TcpKeepaliveController {
* Start monitoring incoming packets. * Start monitoring incoming packets.
* *
* @param fd socket fd to monitor. * @param fd socket fd to monitor.
* @param ki a {@link KeepaliveInfo} that tracks information about a socket keepalive. * @param callback a {@link ISocketKeepaliveCallback} that tracks information about a socket
* keepalive.
* @param slot keepalive slot. * @param slot keepalive slot.
*/ */
public void startSocketMonitor(@NonNull final FileDescriptor fd, public void startSocketMonitor(
@NonNull final KeepaliveInfo ki, final int slot) @NonNull final FileDescriptor fd, @NonNull final ISocketKeepaliveCallback callback,
throws IllegalArgumentException, InvalidSocketException { final int slot) throws IllegalArgumentException, InvalidSocketException {
synchronized (mListeners) { synchronized (mListeners) {
if (null != mListeners.get(slot)) { if (null != mListeners.get(slot)) {
throw new IllegalArgumentException("This slot is already taken"); throw new IllegalArgumentException("This slot is already taken");
@@ -350,7 +355,8 @@ public class TcpKeepaliveController {
} else { } else {
reason = DATA_RECEIVED; reason = DATA_RECEIVED;
} }
ki.onFileDescriptorInitiatedStop(reason); mConnectivityServiceHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE,
0 /* unused */, reason, callback.asBinder()).sendToTarget();
// The listener returns the new set of events to listen to. Because 0 means no // The listener returns the new set of events to listen to. Because 0 means no
// event, the listener gets unregistered. // event, the listener gets unregistered.
return 0; return 0;

View File

@@ -18,6 +18,7 @@ package com.android.server.connectivity;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static com.android.testutils.HandlerUtils.visibleOnHandlerThread; import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
@@ -28,6 +29,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
@@ -47,6 +49,7 @@ import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.INetd; import android.net.INetd;
import android.net.ISocketKeepaliveCallback; import android.net.ISocketKeepaliveCallback;
import android.net.KeepalivePacketData;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.MarkMaskParcel; import android.net.MarkMaskParcel;
@@ -55,6 +58,7 @@ import android.net.Network;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.SocketKeepalive; import android.net.SocketKeepalive;
import android.net.TcpKeepalivePacketData;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
@@ -120,6 +124,7 @@ public class AutomaticOnOffKeepaliveTrackerTest {
TestKeepaliveTracker mKeepaliveTracker; TestKeepaliveTracker mKeepaliveTracker;
AOOTestHandler mTestHandler; AOOTestHandler mTestHandler;
TestTcpKeepaliveController mTcpController;
// Hexadecimal representation of a SOCK_DIAG response with tcp info. // Hexadecimal representation of a SOCK_DIAG response with tcp info.
private static final String SOCK_DIAG_TCP_INET_HEX = private static final String SOCK_DIAG_TCP_INET_HEX =
@@ -233,9 +238,9 @@ public class AutomaticOnOffKeepaliveTrackerTest {
public final FileDescriptor fd; public final FileDescriptor fd;
public final ISocketKeepaliveCallback socketKeepaliveCallback; public final ISocketKeepaliveCallback socketKeepaliveCallback;
public final Network underpinnedNetwork; public final Network underpinnedNetwork;
public final NattKeepalivePacketData kpd; public final KeepalivePacketData kpd;
TestKeepaliveInfo(NattKeepalivePacketData kpd) throws Exception { TestKeepaliveInfo(KeepalivePacketData kpd) throws Exception {
this.kpd = kpd; this.kpd = kpd;
socket = new Socket(); socket = new Socket();
socket.bind(null); socket.bind(null);
@@ -252,8 +257,9 @@ public class AutomaticOnOffKeepaliveTrackerTest {
private class TestKeepaliveTracker extends KeepaliveTracker { private class TestKeepaliveTracker extends KeepaliveTracker {
private KeepaliveInfo mKi; private KeepaliveInfo mKi;
TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler) { TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler,
super(context, handler); @NonNull final TcpKeepaliveController tcpController) {
super(context, handler, tcpController);
} }
public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) { public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) {
@@ -272,6 +278,24 @@ public class AutomaticOnOffKeepaliveTrackerTest {
} }
return mKi; return mKi;
} }
@NonNull
@Override
public KeepaliveInfo makeTcpKeepaliveInfo(@Nullable final NetworkAgentInfo nai,
@Nullable final FileDescriptor fd, final int intervalSeconds,
@NonNull final ISocketKeepaliveCallback cb) {
if (null == mKi) {
throw new IllegalStateException("Please call `setReturnedKeepaliveInfo`"
+ " before makeTcpKeepaliveInfo is called");
}
return mKi;
}
}
private static class TestTcpKeepaliveController extends TcpKeepaliveController {
TestTcpKeepaliveController(final Handler connectivityServiceHandler) {
super(connectivityServiceHandler);
}
} }
@Before @Before
@@ -303,7 +327,8 @@ public class AutomaticOnOffKeepaliveTrackerTest {
mHandlerThread = new HandlerThread("KeepaliveTrackerTest"); mHandlerThread = new HandlerThread("KeepaliveTrackerTest");
mHandlerThread.start(); mHandlerThread.start();
mTestHandler = new AOOTestHandler(mHandlerThread.getLooper()); mTestHandler = new AOOTestHandler(mHandlerThread.getLooper());
mKeepaliveTracker = new TestKeepaliveTracker(mCtx, mTestHandler); mTcpController = new TestTcpKeepaliveController(mTestHandler);
mKeepaliveTracker = new TestKeepaliveTracker(mCtx, mTestHandler, mTcpController);
doReturn(mKeepaliveTracker).when(mDependencies).newKeepaliveTracker(mCtx, mTestHandler); doReturn(mKeepaliveTracker).when(mDependencies).newKeepaliveTracker(mCtx, mTestHandler);
doReturn(true).when(mDependencies).isFeatureEnabled(any(), anyBoolean()); doReturn(true).when(mDependencies).isFeatureEnabled(any(), anyBoolean());
mAOOKeepaliveTracker = mAOOKeepaliveTracker =
@@ -333,6 +358,14 @@ public class AutomaticOnOffKeepaliveTrackerTest {
Log.d(TAG, "Test handler received CMD_MONITOR_AUTOMATIC_KEEPALIVE : " + msg); Log.d(TAG, "Test handler received CMD_MONITOR_AUTOMATIC_KEEPALIVE : " + msg);
mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj); mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
break; break;
case CMD_STOP_SOCKET_KEEPALIVE:
Log.d(TAG, "Test handler received CMD_STOP_SOCKET_KEEPALIVE : " + msg);
mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
if (mLastAutoKi == null) {
fail("Attempt to stop an already stopped keepalive");
}
mAOOKeepaliveTracker.handleStopKeepalive(mLastAutoKi, msg.arg2);
break;
} }
} }
} }
@@ -481,14 +514,15 @@ public class AutomaticOnOffKeepaliveTrackerTest {
mTestHandler, () -> mAOOKeepaliveTracker.getKeepaliveForBinder(binder)); mTestHandler, () -> mAOOKeepaliveTracker.getKeepaliveForBinder(binder));
} }
private void checkAndProcessKeepaliveStart(final NattKeepalivePacketData kpd) throws Exception { private void checkAndProcessKeepaliveStart(final KeepalivePacketData kpd) throws Exception {
checkAndProcessKeepaliveStart(TEST_SLOT, kpd); checkAndProcessKeepaliveStart(TEST_SLOT, kpd);
} }
private void checkAndProcessKeepaliveStart( private void checkAndProcessKeepaliveStart(
int slot, final NattKeepalivePacketData kpd) throws Exception { int slot, final KeepalivePacketData kpd) throws Exception {
verify(mNai).onStartNattSocketKeepalive(slot, TEST_KEEPALIVE_INTERVAL_SEC, kpd); verify(mNai).onStartNattSocketKeepalive(
verify(mNai).onAddNattKeepalivePacketFilter(slot, kpd); slot, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) kpd);
verify(mNai).onAddNattKeepalivePacketFilter(slot, (NattKeepalivePacketData) kpd);
triggerEventKeepalive(slot, SocketKeepalive.SUCCESS); triggerEventKeepalive(slot, SocketKeepalive.SUCCESS);
} }
@@ -531,9 +565,10 @@ public class AutomaticOnOffKeepaliveTrackerTest {
public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception { public void testHandleEventSocketKeepalive_startingFailureHardwareError() throws Exception {
final TestKeepaliveInfo testInfo = doStartNattKeepalive(); final TestKeepaliveInfo testInfo = doStartNattKeepalive();
verify(mNai) verify(mNai).onStartNattSocketKeepalive(
.onStartNattSocketKeepalive(TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, testInfo.kpd); TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) testInfo.kpd);
verify(mNai).onAddNattKeepalivePacketFilter(TEST_SLOT, testInfo.kpd); verify(mNai).onAddNattKeepalivePacketFilter(
TEST_SLOT, (NattKeepalivePacketData) testInfo.kpd);
// Network agent returns an error, fails to start the keepalive. // Network agent returns an error, fails to start the keepalive.
triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR); triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
@@ -674,9 +709,10 @@ public class AutomaticOnOffKeepaliveTrackerTest {
clearInvocations(mNai); clearInvocations(mNai);
doResumeKeepalive(getAutoKiForBinder(testInfo.binder)); doResumeKeepalive(getAutoKiForBinder(testInfo.binder));
verify(mNai) verify(mNai).onStartNattSocketKeepalive(
.onStartNattSocketKeepalive(TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, testInfo.kpd); TEST_SLOT, TEST_KEEPALIVE_INTERVAL_SEC, (NattKeepalivePacketData) testInfo.kpd);
verify(mNai).onAddNattKeepalivePacketFilter(TEST_SLOT, testInfo.kpd); verify(mNai).onAddNattKeepalivePacketFilter(
TEST_SLOT, (NattKeepalivePacketData) testInfo.kpd);
// Network agent returns error on starting the keepalive. // Network agent returns error on starting the keepalive.
triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR); triggerEventKeepalive(TEST_SLOT, SocketKeepalive.ERROR_HARDWARE_ERROR);
@@ -772,4 +808,38 @@ public class AutomaticOnOffKeepaliveTrackerTest {
verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback)); verifyNoMoreInteractions(ignoreStubs(testInfo1.socketKeepaliveCallback));
verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback)); verifyNoMoreInteractions(ignoreStubs(testInfo2.socketKeepaliveCallback));
} }
@Test
public void testStartTcpKeepalive_fdInitiatedStop() throws Exception {
final InetAddress srcAddress = InetAddress.getByAddress(
new byte[] { (byte) 192, 0, 0, (byte) 129 });
mNai.linkProperties.addLinkAddress(new LinkAddress(srcAddress, 24));
final KeepalivePacketData kpd = new TcpKeepalivePacketData(
InetAddress.getByAddress(new byte[] { (byte) 192, 0, 0, (byte) 129 }) /* srcAddr */,
12345 /* srcPort */,
InetAddress.getByAddress(new byte[] { 8, 8, 8, 8}) /* dstAddr */,
12345 /* dstPort */, new byte[] {1}, 111 /* tcpSeq */,
222 /* tcpAck */, 800 /* tcpWindow */, 2 /* tcpWindowScale */,
4 /* ipTos */, 64 /* ipTtl */);
final TestKeepaliveInfo testInfo = new TestKeepaliveInfo(kpd);
final KeepaliveInfo ki = mKeepaliveTracker.new KeepaliveInfo(
testInfo.socketKeepaliveCallback, mNai, kpd,
TEST_KEEPALIVE_INTERVAL_SEC, KeepaliveInfo.TYPE_TCP, testInfo.fd);
mKeepaliveTracker.setReturnedKeepaliveInfo(ki);
// Setup TCP keepalive.
mAOOKeepaliveTracker.startTcpKeepalive(mNai, testInfo.fd, TEST_KEEPALIVE_INTERVAL_SEC,
testInfo.socketKeepaliveCallback);
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
// A closed socket will result in EVENT_HANGUP and trigger error to
// FileDescriptorEventListener.
testInfo.socket.close();
HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
// The keepalive should be removed in AutomaticOnOffKeepaliveTracker.
getAutoKiForBinder(testInfo.binder);
}
} }