Move fromStableParcelable to KeepaliveController
TcpKeepaliveController is the only user of KeepalivePacketDataUtil.fromStableParcelable. Because of fromStableParcelable, networkstack-client needs to depend on net-utils-framework-commonm, which pulls a lot of unnecessary classes. This is particularly problematic considering that networkstack-client may need to be redistributed as a prebuilt. Move the method to TcpKeepaliveController, simplifying dependencies. This also shows that fromStableParcelable could be removed altogether (or moved to tests) if TcpKeepaliveController built a TcpKeepalivePacketData class directly. Test: atest ConnectivityCoverageTests Change-Id: I554318f6bcd07c73d153598a0231e9fcaf912e90
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static android.net.SocketKeepalive.DATA_RECEIVED;
|
||||
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
|
||||
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
||||
import static android.net.SocketKeepalive.ERROR_SOCKET_NOT_IDLE;
|
||||
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
|
||||
@@ -29,6 +30,8 @@ import static android.system.OsConstants.IP_TOS;
|
||||
import static android.system.OsConstants.IP_TTL;
|
||||
import static android.system.OsConstants.TIOCOUTQ;
|
||||
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.net.InvalidPacketException;
|
||||
import android.net.NetworkUtils;
|
||||
@@ -36,7 +39,6 @@ import android.net.SocketKeepalive.InvalidSocketException;
|
||||
import android.net.TcpKeepalivePacketData;
|
||||
import android.net.TcpKeepalivePacketDataParcelable;
|
||||
import android.net.TcpRepairWindow;
|
||||
import android.net.util.KeepalivePacketDataUtil;
|
||||
import android.os.Handler;
|
||||
import android.os.MessageQueue;
|
||||
import android.os.Messenger;
|
||||
@@ -46,12 +48,18 @@ import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.net.module.util.IpUtils;
|
||||
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Manage tcp socket which offloads tcp keepalive.
|
||||
@@ -82,6 +90,8 @@ public class TcpKeepaliveController {
|
||||
|
||||
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
|
||||
|
||||
private static final int TCP_HEADER_LENGTH = 20;
|
||||
|
||||
// Reference include/uapi/linux/tcp.h
|
||||
private static final int TCP_REPAIR = 19;
|
||||
private static final int TCP_REPAIR_QUEUE = 20;
|
||||
@@ -112,12 +122,81 @@ public class TcpKeepaliveController {
|
||||
throws InvalidPacketException, InvalidSocketException {
|
||||
try {
|
||||
final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
|
||||
return KeepalivePacketDataUtil.fromStableParcelable(tcpDetails);
|
||||
// TODO: consider building a TcpKeepalivePacketData directly from switchToRepairMode
|
||||
return fromStableParcelable(tcpDetails);
|
||||
} catch (InvalidPacketException | InvalidSocketException e) {
|
||||
switchOutOfRepairMode(fd);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create tcp keepalive packet structure.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static TcpKeepalivePacketData fromStableParcelable(
|
||||
TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException {
|
||||
final byte[] packet;
|
||||
try {
|
||||
if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null)
|
||||
&& (tcpDetails.srcAddress.length == 4 /* V4 IP length */)
|
||||
&& (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) {
|
||||
packet = buildV4Packet(tcpDetails);
|
||||
} else {
|
||||
// TODO: support ipv6
|
||||
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
|
||||
}
|
||||
return new TcpKeepalivePacketData(
|
||||
InetAddress.getByAddress(tcpDetails.srcAddress),
|
||||
tcpDetails.srcPort,
|
||||
InetAddress.getByAddress(tcpDetails.dstAddress),
|
||||
tcpDetails.dstPort,
|
||||
packet,
|
||||
tcpDetails.seq, tcpDetails.ack, tcpDetails.rcvWnd, tcpDetails.rcvWndScale,
|
||||
tcpDetails.tos, tcpDetails.ttl);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build ipv4 tcp keepalive packet, not including the link-layer header.
|
||||
*/
|
||||
// TODO : if this code is ever moved to the network stack, factorize constants with the ones
|
||||
// over there.
|
||||
// TODO: consider using Ipv4Utils.buildTcpv4Packet() instead
|
||||
private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) {
|
||||
final int length = IPV4_HEADER_MIN_LEN + TCP_HEADER_LENGTH;
|
||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.put((byte) 0x45); // IP version and IHL
|
||||
buf.put((byte) tcpDetails.tos); // TOS
|
||||
buf.putShort((short) length);
|
||||
buf.putInt(0x00004000); // ID, flags=DF, offset
|
||||
buf.put((byte) tcpDetails.ttl); // TTL
|
||||
buf.put((byte) IPPROTO_TCP);
|
||||
final int ipChecksumOffset = buf.position();
|
||||
buf.putShort((short) 0); // IP checksum
|
||||
buf.put(tcpDetails.srcAddress);
|
||||
buf.put(tcpDetails.dstAddress);
|
||||
buf.putShort((short) tcpDetails.srcPort);
|
||||
buf.putShort((short) tcpDetails.dstPort);
|
||||
buf.putInt(tcpDetails.seq); // Sequence Number
|
||||
buf.putInt(tcpDetails.ack); // ACK
|
||||
buf.putShort((short) 0x5010); // TCP length=5, flags=ACK
|
||||
buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size
|
||||
final int tcpChecksumOffset = buf.position();
|
||||
buf.putShort((short) 0); // TCP checksum
|
||||
// URG is not set therefore the urgent pointer is zero.
|
||||
buf.putShort((short) 0); // Urgent pointer
|
||||
|
||||
buf.putShort(ipChecksumOffset, com.android.net.module.util.IpUtils.ipChecksum(buf, 0));
|
||||
buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum(
|
||||
buf, 0, IPV4_HEADER_MIN_LEN, TCP_HEADER_LENGTH));
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the tcp socket to repair mode and query detail tcp information.
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.net.util.KeepalivePacketDataUtil;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.server.connectivity.TcpKeepaliveController;
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
import com.android.testutils.DevSdkIgnoreRunner;
|
||||
|
||||
@@ -81,7 +82,7 @@ public final class KeepalivePacketDataUtilTest {
|
||||
testInfo.tos = tos;
|
||||
testInfo.ttl = ttl;
|
||||
try {
|
||||
resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
|
||||
resultData = TcpKeepaliveController.fromStableParcelable(testInfo);
|
||||
} catch (InvalidPacketException e) {
|
||||
fail("InvalidPacketException: " + e);
|
||||
}
|
||||
@@ -155,7 +156,7 @@ public final class KeepalivePacketDataUtilTest {
|
||||
testInfo.ttl = ttl;
|
||||
TcpKeepalivePacketData testData = null;
|
||||
TcpKeepalivePacketDataParcelable resultData = null;
|
||||
testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
|
||||
testData = TcpKeepaliveController.fromStableParcelable(testInfo);
|
||||
resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
|
||||
assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
|
||||
assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
|
||||
@@ -198,11 +199,11 @@ public final class KeepalivePacketDataUtilTest {
|
||||
testParcel.ttl = ttl;
|
||||
|
||||
final KeepalivePacketData testData =
|
||||
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
|
||||
TcpKeepaliveController.fromStableParcelable(testParcel);
|
||||
final TcpKeepalivePacketDataParcelable parsedParcelable =
|
||||
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
|
||||
final TcpKeepalivePacketData roundTripData =
|
||||
KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
|
||||
TcpKeepaliveController.fromStableParcelable(parsedParcelable);
|
||||
|
||||
// Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
|
||||
assertTrue(testData.getPacket().length > 0);
|
||||
@@ -210,11 +211,11 @@ public final class KeepalivePacketDataUtilTest {
|
||||
|
||||
testParcel.rcvWndScale = 0;
|
||||
final KeepalivePacketData noScaleTestData =
|
||||
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
|
||||
TcpKeepaliveController.fromStableParcelable(testParcel);
|
||||
final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
|
||||
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
|
||||
final TcpKeepalivePacketData noScaleRoundTripData =
|
||||
KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
|
||||
TcpKeepaliveController.fromStableParcelable(noScaleParsedParcelable);
|
||||
assertEquals(noScaleTestData, noScaleRoundTripData);
|
||||
assertTrue(noScaleTestData.getPacket().length > 0);
|
||||
assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
|
||||
|
||||
Reference in New Issue
Block a user