Loading src/com/android/networkstack/netlink/TcpInfo.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -112,6 +112,10 @@ public class TcpInfo { } } } } mFieldsValues = Collections.unmodifiableMap(fields); mFieldsValues = Collections.unmodifiableMap(fields); // tcp_info structure grows over time as new fields are added. Jump to the end of the // structure, as unknown fields might remain at the end of the structure if the tcp_info // struct was expanded. bytes.position(Math.min(infolen + start, bytes.limit())); } } @VisibleForTesting @VisibleForTesting Loading src/com/android/networkstack/netlink/TcpSocketTracker.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -173,7 +173,7 @@ public class TcpSocketTracker { // | Netlink Header | Family Header | Attributes | rtattr | // | Netlink Header | Family Header | Attributes | rtattr | // | struct nlmsghdr | struct rtmsg | struct rtattr| data | // | struct nlmsghdr | struct rtmsg | struct rtattr| data | // +------------------+---------------+--------------+--------+ // +------------------+---------------+--------------+--------+ final ByteBuffer bytes = mDependencies.recvMesssage(fd); final ByteBuffer bytes = mDependencies.recvMessage(fd); try { try { while (enoughBytesRemainForValidNlMsg(bytes)) { while (enoughBytesRemainForValidNlMsg(bytes)) { final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); Loading Loading @@ -212,9 +212,9 @@ public class TcpSocketTracker { } } } } } catch (IllegalArgumentException | BufferUnderflowException e) { } catch (IllegalArgumentException | BufferUnderflowException e) { Log.wtf(TAG, "Unexpected socket info parsing, " + e + ", family " + family Log.wtf(TAG, "Unexpected socket info parsing, family " + family + " buffer:" + bytes + " " + " buffer:" + bytes + " " + Base64.getEncoder().encodeToString(bytes.array())); + Base64.getEncoder().encodeToString(bytes.array()), e); } } } } // Calculate mLatestReceiveCount, mSentSinceLastRecv and mLatestPacketFailPercentage. // Calculate mLatestReceiveCount, mSentSinceLastRecv and mLatestPacketFailPercentage. Loading Loading @@ -547,7 +547,7 @@ public class TcpSocketTracker { /** /** * Receive the request message from kernel via given fd. * Receive the request message from kernel via given fd. */ */ public ByteBuffer recvMesssage(@NonNull final FileDescriptor fd) public ByteBuffer recvMessage(@NonNull final FileDescriptor fd) throws ErrnoException, InterruptedIOException { throws ErrnoException, InterruptedIOException { return NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); return NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); } } Loading tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java +24 −0 Original line number Original line Diff line number Diff line Loading @@ -90,6 +90,13 @@ public class TcpInfoTest { private static final byte[] TCP_INFO_BYTES = private static final byte[] TCP_INFO_BYTES = HexEncoding.decode(TCP_INFO_HEX.toCharArray(), false); HexEncoding.decode(TCP_INFO_HEX.toCharArray(), false); private static final String EXPANDED_TCP_INFO_HEX = TCP_INFO_HEX + "00000000" // tcpi_delivered + "00000000"; // tcpi_delivered_ce private static final byte[] EXPANDED_TCP_INFO_BYTES = HexEncoding.decode(EXPANDED_TCP_INFO_HEX.toCharArray(), false); private static final int EXPANDED_TCP_INFO_LENGTH = EXPANDED_TCP_INFO_BYTES.length - TCP_INFO_BYTES.length; @Test @Test public void testParseTcpInfo() { public void testParseTcpInfo() { final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); Loading @@ -99,6 +106,23 @@ public class TcpInfoTest { assertEquals(parsedInfo, new TcpInfo(expected)); assertEquals(parsedInfo, new TcpInfo(expected)); } } @Test public void testParseTcpInfoExpanded() { final ByteBuffer buffer = ByteBuffer.wrap(EXPANDED_TCP_INFO_BYTES); final Map<TcpInfo.Field, Number> expected = makeTestTcpInfoHash(); final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1 + EXPANDED_TCP_INFO_LENGTH); assertEquals(parsedInfo, new TcpInfo(expected)); assertEquals(buffer.limit(), buffer.position()); // reset the index. buffer.position(0); final TcpInfo parsedInfoShorterLen = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); assertEquals(parsedInfoShorterLen, new TcpInfo(expected)); assertEquals(TCP_INFO_LENGTH_V1, buffer.position()); } @Test @Test public void testValidOffset() { public void testValidOffset() { final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); Loading tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java +101 −47 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ import org.mockito.MockitoAnnotations; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashMap; import java.util.HashMap; // TODO: Add more tests for missing coverage. // TODO: Add more tests for missing coverage. Loading @@ -55,9 +56,9 @@ public class TcpSocketTrackerTest { private static final int TEST_BUFFER_SIZE = 1024; private static final int TEST_BUFFER_SIZE = 1024; private static final String DIAG_MSG_HEX = private static final String DIAG_MSG_HEX = // struct nlmsghdr. // struct nlmsghdr. "00000058" + // length = 88 "58000000" + // length = 88 "0014" + // type = SOCK_DIAG_BY_FAMILY "1400" + // type = SOCK_DIAG_BY_FAMILY "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // seqno "00000000" + // pid (0 == kernel) "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -66,12 +67,12 @@ public class TcpSocketTrackerTest { "00" + // timer "00" + // timer "00" + // retrans "00" + // retrans // inet_diag_sockid // inet_diag_sockid "A5DE" + // idiag_sport = 42462 "DEA5" + // idiag_sport = 42462 "B971" + // idiag_dport = 47473 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "00000000" + // idiag_if "000027760000ED34" + // idiag_cookie = 43387759684916 "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_wqueue Loading @@ -82,9 +83,9 @@ public class TcpSocketTrackerTest { // 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 = // struct nlmsghdr. // struct nlmsghdr. "00000114" + // length = 276 "14010000" + // length = 276 "0014" + // type = SOCK_DIAG_BY_FAMILY "1400" + // type = SOCK_DIAG_BY_FAMILY "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // seqno "00000000" + // pid (0 == kernel) "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -93,26 +94,26 @@ public class TcpSocketTrackerTest { "00" + // timer "00" + // timer "00" + // retrans "00" + // retrans // inet_diag_sockid // inet_diag_sockid "A5DE" + // idiag_sport = 42462 "DEA5" + // idiag_sport = 42462 "B971" + // idiag_dport = 47473 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "00000000" + // idiag_if "000027760000ED34" + // idiag_cookie = 43387759684916 "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_wqueue "00000000" + // idiag_uid "00000000" + // idiag_uid "00000000" + // idiag_inode "00000000" + // idiag_inode // rtattr // rtattr "0005" + // len = 5 "0500" + // len = 5 "0008" + // type = 8 "0800" + // type = 8 "00000000" + // data "00000000" + // data "0008" + // len = 8 "0800" + // len = 8 "000F" + // type = 15(INET_DIAG_MARK) "0F00" + // type = 15(INET_DIAG_MARK) "000C1A85" + // data, socket mark=793221 "851A0C00" + // data, socket mark=793221 "00AC" + // len = 172 "AC00" + // len = 172 "0002" + // type = 2(INET_DIAG_INFO) "0200" + // type = 2(INET_DIAG_INFO) // tcp_info // tcp_info "01" + // state = TCP_ESTABLISHED "01" + // state = TCP_ESTABLISHED "00" + // ca_state = TCP_CA_OPEN "00" + // ca_state = TCP_CA_OPEN Loading @@ -122,38 +123,38 @@ public class TcpSocketTrackerTest { "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS "88" + // wscale = 8 "88" + // wscale = 8 "00" + // delivery_rate_app_limited = 0 "00" + // delivery_rate_app_limited = 0 "001B914A" + // rto = 1806666 "4A911B00" + // rto = 1806666 "00000000" + // ato = 0 "00000000" + // ato = 0 "0000052E" + // sndMss = 1326 "2E050000" + // sndMss = 1326 "00000218" + // rcvMss = 536 "18020000" + // rcvMss = 536 "00000000" + // unsacked = 0 "00000000" + // unsacked = 0 "00000000" + // acked = 0 "00000000" + // acked = 0 "00000000" + // lost = 0 "00000000" + // lost = 0 "00000000" + // retrans = 0 "00000000" + // retrans = 0 "00000000" + // fackets = 0 "00000000" + // fackets = 0 "000000BB" + // lastDataSent = 187 "BB000000" + // lastDataSent = 187 "00000000" + // lastAckSent = 0 "00000000" + // lastAckSent = 0 "000000BB" + // lastDataRecv = 187 "BB000000" + // lastDataRecv = 187 "000000BB" + // lastDataAckRecv = 187 "BB000000" + // lastDataAckRecv = 187 "000005DC" + // pmtu = 1500 "DC050000" + // pmtu = 1500 "00015630" + // rcvSsthresh = 87600 "30560100" + // rcvSsthresh = 87600 "00092C3E" + // rttt = 601150 "3E2C0900" + // rttt = 601150 "0004961F" + // rttvar = 300575 "1F960400" + // rttvar = 300575 "00000578" + // sndSsthresh = 1400 "78050000" + // sndSsthresh = 1400 "0000000A" + // sndCwnd = 10 "0A000000" + // sndCwnd = 10 "000005A8" + // advmss = 1448 "A8050000" + // advmss = 1448 "00000003" + // reordering = 3 "03000000" + // reordering = 3 "00000000" + // rcvrtt = 0 "00000000" + // rcvrtt = 0 "00015630" + // rcvspace = 87600 "30560100" + // rcvspace = 87600 "00000000" + // totalRetrans = 0 "00000000" + // totalRetrans = 0 "000000000000AC53" + // pacingRate = 44115 "53AC000000000000" + // pacingRate = 44115 "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 "0000000000000001" + // bytesAcked = 1 "0100000000000000" + // bytesAcked = 1 "0000000000000000" + // bytesReceived = 0 "0000000000000000" + // bytesReceived = 0 "0000000A" + // SegsOut = 10 "0A000000" + // SegsOut = 10 "00000000" + // SegsIn = 0 "00000000" + // SegsIn = 0 "00000000" + // NotSentBytes = 0 "00000000" + // NotSentBytes = 0 "00092C3E" + // minRtt = 601150 "3E2C0900" + // minRtt = 601150 "00000000" + // DataSegsIn = 0 "00000000" + // DataSegsIn = 0 "00000000" + // DataSegsOut = 0 "00000000" + // DataSegsOut = 0 "0000000000000000"; // deliverRate = 0 "0000000000000000"; // deliverRate = 0 Loading @@ -162,9 +163,9 @@ public class TcpSocketTrackerTest { private static final String TEST_RESPONSE_HEX = SOCK_DIAG_TCP_INET_HEX private static final String TEST_RESPONSE_HEX = SOCK_DIAG_TCP_INET_HEX // struct nlmsghdr // struct nlmsghdr + "00000014" // length = 20 + "14000000" // length = 20 + "0003" // type = NLMSG_DONE + "0300" // type = NLMSG_DONE + "0103" // flags = NLM_F_REQUEST | NLM_F_DUMP + "0301" // flags = NLM_F_REQUEST | NLM_F_DUMP + "00000000" // seqno + "00000000" // seqno + "00000000" // pid (0 == kernel) + "00000000" // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -188,9 +189,15 @@ public class TcpSocketTrackerTest { anyInt())).thenReturn(DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE); anyInt())).thenReturn(DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE); } } private ByteBuffer getByteBuffer(final byte[] bytes) { final ByteBuffer buffer = ByteBuffer.wrap(bytes); buffer.order(ByteOrder.LITTLE_ENDIAN); return buffer; } @Test @Test public void testParseSockInfo() { public void testParseSockInfo() { final ByteBuffer buffer = ByteBuffer.wrap(SOCK_DIAG_TCP_INET_BYTES); final ByteBuffer buffer = getByteBuffer(SOCK_DIAG_TCP_INET_BYTES); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); buffer.position(SOCKDIAG_MSG_HEADER_SIZE); buffer.position(SOCKDIAG_MSG_HEADER_SIZE); final TcpSocketTracker.SocketInfo parsed = final TcpSocketTracker.SocketInfo parsed = Loading Loading @@ -269,20 +276,21 @@ public class TcpSocketTrackerTest { when(mDependencies.isTcpInfoParsingSupported()).thenReturn(true); when(mDependencies.isTcpInfoParsingSupported()).thenReturn(true); // No enough bytes remain for a valid NlMsg. // No enough bytes remain for a valid NlMsg. final ByteBuffer invalidBuffer = ByteBuffer.allocate(1); final ByteBuffer invalidBuffer = ByteBuffer.allocate(1); when(mDependencies.recvMesssage(any())).thenReturn(invalidBuffer); invalidBuffer.order(ByteOrder.LITTLE_ENDIAN); when(mDependencies.recvMessage(any())).thenReturn(invalidBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(0, tst.getSentSinceLastRecv()); assertEquals(0, tst.getSentSinceLastRecv()); // Header only. // Header only. final ByteBuffer headerBuffer = ByteBuffer.wrap(SOCK_DIAG_MSG_BYTES); final ByteBuffer headerBuffer = getByteBuffer(SOCK_DIAG_MSG_BYTES); when(mDependencies.recvMesssage(any())).thenReturn(headerBuffer); when(mDependencies.recvMessage(any())).thenReturn(headerBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(0, tst.getSentSinceLastRecv()); assertEquals(0, tst.getSentSinceLastRecv()); final ByteBuffer tcpBuffer = ByteBuffer.wrap(TEST_RESPONSE_BYTES); final ByteBuffer tcpBuffer = getByteBuffer(TEST_RESPONSE_BYTES); when(mDependencies.recvMesssage(any())).thenReturn(tcpBuffer); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); assertEquals(10, tst.getSentSinceLastRecv()); Loading @@ -297,4 +305,50 @@ public class TcpSocketTrackerTest { tst.mConfigListener.onPropertiesChanged(null /* properties */); tst.mConfigListener.onPropertiesChanged(null /* properties */); assertTrue(tst.isDataStallSuspected()); assertTrue(tst.isDataStallSuspected()); } } private static final String BAD_DIAG_MSG_HEX = // struct nlmsghdr. "00000058" + // length = 1476395008 "1400" + // type = SOCK_DIAG_BY_FAMILY "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 "02" + // family = AF_INET "06" + // state "00" + // timer "00" + // retrans // inet_diag_sockid "DEA5" + // idiag_sport = 42462 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_uid "00000000"; // idiag_inode private static final byte[] BAD_SOCK_DIAG_MSG_BYTES = HexEncoding.decode(BAD_DIAG_MSG_HEX.toCharArray(), false); @Test public void testPollSocketsInfo_BadFormat() throws Exception { final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); ByteBuffer tcpBuffer = getByteBuffer(TEST_RESPONSE_BYTES); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); assertEquals(50, tst.getLatestPacketFailPercentage()); tcpBuffer = getByteBuffer(BAD_SOCK_DIAG_MSG_BYTES); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); // Expect no additional packets, so still 10. assertEquals(10, tst.getSentSinceLastRecv()); // Expect to reset to 0. assertEquals(0, tst.getLatestPacketFailPercentage()); } } } Loading
src/com/android/networkstack/netlink/TcpInfo.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -112,6 +112,10 @@ public class TcpInfo { } } } } mFieldsValues = Collections.unmodifiableMap(fields); mFieldsValues = Collections.unmodifiableMap(fields); // tcp_info structure grows over time as new fields are added. Jump to the end of the // structure, as unknown fields might remain at the end of the structure if the tcp_info // struct was expanded. bytes.position(Math.min(infolen + start, bytes.limit())); } } @VisibleForTesting @VisibleForTesting Loading
src/com/android/networkstack/netlink/TcpSocketTracker.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -173,7 +173,7 @@ public class TcpSocketTracker { // | Netlink Header | Family Header | Attributes | rtattr | // | Netlink Header | Family Header | Attributes | rtattr | // | struct nlmsghdr | struct rtmsg | struct rtattr| data | // | struct nlmsghdr | struct rtmsg | struct rtattr| data | // +------------------+---------------+--------------+--------+ // +------------------+---------------+--------------+--------+ final ByteBuffer bytes = mDependencies.recvMesssage(fd); final ByteBuffer bytes = mDependencies.recvMessage(fd); try { try { while (enoughBytesRemainForValidNlMsg(bytes)) { while (enoughBytesRemainForValidNlMsg(bytes)) { final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); Loading Loading @@ -212,9 +212,9 @@ public class TcpSocketTracker { } } } } } catch (IllegalArgumentException | BufferUnderflowException e) { } catch (IllegalArgumentException | BufferUnderflowException e) { Log.wtf(TAG, "Unexpected socket info parsing, " + e + ", family " + family Log.wtf(TAG, "Unexpected socket info parsing, family " + family + " buffer:" + bytes + " " + " buffer:" + bytes + " " + Base64.getEncoder().encodeToString(bytes.array())); + Base64.getEncoder().encodeToString(bytes.array()), e); } } } } // Calculate mLatestReceiveCount, mSentSinceLastRecv and mLatestPacketFailPercentage. // Calculate mLatestReceiveCount, mSentSinceLastRecv and mLatestPacketFailPercentage. Loading Loading @@ -547,7 +547,7 @@ public class TcpSocketTracker { /** /** * Receive the request message from kernel via given fd. * Receive the request message from kernel via given fd. */ */ public ByteBuffer recvMesssage(@NonNull final FileDescriptor fd) public ByteBuffer recvMessage(@NonNull final FileDescriptor fd) throws ErrnoException, InterruptedIOException { throws ErrnoException, InterruptedIOException { return NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); return NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); } } Loading
tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java +24 −0 Original line number Original line Diff line number Diff line Loading @@ -90,6 +90,13 @@ public class TcpInfoTest { private static final byte[] TCP_INFO_BYTES = private static final byte[] TCP_INFO_BYTES = HexEncoding.decode(TCP_INFO_HEX.toCharArray(), false); HexEncoding.decode(TCP_INFO_HEX.toCharArray(), false); private static final String EXPANDED_TCP_INFO_HEX = TCP_INFO_HEX + "00000000" // tcpi_delivered + "00000000"; // tcpi_delivered_ce private static final byte[] EXPANDED_TCP_INFO_BYTES = HexEncoding.decode(EXPANDED_TCP_INFO_HEX.toCharArray(), false); private static final int EXPANDED_TCP_INFO_LENGTH = EXPANDED_TCP_INFO_BYTES.length - TCP_INFO_BYTES.length; @Test @Test public void testParseTcpInfo() { public void testParseTcpInfo() { final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); Loading @@ -99,6 +106,23 @@ public class TcpInfoTest { assertEquals(parsedInfo, new TcpInfo(expected)); assertEquals(parsedInfo, new TcpInfo(expected)); } } @Test public void testParseTcpInfoExpanded() { final ByteBuffer buffer = ByteBuffer.wrap(EXPANDED_TCP_INFO_BYTES); final Map<TcpInfo.Field, Number> expected = makeTestTcpInfoHash(); final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1 + EXPANDED_TCP_INFO_LENGTH); assertEquals(parsedInfo, new TcpInfo(expected)); assertEquals(buffer.limit(), buffer.position()); // reset the index. buffer.position(0); final TcpInfo parsedInfoShorterLen = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1); assertEquals(parsedInfoShorterLen, new TcpInfo(expected)); assertEquals(TCP_INFO_LENGTH_V1, buffer.position()); } @Test @Test public void testValidOffset() { public void testValidOffset() { final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES); Loading
tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java +101 −47 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ import org.mockito.MockitoAnnotations; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashMap; import java.util.HashMap; // TODO: Add more tests for missing coverage. // TODO: Add more tests for missing coverage. Loading @@ -55,9 +56,9 @@ public class TcpSocketTrackerTest { private static final int TEST_BUFFER_SIZE = 1024; private static final int TEST_BUFFER_SIZE = 1024; private static final String DIAG_MSG_HEX = private static final String DIAG_MSG_HEX = // struct nlmsghdr. // struct nlmsghdr. "00000058" + // length = 88 "58000000" + // length = 88 "0014" + // type = SOCK_DIAG_BY_FAMILY "1400" + // type = SOCK_DIAG_BY_FAMILY "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // seqno "00000000" + // pid (0 == kernel) "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -66,12 +67,12 @@ public class TcpSocketTrackerTest { "00" + // timer "00" + // timer "00" + // retrans "00" + // retrans // inet_diag_sockid // inet_diag_sockid "A5DE" + // idiag_sport = 42462 "DEA5" + // idiag_sport = 42462 "B971" + // idiag_dport = 47473 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "00000000" + // idiag_if "000027760000ED34" + // idiag_cookie = 43387759684916 "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_wqueue Loading @@ -82,9 +83,9 @@ public class TcpSocketTrackerTest { // 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 = // struct nlmsghdr. // struct nlmsghdr. "00000114" + // length = 276 "14010000" + // length = 276 "0014" + // type = SOCK_DIAG_BY_FAMILY "1400" + // type = SOCK_DIAG_BY_FAMILY "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // seqno "00000000" + // pid (0 == kernel) "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -93,26 +94,26 @@ public class TcpSocketTrackerTest { "00" + // timer "00" + // timer "00" + // retrans "00" + // retrans // inet_diag_sockid // inet_diag_sockid "A5DE" + // idiag_sport = 42462 "DEA5" + // idiag_sport = 42462 "B971" + // idiag_dport = 47473 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "00000000" + // idiag_if "000027760000ED34" + // idiag_cookie = 43387759684916 "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_wqueue "00000000" + // idiag_uid "00000000" + // idiag_uid "00000000" + // idiag_inode "00000000" + // idiag_inode // rtattr // rtattr "0005" + // len = 5 "0500" + // len = 5 "0008" + // type = 8 "0800" + // type = 8 "00000000" + // data "00000000" + // data "0008" + // len = 8 "0800" + // len = 8 "000F" + // type = 15(INET_DIAG_MARK) "0F00" + // type = 15(INET_DIAG_MARK) "000C1A85" + // data, socket mark=793221 "851A0C00" + // data, socket mark=793221 "00AC" + // len = 172 "AC00" + // len = 172 "0002" + // type = 2(INET_DIAG_INFO) "0200" + // type = 2(INET_DIAG_INFO) // tcp_info // tcp_info "01" + // state = TCP_ESTABLISHED "01" + // state = TCP_ESTABLISHED "00" + // ca_state = TCP_CA_OPEN "00" + // ca_state = TCP_CA_OPEN Loading @@ -122,38 +123,38 @@ public class TcpSocketTrackerTest { "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS "07" + // option = TCPI_OPT_WSCALE|TCPI_OPT_SACK|TCPI_OPT_TIMESTAMPS "88" + // wscale = 8 "88" + // wscale = 8 "00" + // delivery_rate_app_limited = 0 "00" + // delivery_rate_app_limited = 0 "001B914A" + // rto = 1806666 "4A911B00" + // rto = 1806666 "00000000" + // ato = 0 "00000000" + // ato = 0 "0000052E" + // sndMss = 1326 "2E050000" + // sndMss = 1326 "00000218" + // rcvMss = 536 "18020000" + // rcvMss = 536 "00000000" + // unsacked = 0 "00000000" + // unsacked = 0 "00000000" + // acked = 0 "00000000" + // acked = 0 "00000000" + // lost = 0 "00000000" + // lost = 0 "00000000" + // retrans = 0 "00000000" + // retrans = 0 "00000000" + // fackets = 0 "00000000" + // fackets = 0 "000000BB" + // lastDataSent = 187 "BB000000" + // lastDataSent = 187 "00000000" + // lastAckSent = 0 "00000000" + // lastAckSent = 0 "000000BB" + // lastDataRecv = 187 "BB000000" + // lastDataRecv = 187 "000000BB" + // lastDataAckRecv = 187 "BB000000" + // lastDataAckRecv = 187 "000005DC" + // pmtu = 1500 "DC050000" + // pmtu = 1500 "00015630" + // rcvSsthresh = 87600 "30560100" + // rcvSsthresh = 87600 "00092C3E" + // rttt = 601150 "3E2C0900" + // rttt = 601150 "0004961F" + // rttvar = 300575 "1F960400" + // rttvar = 300575 "00000578" + // sndSsthresh = 1400 "78050000" + // sndSsthresh = 1400 "0000000A" + // sndCwnd = 10 "0A000000" + // sndCwnd = 10 "000005A8" + // advmss = 1448 "A8050000" + // advmss = 1448 "00000003" + // reordering = 3 "03000000" + // reordering = 3 "00000000" + // rcvrtt = 0 "00000000" + // rcvrtt = 0 "00015630" + // rcvspace = 87600 "30560100" + // rcvspace = 87600 "00000000" + // totalRetrans = 0 "00000000" + // totalRetrans = 0 "000000000000AC53" + // pacingRate = 44115 "53AC000000000000" + // pacingRate = 44115 "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 "FFFFFFFFFFFFFFFF" + // maxPacingRate = 18446744073709551615 "0000000000000001" + // bytesAcked = 1 "0100000000000000" + // bytesAcked = 1 "0000000000000000" + // bytesReceived = 0 "0000000000000000" + // bytesReceived = 0 "0000000A" + // SegsOut = 10 "0A000000" + // SegsOut = 10 "00000000" + // SegsIn = 0 "00000000" + // SegsIn = 0 "00000000" + // NotSentBytes = 0 "00000000" + // NotSentBytes = 0 "00092C3E" + // minRtt = 601150 "3E2C0900" + // minRtt = 601150 "00000000" + // DataSegsIn = 0 "00000000" + // DataSegsIn = 0 "00000000" + // DataSegsOut = 0 "00000000" + // DataSegsOut = 0 "0000000000000000"; // deliverRate = 0 "0000000000000000"; // deliverRate = 0 Loading @@ -162,9 +163,9 @@ public class TcpSocketTrackerTest { private static final String TEST_RESPONSE_HEX = SOCK_DIAG_TCP_INET_HEX private static final String TEST_RESPONSE_HEX = SOCK_DIAG_TCP_INET_HEX // struct nlmsghdr // struct nlmsghdr + "00000014" // length = 20 + "14000000" // length = 20 + "0003" // type = NLMSG_DONE + "0300" // type = NLMSG_DONE + "0103" // flags = NLM_F_REQUEST | NLM_F_DUMP + "0301" // flags = NLM_F_REQUEST | NLM_F_DUMP + "00000000" // seqno + "00000000" // seqno + "00000000" // pid (0 == kernel) + "00000000" // pid (0 == kernel) // struct inet_diag_req_v2 // struct inet_diag_req_v2 Loading @@ -188,9 +189,15 @@ public class TcpSocketTrackerTest { anyInt())).thenReturn(DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE); anyInt())).thenReturn(DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE); } } private ByteBuffer getByteBuffer(final byte[] bytes) { final ByteBuffer buffer = ByteBuffer.wrap(bytes); buffer.order(ByteOrder.LITTLE_ENDIAN); return buffer; } @Test @Test public void testParseSockInfo() { public void testParseSockInfo() { final ByteBuffer buffer = ByteBuffer.wrap(SOCK_DIAG_TCP_INET_BYTES); final ByteBuffer buffer = getByteBuffer(SOCK_DIAG_TCP_INET_BYTES); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); buffer.position(SOCKDIAG_MSG_HEADER_SIZE); buffer.position(SOCKDIAG_MSG_HEADER_SIZE); final TcpSocketTracker.SocketInfo parsed = final TcpSocketTracker.SocketInfo parsed = Loading Loading @@ -269,20 +276,21 @@ public class TcpSocketTrackerTest { when(mDependencies.isTcpInfoParsingSupported()).thenReturn(true); when(mDependencies.isTcpInfoParsingSupported()).thenReturn(true); // No enough bytes remain for a valid NlMsg. // No enough bytes remain for a valid NlMsg. final ByteBuffer invalidBuffer = ByteBuffer.allocate(1); final ByteBuffer invalidBuffer = ByteBuffer.allocate(1); when(mDependencies.recvMesssage(any())).thenReturn(invalidBuffer); invalidBuffer.order(ByteOrder.LITTLE_ENDIAN); when(mDependencies.recvMessage(any())).thenReturn(invalidBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(0, tst.getSentSinceLastRecv()); assertEquals(0, tst.getSentSinceLastRecv()); // Header only. // Header only. final ByteBuffer headerBuffer = ByteBuffer.wrap(SOCK_DIAG_MSG_BYTES); final ByteBuffer headerBuffer = getByteBuffer(SOCK_DIAG_MSG_BYTES); when(mDependencies.recvMesssage(any())).thenReturn(headerBuffer); when(mDependencies.recvMessage(any())).thenReturn(headerBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(0, tst.getSentSinceLastRecv()); assertEquals(0, tst.getSentSinceLastRecv()); final ByteBuffer tcpBuffer = ByteBuffer.wrap(TEST_RESPONSE_BYTES); final ByteBuffer tcpBuffer = getByteBuffer(TEST_RESPONSE_BYTES); when(mDependencies.recvMesssage(any())).thenReturn(tcpBuffer); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); assertEquals(10, tst.getSentSinceLastRecv()); Loading @@ -297,4 +305,50 @@ public class TcpSocketTrackerTest { tst.mConfigListener.onPropertiesChanged(null /* properties */); tst.mConfigListener.onPropertiesChanged(null /* properties */); assertTrue(tst.isDataStallSuspected()); assertTrue(tst.isDataStallSuspected()); } } private static final String BAD_DIAG_MSG_HEX = // struct nlmsghdr. "00000058" + // length = 1476395008 "1400" + // type = SOCK_DIAG_BY_FAMILY "0301" + // flags = NLM_F_REQUEST | NLM_F_DUMP "00000000" + // seqno "00000000" + // pid (0 == kernel) // struct inet_diag_req_v2 "02" + // family = AF_INET "06" + // state "00" + // timer "00" + // retrans // inet_diag_sockid "DEA5" + // idiag_sport = 42462 "71B9" + // idiag_dport = 47473 "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 "00000000" + // idiag_if "34ED000076270000" + // idiag_cookie = 43387759684916 "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue "00000000" + // idiag_uid "00000000"; // idiag_inode private static final byte[] BAD_SOCK_DIAG_MSG_BYTES = HexEncoding.decode(BAD_DIAG_MSG_HEX.toCharArray(), false); @Test public void testPollSocketsInfo_BadFormat() throws Exception { final TcpSocketTracker tst = new TcpSocketTracker(mDependencies); ByteBuffer tcpBuffer = getByteBuffer(TEST_RESPONSE_BYTES); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); assertEquals(50, tst.getLatestPacketFailPercentage()); tcpBuffer = getByteBuffer(BAD_SOCK_DIAG_MSG_BYTES); when(mDependencies.recvMessage(any())).thenReturn(tcpBuffer); assertTrue(tst.pollSocketsInfo()); // Expect no additional packets, so still 10. assertEquals(10, tst.getSentSinceLastRecv()); // Expect to reset to 0. assertEquals(0, tst.getLatestPacketFailPercentage()); } } }