summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChiachang Wang <chiachangwang@google.com>2019-11-26 15:39:22 +0800
committerChiachang Wang <chiachangwang@google.com>2019-11-26 16:18:41 +0800
commit4336b91fb41df54e6dcb855e4b30ab1f30dd3409 (patch)
treec6ebd056e1e117cb8d282bab9c8143e84760c144
parentdc24d1c740fb4350bce476ea3471212ea20c4cad (diff)
Follow up commit of aosp/1157146
Address follow up actions and comments Bug: 130325409 Test: NetworkStackTests NetworkStackNextTests Change-Id: Ic768f08e5e54667e375c0d486df278773d9c707a
-rw-r--r--common/netlinkclient/src/android/net/netlink/NetlinkConstants.java8
-rw-r--r--src/android/net/util/DataStallUtils.java2
-rw-r--r--src/com/android/networkstack/netlink/TcpSocketTracker.java152
-rw-r--r--src/com/android/server/connectivity/NetworkMonitor.java15
-rw-r--r--tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java43
-rw-r--r--tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java18
6 files changed, 151 insertions, 87 deletions
diff --git a/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java b/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java
index 181a361..b8fd4b1 100644
--- a/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java
+++ b/common/netlinkclient/src/android/net/netlink/NetlinkConstants.java
@@ -35,6 +35,14 @@ public class NetlinkConstants {
private NetlinkConstants() {}
public static final int NLA_ALIGNTO = 4;
+ /**
+ * Flag for dumping struct tcp_info.
+ * Corresponding to enum definition in external/strace/linux/inet_diag.h.
+ */
+ public static final int INET_DIAG_MEMINFO = 1;
+
+ public static final int SOCKDIAG_MSG_HEADER_SIZE =
+ StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE;
public static final int alignedLengthOf(short length) {
final int intLength = (int) length & 0xffff;
diff --git a/src/android/net/util/DataStallUtils.java b/src/android/net/util/DataStallUtils.java
index 454faf6..5787879 100644
--- a/src/android/net/util/DataStallUtils.java
+++ b/src/android/net/util/DataStallUtils.java
@@ -98,7 +98,7 @@ public class DataStallUtils {
* Type: int
* Valid values: 0 to 100.
*/
- public static final String CONFIG_TCP_PACKETS_FAIL_RATE = "tcp_packets_fail_rate";
+ public static final String CONFIG_TCP_PACKETS_FAIL_PERCENTAGE = "tcp_packets_fail_percentage";
/** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */
public static final int TCP_ESTABLISHED = 1;
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java
index 8eb81b2..fc762cb 100644
--- a/src/com/android/networkstack/netlink/TcpSocketTracker.java
+++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -16,11 +16,14 @@
package com.android.networkstack.netlink;
import static android.net.netlink.InetDiagMessage.InetDiagReqV2;
+import static android.net.netlink.NetlinkConstants.INET_DIAG_MEMINFO;
+import static android.net.netlink.NetlinkConstants.NLA_ALIGNTO;
import static android.net.netlink.NetlinkConstants.NLMSG_DONE;
+import static android.net.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static android.net.util.DataStallUtils.CONFIG_MIN_PACKETS_THRESHOLD;
-import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_RATE;
+import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_PERCENTAGE;
import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD;
import static android.net.util.DataStallUtils.DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE;
import static android.net.util.DataStallUtils.TCP_MONITOR_STATE_FILTER;
@@ -35,13 +38,15 @@ import static android.system.OsConstants.SOCK_DGRAM;
import static android.system.OsConstants.SOL_SOCKET;
import static android.system.OsConstants.SO_SNDTIMEO;
+import android.content.Context;
import android.net.netlink.NetlinkSocket;
import android.net.netlink.StructInetDiagMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.NetworkStackUtils;
import android.net.util.SocketUtils;
-import android.os.Build;
+import android.os.AsyncTask;
import android.os.SystemClock;
+import android.provider.DeviceConfig;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructTimeval;
@@ -53,7 +58,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.networkstack.apishim.ShimUtils;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
@@ -65,7 +69,7 @@ import java.util.List;
/**
* Class for NetworkStack to send a SockDiag request and parse the returned tcp info.
*
- * This should be only access from the NetworkMonitor statemahcine thread.
+ * This is not thread-safe. This should be only accessed from one thread.
*/
public class TcpSocketTracker {
private static final String TAG = "TcpSocketTracker";
@@ -75,16 +79,6 @@ public class TcpSocketTracker {
private static final int DEFAULT_RECV_BUFSIZE = 60_000;
// Default I/O timeout time in ms of the socket request.
private static final long IO_TIMEOUT = 3_000L;
- // Map to definition in bionic/libc/kernel/uapi/linux/netlink.h.
- private static final int NLMSG_ALIGNTO = 4;
- /**
- * Flag for dumping struct tcp_info.
- * Corresponding to enum definition in external/strace/linux/inet_diag.h.
- */
- private static final int INET_DIAG_MEMINFO = 1;
- @VisibleForTesting
- public static final int SOCKDIAG_MSG_HEADER_SIZE =
- StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE;
/** Cookie offset of an InetMagMessage header. */
private static final int IDIAG_COOKIE_OFFSET = 44;
/**
@@ -98,7 +92,9 @@ public class TcpSocketTracker {
// Number of packets sent since the last received packet
private int mSentSinceLastRecv;
// The latest fail rate calculated by the latest tcp info.
- private int mLatestPacketFailRate;
+ private int mLatestPacketFailPercentage;
+ // Number of packets received in the latest polling cycle.
+ private int mLatestReceivedCount;
/**
* Request to send to kernel to request tcp info.
*
@@ -106,15 +102,30 @@ public class TcpSocketTracker {
* Value: Bytes array represent the {@Code InetDiagReqV2}.
*/
private final SparseArray<byte[]> mSockDiagMsg = new SparseArray<>();
+ private final Dependencies mDependencies;
+ private int mMinPacketsThreshold = DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD;
+ private int mTcpPacketsFailRateThreshold = DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE;
@VisibleForTesting
- public final Dependencies mDependencies;
+ protected final DeviceConfig.OnPropertiesChangedListener mConfigListener =
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ mMinPacketsThreshold = mDependencies.getDeviceConfigPropertyInt(
+ NAMESPACE_CONNECTIVITY,
+ CONFIG_MIN_PACKETS_THRESHOLD,
+ DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD);
+ mTcpPacketsFailRateThreshold = mDependencies.getDeviceConfigPropertyInt(
+ NAMESPACE_CONNECTIVITY,
+ CONFIG_TCP_PACKETS_FAIL_PERCENTAGE,
+ DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE);
+ }
+ };
- public TcpSocketTracker(Dependencies dps) {
+ public TcpSocketTracker(@NonNull final Dependencies dps) {
+ mDependencies = dps;
// Request tcp info from NetworkStack directly needs extra SELinux permission added after Q
// release.
- mDependencies = dps;
if (!mDependencies.isTcpInfoParsingSupported()) return;
-
// Build SocketDiag messages.
for (final int family : ADDRESS_FAMILIES) {
mSockDiagMsg.put(
@@ -128,14 +139,14 @@ public class TcpSocketTracker {
1 << INET_DIAG_MEMINFO /* idiagExt */,
TCP_MONITOR_STATE_FILTER));
}
+ mDependencies.addDeviceConfigChangedListener(mConfigListener);
}
/**
* Request to send a SockDiag Netlink request. Receive and parse the returned message. This
- * function should only be called from statemachine thread of NetworkMonitor.
+ * function is not thread-safe and should only be called from only one thread.
*
* @Return if this polling request executes successfully or not.
- *
* TODO: Need to filter socket info based on the target network.
*/
public boolean pollSocketsInfo() {
@@ -143,7 +154,7 @@ public class TcpSocketTracker {
FileDescriptor fd = null;
try {
final long time = SystemClock.elapsedRealtime();
- fd = mDependencies.connectToKernel();
+ fd = mDependencies.connectToKernel();
final TcpStat stat = new TcpStat();
for (final int family : ADDRESS_FAMILIES) {
@@ -163,6 +174,10 @@ public class TcpSocketTracker {
while (enoughBytesRemainForValidNlMsg(bytes)) {
final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes);
+ if (nlmsghdr == null) {
+ Log.e(TAG, "Badly formatted data.");
+ break;
+ }
final int nlmsgLen = nlmsghdr.nlmsg_len;
log("pollSocketsInfo: nlmsghdr=" + nlmsghdr);
if (nlmsghdr.nlmsg_type == NLMSG_DONE) break;
@@ -175,19 +190,20 @@ public class TcpSocketTracker {
// It's stored in native with 2 int. Parse it as long for convenience.
final long cookie = bytes.getLong();
// Skip the rest part of StructInetDiagMsg.
- bytes.position(bytes.position() + 5 * Integer.BYTES);
- final SocketInfo info =
- parseSockInfo(bytes, family, nlmsgLen, time);
+ bytes.position(bytes.position()
+ + StructInetDiagMsg.STRUCT_SIZE - IDIAG_COOKIE_OFFSET - Long.BYTES);
+ final SocketInfo info = parseSockInfo(bytes, family, nlmsgLen, time);
// Update TcpStats based on previous and current socket info.
stat.accumulate(calculateLatestPacketsStat(info, mSocketInfos.get(cookie)));
mSocketInfos.put(cookie, info);
}
}
}
- // Calculate mSentSinceLastRecv and mLatestPacketFailRate.
+ // Calculate mLatestReceiveCount, mSentSinceLastRecv and mLatestPacketFailPercentage.
mSentSinceLastRecv = (stat.receivedCount == 0)
? (mSentSinceLastRecv + stat.sentCount) : 0;
- mLatestPacketFailRate = ((stat.sentCount != 0)
+ mLatestReceivedCount = stat.receivedCount;
+ mLatestPacketFailPercentage = ((stat.sentCount != 0)
? ((stat.retransmitCount + stat.lostCount) * 100 / stat.sentCount) : 0);
// Remove out-of-date socket info.
@@ -252,20 +268,25 @@ public class TcpSocketTracker {
*/
public boolean isDataStallSuspected() {
if (!mDependencies.isTcpInfoParsingSupported()) return false;
- return (getLatestPacketFailRate() >= getTcpPacketsFailRateThreshold());
+ return (getLatestPacketFailPercentage() >= getTcpPacketsFailRateThreshold());
}
/** Calculate the change between the {@param current} and {@param previous}. */
+ @Nullable
private TcpStat calculateLatestPacketsStat(@NonNull final SocketInfo current,
@Nullable final SocketInfo previous) {
final TcpStat stat = new TcpStat();
- if (current.tcpInfo != null) {
- stat.sentCount = current.tcpInfo.getValue(TcpInfo.Field.SEGS_OUT).intValue();
- stat.receivedCount = current.tcpInfo.getValue(TcpInfo.Field.SEGS_IN).intValue();
- stat.lostCount = current.tcpInfo.getValue(TcpInfo.Field.LOST).intValue();
- stat.retransmitCount = current.tcpInfo.getValue(TcpInfo.Field.RETRANSMITS).intValue();
+ if (current.tcpInfo == null) {
+ log("Current tcpInfo is null.");
+ return null;
}
+
+ stat.sentCount = current.tcpInfo.getValue(TcpInfo.Field.SEGS_OUT).intValue();
+ stat.receivedCount = current.tcpInfo.getValue(TcpInfo.Field.SEGS_IN).intValue();
+ stat.lostCount = current.tcpInfo.getValue(TcpInfo.Field.LOST).intValue();
+ stat.retransmitCount = current.tcpInfo.getValue(TcpInfo.Field.RETRANSMITS).intValue();
+
if (previous != null && previous.tcpInfo != null) {
stat.sentCount -= previous.tcpInfo.getValue(TcpInfo.Field.SEGS_OUT).intValue();
stat.receivedCount -= previous.tcpInfo.getValue(TcpInfo.Field.SEGS_IN).intValue();
@@ -278,12 +299,14 @@ public class TcpSocketTracker {
/**
* Get tcp connection fail rate based on packet lost and retransmission count.
+ *
+ * @return the latest packet fail percentage. -1 denotes that there is no available data.
*/
- public int getLatestPacketFailRate() {
- if (!mDependencies.isTcpInfoParsingSupported()) return 0;
+ public int getLatestPacketFailPercentage() {
+ if (!mDependencies.isTcpInfoParsingSupported()) return -1;
// Only return fail rate if device sent enough packets.
- if (getSentSinceLastRecv() < getMinPacketsThreshold()) return 0;
- return mLatestPacketFailRate;
+ if (getSentSinceLastRecv() < getMinPacketsThreshold()) return -1;
+ return mLatestPacketFailPercentage;
}
/**
@@ -291,18 +314,14 @@ public class TcpSocketTracker {
* between each polling period, not an accurate number.
*/
public int getSentSinceLastRecv() {
- if (!mDependencies.isTcpInfoParsingSupported()) return 0;
+ if (!mDependencies.isTcpInfoParsingSupported()) return -1;
return mSentSinceLastRecv;
}
- private int getMinPacketsThreshold() {
- return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
- CONFIG_MIN_PACKETS_THRESHOLD, DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD);
- }
-
- private int getTcpPacketsFailRateThreshold() {
- return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
- CONFIG_TCP_PACKETS_FAIL_RATE, DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE);
+ /** Return the number of the packets received in the latest polling cycle. */
+ public int getLatestReceivedCount() {
+ if (!mDependencies.isTcpInfoParsingSupported()) return -1;
+ return mLatestReceivedCount;
}
/** Check if the length and position of the given ByteBuffer is valid for a nlmsghdr message. */
@@ -315,6 +334,14 @@ public class TcpSocketTracker {
return nlMsgLen >= SOCKDIAG_MSG_HEADER_SIZE;
}
+ private int getMinPacketsThreshold() {
+ return mMinPacketsThreshold;
+ }
+
+ private int getTcpPacketsFailRateThreshold() {
+ return mTcpPacketsFailRateThreshold;
+ }
+
/**
* Method to skip the remaining attributes bytes.
* Corresponds to NLMSG_NEXT in bionic/libc/kernel/uapi/linux/netlink.h.
@@ -324,12 +351,12 @@ public class TcpSocketTracker {
*/
private void skipRemainingAttributesBytesAligned(@NonNull final ByteBuffer buffer,
final int len) {
- // Data in {@Code RoutingAttribute} is followed after header with size {@Code NLMSG_ALIGNTO}
+ // Data in {@Code RoutingAttribute} is followed after header with size {@Code NLA_ALIGNTO}
// bytes long for each block. Next attribute will start after the padding bytes if any.
// If all remaining bytes after header are valid in a data block, next attr will just start
// after valid bytes.
//
- // E.g. With NLMSG_ALIGNTO(4), an attr struct with length 5 means 1 byte valid data remains
+ // E.g. With NLA_ALIGNTO(4), an attr struct with length 5 means 1 byte valid data remains
// after header and 3(4-1) padding bytes. Next attr with length 8 will start after the
// padding bytes and contain 4(8-4) valid bytes of data. The next attr start after the
// valid bytes, like:
@@ -337,7 +364,7 @@ public class TcpSocketTracker {
// [HEADER(L=5)][ 4-Bytes DATA ][ HEADER(L=8) ][4 bytes DATA][Next attr]
// [ 5 valid bytes ][3 padding bytes ][ 8 valid bytes ] ...
final int cur = buffer.position();
- buffer.position(cur + ((len + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)));
+ buffer.position(cur + ((len + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)));
}
private void log(final String str) {
@@ -423,7 +450,9 @@ public class TcpSocketTracker {
public int retransmitCount;
public int receivedCount;
- void accumulate(final TcpStat stat) {
+ void accumulate(@Nullable final TcpStat stat) {
+ if (stat == null) return;
+
sentCount += stat.sentCount;
lostCount += stat.lostCount;
receivedCount += stat.receivedCount;
@@ -431,12 +460,19 @@ public class TcpSocketTracker {
}
}
-
/**
* Dependencies class for testing.
*/
@VisibleForTesting
public static class Dependencies {
+ private final Context mContext;
+ private final boolean mIsTcpInfoParsingSupported;
+
+ public Dependencies(final Context context, final boolean tcpSupport) {
+ mContext = context;
+ mIsTcpInfoParsingSupported = tcpSupport;
+ }
+
/**
* Connect to kernel via netlink socket.
*
@@ -451,6 +487,7 @@ public class TcpSocketTracker {
return fd;
}
+
/**
* Send composed message request to kernel.
* @param fd see {@Code FileDescriptor}
@@ -484,7 +521,7 @@ public class TcpSocketTracker {
public boolean isTcpInfoParsingSupported() {
// Request tcp info from NetworkStack directly needs extra SELinux permission added
// after Q release.
- return ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q);
+ return mIsTcpInfoParsingSupported;
}
/**
@@ -494,5 +531,16 @@ public class TcpSocketTracker {
throws ErrnoException, InterruptedIOException {
return NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
}
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ /** Add device config change listener */
+ public void addDeviceConfigChangedListener(
+ @NonNull final DeviceConfig.OnPropertiesChangedListener listener) {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CONNECTIVITY,
+ AsyncTask.THREAD_POOL_EXECUTOR, listener);
+ }
}
}
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index 63c294c..3dfe004 100644
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -126,6 +126,7 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.TrafficStatsConstants;
import com.android.networkstack.R;
+import com.android.networkstack.apishim.ShimUtils;
import com.android.networkstack.metrics.DataStallDetectionStats;
import com.android.networkstack.metrics.DataStallStatsUtils;
import com.android.networkstack.netlink.TcpSocketTracker;
@@ -389,13 +390,15 @@ public class NetworkMonitor extends StateMachine {
public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
SharedLog validationLog) {
this(context, cb, network, new IpConnectivityLog(), validationLog,
- Dependencies.DEFAULT, new DataStallStatsUtils());
+ Dependencies.DEFAULT, new DataStallStatsUtils(), new TcpSocketTracker(
+ new TcpSocketTracker.Dependencies(context,
+ ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q))));
}
@VisibleForTesting
public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
IpConnectivityLog logger, SharedLog validationLogs,
- Dependencies deps, DataStallStatsUtils detectionStatsUtils) {
+ Dependencies deps, DataStallStatsUtils detectionStatsUtils, TcpSocketTracker tst) {
// Add suffix indicating which NetworkMonitor we're talking about.
super(TAG + "/" + network.toString());
@@ -442,7 +445,7 @@ public class NetworkMonitor extends StateMachine {
mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
mDataStallEvaluationType = getDataStallEvaluationType();
- mTcpTracker = new TcpSocketTracker(new TcpSocketTracker.Dependencies());
+ mTcpTracker = tst;
// Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
// even before notifyNetworkConnected.
@@ -2139,7 +2142,7 @@ public class NetworkMonitor extends StateMachine {
// 2. Accumulate enough packets count.
// TODO: Need to filter per target network.
if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_TCP)) {
- if (getTcpSocketTracker().getSentSinceLastRecv() > 0) {
+ if (getTcpSocketTracker().getLatestReceivedCount() > 0) {
result = false;
} else if (getTcpSocketTracker().isDataStallSuspected()) {
result = true;
@@ -2160,8 +2163,8 @@ public class NetworkMonitor extends StateMachine {
if (VDBG_STALL) {
log("isDataStall: result=" + result + ", consecutive dns timeout count="
+ mDnsStallDetector.getConsecutiveTimeoutCount()
- + ", tcp packets received=" + getTcpSocketTracker().getSentSinceLastRecv()
- + ", tcp fail rate=" + getTcpSocketTracker().getLatestPacketFailRate());
+ + ", tcp packets received=" + getTcpSocketTracker().getLatestReceivedCount()
+ + ", tcp fail rate=" + getTcpSocketTracker().getLatestPacketFailPercentage());
}
return (result == null) ? false : result;
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
index aa94b76..6a92d8a 100644
--- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
+++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -16,13 +16,12 @@
package com.android.networkstack.netlink;
-import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_RATE;
+import static android.net.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE;
+import static android.net.util.DataStallUtils.CONFIG_TCP_PACKETS_FAIL_PERCENTAGE;
import static android.net.util.DataStallUtils.DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
import static android.system.OsConstants.AF_INET;
-import static com.android.networkstack.netlink.TcpSocketTracker.SOCKDIAG_MSG_HEADER_SIZE;
-
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -111,7 +110,7 @@ public class TcpSocketTrackerTest {
"00000000" + // data
"0008" + // len = 8
"000F" + // type = 15(INET_DIAG_MARK)
- "000C0064" + // data, socket mark=786532
+ "000C1A85" + // data, socket mark=793221
"00AC" + // len = 172
"0002" + // type = 2(INET_DIAG_INFO)
// tcp_info
@@ -129,7 +128,7 @@ public class TcpSocketTrackerTest {
"00000218" + // rcvMss = 536
"00000000" + // unsacked = 0
"00000000" + // acked = 0
- "00000005" + // lost = 5
+ "00000000" + // lost = 0
"00000000" + // retrans = 0
"00000000" + // fackets = 0
"000000BB" + // lastDataSent = 187
@@ -185,7 +184,7 @@ public class TcpSocketTrackerTest {
when(mDependencies.connectToKernel()).thenReturn(mMockFd);
when(mDependencies.getDeviceConfigPropertyInt(
eq(NAMESPACE_CONNECTIVITY),
- eq(CONFIG_TCP_PACKETS_FAIL_RATE),
+ eq(CONFIG_TCP_PACKETS_FAIL_PERCENTAGE),
anyInt())).thenReturn(DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE);
}
@@ -211,7 +210,7 @@ public class TcpSocketTrackerTest {
expected.put(TcpInfo.Field.RCV_MSS, 536);
expected.put(TcpInfo.Field.UNACKED, 0);
expected.put(TcpInfo.Field.SACKED, 0);
- expected.put(TcpInfo.Field.LOST, 5);
+ expected.put(TcpInfo.Field.LOST, 0);
expected.put(TcpInfo.Field.RETRANS, 0);
expected.put(TcpInfo.Field.FACKETS, 0);
expected.put(TcpInfo.Field.LAST_DATA_SENT, 187);
@@ -242,7 +241,7 @@ public class TcpSocketTrackerTest {
expected.put(TcpInfo.Field.DELIVERY_RATE, 0L);
assertEquals(parsed.tcpInfo, new TcpInfo(expected));
- assertEquals(parsed.fwmark, 786532);
+ assertEquals(parsed.fwmark, 793221);
assertEquals(parsed.updateTime, 100);
assertEquals(parsed.ipFamily, AF_INET);
}
@@ -262,18 +261,6 @@ public class TcpSocketTrackerTest {
}
@Test
- public void testIsDataStallSuspected() {
- when(mDependencies.isTcpInfoParsingSupported()).thenReturn(false);
- final TcpSocketTracker tst = new TcpSocketTracker(mDependencies);
- assertFalse(tst.isDataStallSuspected());
- when(mDependencies.isTcpInfoParsingSupported()).thenReturn(true);
- assertFalse(tst.isDataStallSuspected());
- when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CONFIG_TCP_PACKETS_FAIL_RATE),
- anyInt())).thenReturn(0);
- assertTrue(tst.isDataStallSuspected());
- }
-
- @Test
public void testPollSocketsInfo() throws Exception {
when(mDependencies.isTcpInfoParsingSupported()).thenReturn(false);
final TcpSocketTracker tst = new TcpSocketTracker(mDependencies);
@@ -284,20 +271,30 @@ public class TcpSocketTrackerTest {
final ByteBuffer invalidBuffer = ByteBuffer.allocate(1);
when(mDependencies.recvMesssage(any())).thenReturn(invalidBuffer);
assertTrue(tst.pollSocketsInfo());
- assertEquals(0, tst.getLatestPacketFailRate());
+ assertEquals(-1, tst.getLatestPacketFailPercentage());
assertEquals(0, tst.getSentSinceLastRecv());
// Header only.
final ByteBuffer headerBuffer = ByteBuffer.wrap(SOCK_DIAG_MSG_BYTES);
when(mDependencies.recvMesssage(any())).thenReturn(headerBuffer);
assertTrue(tst.pollSocketsInfo());
+ assertEquals(-1, tst.getLatestPacketFailPercentage());
assertEquals(0, tst.getSentSinceLastRecv());
- assertEquals(0, tst.getLatestPacketFailRate());
final ByteBuffer tcpBuffer = ByteBuffer.wrap(TEST_RESPONSE_BYTES);
when(mDependencies.recvMesssage(any())).thenReturn(tcpBuffer);
assertTrue(tst.pollSocketsInfo());
+
assertEquals(10, tst.getSentSinceLastRecv());
- assertEquals(100, tst.getLatestPacketFailRate());
+ assertEquals(50, tst.getLatestPacketFailPercentage());
+ assertFalse(tst.isDataStallSuspected());
+ // Lower the threshold.
+ when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CONFIG_TCP_PACKETS_FAIL_PERCENTAGE),
+ anyInt())).thenReturn(40);
+ // No device config change. Using cache value.
+ assertFalse(tst.isDataStallSuspected());
+ // Trigger a config update
+ tst.mConfigListener.onPropertiesChanged(null /* properties */);
+ assertTrue(tst.isDataStallSuspected());
}
}
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index 21dfb2f..75491ec 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -154,7 +154,7 @@ public class NetworkMonitorTest {
private @Mock WifiInfo mWifiInfo;
private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
private @Mock TcpSocketTracker.Dependencies mTstDependencies;
-
+ private @Mock TcpSocketTracker mTst;
private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
private HashSet<BroadcastReceiver> mRegisteredReceivers;
@@ -449,11 +449,10 @@ public class NetworkMonitorTest {
private class WrappedNetworkMonitor extends NetworkMonitor {
private long mProbeTime = 0;
private final ConditionVariable mQuitCv = new ConditionVariable(false);
- private final TcpSocketTracker mTst = new TcpSocketTracker(mTstDependencies);
WrappedNetworkMonitor() {
super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
- mDependencies, mDataStallStatsUtils);
+ mDependencies, mDataStallStatsUtils, mTst);
}
@Override
@@ -494,6 +493,7 @@ public class NetworkMonitorTest {
HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
mCreatedNetworkMonitors.add(nm);
when(mTstDependencies.isTcpInfoParsingSupported()).thenReturn(false);
+
return nm;
}
@@ -753,8 +753,16 @@ public class NetworkMonitorTest {
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertFalse(wrappedMonitor.isDataStall());
-
- when(wrappedMonitor.getTcpSocketTracker().isDataStallSuspected()).thenReturn(true);
+ // Packet received.
+ when(mTstDependencies.isTcpInfoParsingSupported()).thenReturn(true);
+ when(mTst.getLatestReceivedCount()).thenReturn(5);
+ // Trigger a tcp event immediately.
+ setTcpPollingInterval(0);
+ wrappedMonitor.sendTcpPollingEvent();
+ HandlerUtilsKt.waitForIdle(wrappedMonitor.getHandler(), HANDLER_TIMEOUT_MS);
+ assertFalse(wrappedMonitor.isDataStall());
+ when(mTst.getLatestReceivedCount()).thenReturn(0);
+ when(mTst.isDataStallSuspected()).thenReturn(true);
// Trigger a tcp event immediately.
setTcpPollingInterval(0);
wrappedMonitor.sendTcpPollingEvent();