Merge "Add NetworkStack utilities for reading text"
diff --git a/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java b/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
index 29d8506..762a8b8 100644
--- a/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
+++ b/apishim/29/com/android/networkstack/apishim/api29/ConstantsShim.java
@@ -24,7 +24,7 @@
public static final int DETECTION_METHOD_DNS_EVENTS = 1;
public static final int DETECTION_METHOD_TCP_METRICS = 2;
public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
- public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+ public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
diff --git a/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java b/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
index 00b4e19..7de376a 100644
--- a/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
+++ b/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
@@ -16,14 +16,25 @@
package android.net.shared;
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.INetd;
+import android.net.InformationElementParcelable;
import android.net.Network;
import android.net.ProvisioningConfigurationParcelable;
+import android.net.ScanResultInfoParcelable;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
import android.net.ip.IIpClient;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
@@ -193,6 +204,17 @@
}
/**
+ * Specify the information elements included in wifi scan result that was obtained
+ * prior to connecting to the access point, if this is a WiFi network.
+ *
+ * <p>The scan result can be used to infer whether the network is metered.
+ */
+ public Builder withScanResultInfo(ScanResultInfo scanResultInfo) {
+ mConfig.mScanResultInfo = scanResultInfo;
+ return this;
+ }
+
+ /**
* Build the configuration using previously specified parameters.
*/
public ProvisioningConfiguration build() {
@@ -200,6 +222,158 @@
}
}
+ /**
+ * Class wrapper of {@link android.net.wifi.ScanResult} to encapsulate the SSID and
+ * InformationElements fields of ScanResult.
+ */
+ public static class ScanResultInfo {
+ private final String mSsid;
+ private final List<InformationElement> mInformationElements;
+
+ /**
+ * Class wrapper of {@link android.net.wifi.ScanResult.InformationElement} to encapsulate
+ * the specific IE id and payload fields.
+ */
+ public static class InformationElement {
+ private final int mId;
+ private final byte[] mPayload;
+
+ public InformationElement(int id, @NonNull ByteBuffer payload) {
+ mId = id;
+ mPayload = convertToByteArray(payload.asReadOnlyBuffer());
+ }
+
+ /**
+ * Get the element ID of the information element.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Get the specific content of the information element.
+ */
+ public ByteBuffer getPayload() {
+ return ByteBuffer.wrap(mPayload).asReadOnlyBuffer();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof InformationElement)) return false;
+ InformationElement other = (InformationElement) o;
+ return mId == other.mId && Arrays.equals(mPayload, other.mPayload);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mPayload);
+ }
+
+ @Override
+ public String toString() {
+ return "ID: " + mId + ", " + Arrays.toString(mPayload);
+ }
+
+ /**
+ * Convert this InformationElement to a {@link InformationElementParcelable}.
+ */
+ public InformationElementParcelable toStableParcelable() {
+ final InformationElementParcelable p = new InformationElementParcelable();
+ p.id = mId;
+ p.payload = mPayload.clone();
+ return p;
+ }
+
+ /**
+ * Create an instance of {@link InformationElement} based on the contents of the
+ * specified {@link InformationElementParcelable}.
+ */
+ public static InformationElement fromStableParcelable(InformationElementParcelable p) {
+ if (p == null) return null;
+ return new InformationElement(p.id,
+ ByteBuffer.wrap(p.payload.clone()).asReadOnlyBuffer());
+ }
+ }
+
+ public ScanResultInfo(String ssid, @NonNull List<InformationElement> informationElements) {
+ mSsid = ssid;
+ mInformationElements =
+ Collections.unmodifiableList(new ArrayList<>(informationElements));
+ }
+
+ /**
+ * Get the scanned network name.
+ */
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /**
+ * Get all information elements found in the beacon.
+ */
+ public List<InformationElement> getInformationElements() {
+ return mInformationElements;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer str = new StringBuffer();
+ str.append("SSID: ").append(mSsid);
+ str.append(", Information Elements: {");
+ for (InformationElement ie : mInformationElements) {
+ str.append("[").append(ie.toString()).append("]");
+ }
+ str.append("}");
+ return str.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof ScanResultInfo)) return false;
+ ScanResultInfo other = (ScanResultInfo) o;
+ return Objects.equals(mSsid, other.mSsid)
+ && mInformationElements.equals(other.mInformationElements);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSsid, mInformationElements);
+ }
+
+ /**
+ * Convert this ScanResultInfo to a {@link ScanResultInfoParcelable}.
+ */
+ public ScanResultInfoParcelable toStableParcelable() {
+ final ScanResultInfoParcelable p = new ScanResultInfoParcelable();
+ p.ssid = mSsid;
+ p.informationElements = toParcelableArray(mInformationElements,
+ InformationElement::toStableParcelable, InformationElementParcelable.class);
+ return p;
+ }
+
+ /**
+ * Create an instance of {@link ScanResultInfo} based on the contents of the specified
+ * {@link ScanResultInfoParcelable}.
+ */
+ public static ScanResultInfo fromStableParcelable(ScanResultInfoParcelable p) {
+ if (p == null) return null;
+ final List<InformationElement> ies = new ArrayList<InformationElement>();
+ ies.addAll(fromParcelableArray(p.informationElements,
+ InformationElement::fromStableParcelable));
+ return new ScanResultInfo(p.ssid, ies);
+ }
+
+ private static byte[] convertToByteArray(final ByteBuffer buffer) {
+ if (buffer == null) return null;
+ byte[] bytes = new byte[buffer.limit()];
+ final ByteBuffer copy = buffer.asReadOnlyBuffer();
+ copy.get(bytes);
+ return bytes;
+ }
+ }
+
public boolean mEnableIPv4 = true;
public boolean mEnableIPv6 = true;
public boolean mEnablePreconnection = false;
@@ -213,6 +387,7 @@
public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
public Network mNetwork = null;
public String mDisplayName = null;
+ public ScanResultInfo mScanResultInfo;
public ProvisioningConfiguration() {} // used by Builder
@@ -232,6 +407,7 @@
mIPv6AddrGenMode = other.mIPv6AddrGenMode;
mNetwork = other.mNetwork;
mDisplayName = other.mDisplayName;
+ mScanResultInfo = other.mScanResultInfo;
}
/**
@@ -254,6 +430,7 @@
p.ipv6AddrGenMode = mIPv6AddrGenMode;
p.network = mNetwork;
p.displayName = mDisplayName;
+ p.scanResultInfo = mScanResultInfo == null ? null : mScanResultInfo.toStableParcelable();
return p;
}
@@ -279,6 +456,7 @@
config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
config.mNetwork = p.network;
config.mDisplayName = p.displayName;
+ config.mScanResultInfo = ScanResultInfo.fromStableParcelable(p.scanResultInfo);
return config;
}
@@ -298,6 +476,7 @@
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
.add("mNetwork: " + mNetwork)
.add("mDisplayName: " + mDisplayName)
+ .add("mScanResultInfo: " + mScanResultInfo)
.toString();
}
@@ -317,7 +496,8 @@
&& mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
&& mIPv6AddrGenMode == other.mIPv6AddrGenMode
&& Objects.equals(mNetwork, other.mNetwork)
- && Objects.equals(mDisplayName, other.mDisplayName);
+ && Objects.equals(mDisplayName, other.mDisplayName)
+ && Objects.equals(mScanResultInfo, other.mScanResultInfo);
}
public boolean isValid() {
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp
index 31f3384..dbe8ff0 100644
--- a/common/networkstackclient/Android.bp
+++ b/common/networkstackclient/Android.bp
@@ -45,6 +45,7 @@
include_dirs: [
"frameworks/base/core/java", // For framework parcelables.
"frameworks/native/aidl/binder/android/os", // For PersistableBundle.aidl
+ "frameworks/base/wifi/aidl-export", // For wifi parcelables.
],
srcs: [
"src/android/net/DhcpResultsParcelable.aidl",
@@ -53,10 +54,12 @@
"src/android/net/INetworkStackConnector.aidl",
"src/android/net/INetworkStackStatusCallback.aidl",
"src/android/net/InitialConfigurationParcelable.aidl",
+ "src/android/net/InformationElementParcelable.aidl",
"src/android/net/Layer2PacketParcelable.aidl",
"src/android/net/NattKeepalivePacketDataParcelable.aidl",
"src/android/net/PrivateDnsConfigParcel.aidl",
"src/android/net/ProvisioningConfigurationParcelable.aidl",
+ "src/android/net/ScanResultInfoParcelable.aidl",
"src/android/net/TcpKeepalivePacketDataParcelable.aidl",
"src/android/net/dhcp/DhcpServingParamsParcel.aidl",
"src/android/net/dhcp/IDhcpServer.aidl",
diff --git a/common/networkstackclient/src/android/net/InformationElementParcelable.aidl b/common/networkstackclient/src/android/net/InformationElementParcelable.aidl
new file mode 100644
index 0000000..c70bf6f
--- /dev/null
+++ b/common/networkstackclient/src/android/net/InformationElementParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable InformationElementParcelable {
+ int id;
+ byte[] payload;
+}
diff --git a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
index 0b6d7d5..9fcb036 100644
--- a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
+++ b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
@@ -19,6 +19,7 @@
import android.net.InitialConfigurationParcelable;
import android.net.Network;
+import android.net.ScanResultInfoParcelable;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
@@ -36,4 +37,5 @@
Network network;
String displayName;
boolean enablePreconnection;
+ ScanResultInfoParcelable scanResultInfo;
}
diff --git a/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl
new file mode 100644
index 0000000..f5f101d
--- /dev/null
+++ b/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.InformationElementParcelable;
+
+parcelable ScanResultInfoParcelable {
+ String ssid;
+ InformationElementParcelable[] informationElements;
+}
diff --git a/src/com/android/networkstack/netlink/TcpInfo.java b/src/com/android/networkstack/netlink/TcpInfo.java
index e6036b5..31a408f 100644
--- a/src/com/android/networkstack/netlink/TcpInfo.java
+++ b/src/com/android/networkstack/netlink/TcpInfo.java
@@ -22,11 +22,9 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
import java.util.Objects;
/**
@@ -91,27 +89,39 @@
}
private static final String TAG = "TcpInfo";
- private final Map<Field, Number> mFieldsValues;
+ @VisibleForTesting
+ static final int LOST_OFFSET = getFieldOffset(Field.LOST);
+ @VisibleForTesting
+ static final int RETRANSMITS_OFFSET = getFieldOffset(Field.RETRANSMITS);
+ @VisibleForTesting
+ static final int SEGS_IN_OFFSET = getFieldOffset(Field.SEGS_IN);
+ @VisibleForTesting
+ static final int SEGS_OUT_OFFSET = getFieldOffset(Field.SEGS_OUT);
+ final int mSegsIn;
+ final int mSegsOut;
+ final int mLost;
+ final int mRetransmits;
+
+ private static int getFieldOffset(@NonNull final Field needle) {
+ int offset = 0;
+ for (final Field field : Field.values()) {
+ if (field == needle) return offset;
+ offset += field.size;
+ }
+ throw new IllegalArgumentException("Unknown field");
+ }
private TcpInfo(@NonNull ByteBuffer bytes, int infolen) {
- final int start = bytes.position();
- final LinkedHashMap<Field, Number> fields = new LinkedHashMap<>();
- for (final Field field : Field.values()) {
- switch (field.size) {
- case Byte.BYTES:
- fields.put(field, getByte(bytes, start, infolen));
- break;
- case Integer.BYTES:
- fields.put(field, getInt(bytes, start, infolen));
- break;
- case Long.BYTES:
- fields.put(field, getLong(bytes, start, infolen));
- break;
- default:
- Log.e(TAG, "Unexpected size:" + field.size);
- }
+ // SEGS_IN is the last required field in the buffer, so if the buffer is long enough for
+ // SEGS_IN it's long enough for everything
+ if (SEGS_IN_OFFSET + Field.SEGS_IN.size > infolen) {
+ throw new IllegalArgumentException("Length " + infolen + " is less than required.");
}
- mFieldsValues = Collections.unmodifiableMap(fields);
+ final int start = bytes.position();
+ mSegsIn = bytes.getInt(start + SEGS_IN_OFFSET);
+ mSegsOut = bytes.getInt(start + SEGS_OUT_OFFSET);
+ mLost = bytes.getInt(start + LOST_OFFSET);
+ mRetransmits = bytes.get(start + RETRANSMITS_OFFSET);
// 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.
@@ -119,12 +129,11 @@
}
@VisibleForTesting
- TcpInfo(@NonNull Map<Field, Number> info) {
- final LinkedHashMap<Field, Number> fields = new LinkedHashMap<>();
- for (final Field field : Field.values()) {
- fields.put(field, info.get(field));
- }
- mFieldsValues = Collections.unmodifiableMap(fields);
+ TcpInfo(int retransmits, int lost, int segsOut, int segsIn) {
+ mRetransmits = retransmits;
+ mLost = lost;
+ mSegsOut = segsOut;
+ mSegsIn = segsIn;
}
/** Parse a TcpInfo from a giving ByteBuffer with a specific length. */
@@ -132,53 +141,13 @@
public static TcpInfo parse(@NonNull ByteBuffer bytes, int infolen) {
try {
return new TcpInfo(bytes, infolen);
- } catch (BufferUnderflowException | IllegalArgumentException e) {
+ } catch (BufferUnderflowException | BufferOverflowException | IllegalArgumentException
+ | IndexOutOfBoundsException e) {
Log.e(TAG, "parsing error.", e);
return null;
}
}
- /**
- * Helper function for handling different struct tcp_info versions in the kernel.
- */
- private static boolean isValidTargetPosition(int start, int len, int pos, int targetBytes)
- throws IllegalArgumentException {
- // Equivalent to new Range(start, start + len).contains(new Range(pos, pos + targetBytes))
- if (len < 0 || targetBytes < 0) throw new IllegalArgumentException();
- // Check that start < pos < start + len
- if (pos < start || pos > start + len) return false;
- // Pos is inside the range and targetBytes is positive. Offset is valid if end of 2nd range
- // is below end of 1st range.
- return pos + targetBytes <= start + len;
- }
-
- /** Get value for specific key. */
- @Nullable
- public Number getValue(@NonNull Field key) {
- return mFieldsValues.get(key);
- }
-
- @Nullable
- private static Byte getByte(@NonNull ByteBuffer buffer, int start, int len) {
- if (!isValidTargetPosition(start, len, buffer.position(), Byte.BYTES)) return null;
-
- return buffer.get();
- }
-
- @Nullable
- private static Integer getInt(@NonNull ByteBuffer buffer, int start, int len) {
- if (!isValidTargetPosition(start, len, buffer.position(), Integer.BYTES)) return null;
-
- return buffer.getInt();
- }
-
- @Nullable
- private static Long getLong(@NonNull ByteBuffer buffer, int start, int len) {
- if (!isValidTargetPosition(start, len, buffer.position(), Long.BYTES)) return null;
-
- return buffer.getLong();
- }
-
private static String decodeWscale(byte num) {
return String.valueOf((num >> 4) & 0x0f) + ":" + String.valueOf(num & 0x0f);
}
@@ -210,33 +179,18 @@
if (!(obj instanceof TcpInfo)) return false;
TcpInfo other = (TcpInfo) obj;
- for (final Field key : mFieldsValues.keySet()) {
- if (!Objects.equals(mFieldsValues.get(key), other.mFieldsValues.get(key))) {
- return false;
- }
- }
- return true;
+ return mSegsIn == other.mSegsIn && mSegsOut == other.mSegsOut
+ && mRetransmits == other.mRetransmits && mLost == other.mLost;
}
@Override
public int hashCode() {
- return Objects.hash(mFieldsValues.values().toArray());
+ return Objects.hash(mLost, mRetransmits, mSegsIn, mSegsOut);
}
@Override
public String toString() {
- String str = "TcpInfo{ ";
- for (final Field key : mFieldsValues.keySet()) {
- str += key.name().toLowerCase() + "=";
- if (key == Field.STATE) {
- str += getTcpStateName(mFieldsValues.get(key).intValue()) + " ";
- } else if (key == Field.WSCALE) {
- str += decodeWscale(mFieldsValues.get(key).byteValue()) + " ";
- } else {
- str += mFieldsValues.get(key) + " ";
- }
- }
- str += "}";
- return str;
+ return "TcpInfo{lost=" + mLost + ", retransmit=" + mRetransmits + ", received=" + mSegsIn
+ + ", sent=" + mSegsOut + "}";
}
}
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java
index 78813bd..f660f81 100644
--- a/src/com/android/networkstack/netlink/TcpSocketTracker.java
+++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -340,16 +340,16 @@
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();
+ stat.sentCount = current.tcpInfo.mSegsOut;
+ stat.receivedCount = current.tcpInfo.mSegsIn;
+ stat.lostCount = current.tcpInfo.mLost;
+ stat.retransmitCount = current.tcpInfo.mRetransmits;
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();
- stat.lostCount -= previous.tcpInfo.getValue(TcpInfo.Field.LOST).intValue();
- stat.retransmitCount -= previous.tcpInfo.getValue(TcpInfo.Field.RETRANSMITS).intValue();
+ stat.sentCount -= previous.tcpInfo.mSegsOut;
+ stat.receivedCount -= previous.tcpInfo.mSegsIn;
+ stat.lostCount -= previous.tcpInfo.mLost;
+ stat.retransmitCount -= previous.tcpInfo.mRetransmits;
}
return stat;
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
index b782efc..c4f057b 100644
--- a/tests/integration/Android.bp
+++ b/tests/integration/Android.bp
@@ -67,6 +67,7 @@
platform_apis: true,
min_sdk_version: "29",
test_suites: ["device-tests", "mts"],
+ test_config: "AndroidTest_Coverage.xml",
defaults: ["NetworkStackIntegrationTestsJniDefaults"],
static_libs: ["NetworkStackTestsLib", "NetworkStackIntegrationTestsLib"],
compile_multilib: "both",
diff --git a/tests/integration/AndroidTest_Coverage.xml b/tests/integration/AndroidTest_Coverage.xml
new file mode 100644
index 0000000..e33fa87
--- /dev/null
+++ b/tests/integration/AndroidTest_Coverage.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs coverage tests for NetworkStack">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="NetworkStackCoverageTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="NetworkStackCoverageTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.server.networkstack.coverage" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
index e645a2c..e9384c8 100644
--- a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
+++ b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
@@ -28,6 +28,7 @@
import android.net.Network;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
+import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +37,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.function.Consumer;
/**
@@ -46,6 +49,17 @@
public class ProvisioningConfigurationTest {
private ProvisioningConfiguration mConfig;
+ private ScanResultInfo makeScanResultInfo(final String ssid) {
+ final byte[] payload = new byte[] {
+ (byte) 0x00, (byte) 0x17, (byte) 0xF2, (byte) 0x06, (byte) 0x01,
+ (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ };
+ final ScanResultInfo.InformationElement ie =
+ new ScanResultInfo.InformationElement(0xdd /* vendor specific IE id */,
+ ByteBuffer.wrap(payload));
+ return new ScanResultInfo(ssid, Collections.singletonList(ie));
+ }
+
@Before
public void setUp() {
mConfig = new ProvisioningConfiguration();
@@ -67,8 +81,9 @@
mConfig.mNetwork = new Network(321);
mConfig.mDisplayName = "test_config";
mConfig.mEnablePreconnection = false;
+ mConfig.mScanResultInfo = makeScanResultInfo("ssid");
// Any added field must be included in equals() to be tested properly
- assertFieldCountEquals(13, ProvisioningConfiguration.class);
+ assertFieldCountEquals(14, ProvisioningConfiguration.class);
}
@Test
@@ -101,6 +116,12 @@
}
@Test
+ public void testParcelUnparcel_NullScanResultInfo() {
+ mConfig.mScanResultInfo = null;
+ doParcelUnparcelTest();
+ }
+
+ @Test
public void testParcelUnparcel_WithPreDhcpConnection() {
mConfig.mEnablePreconnection = true;
doParcelUnparcelTest();
@@ -136,7 +157,9 @@
assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
assertNotEqualsAfterChange(c -> c.mDisplayName = null);
assertNotEqualsAfterChange(c -> c.mEnablePreconnection = true);
- assertFieldCountEquals(13, ProvisioningConfiguration.class);
+ assertNotEqualsAfterChange(c -> c.mScanResultInfo = null);
+ assertNotEqualsAfterChange(c -> c.mScanResultInfo = makeScanResultInfo("another ssid"));
+ assertFieldCountEquals(14, ProvisioningConfiguration.class);
}
private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java
index f65de9c..ddab8c7 100644
--- a/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java
+++ b/tests/unit/src/com/android/networkstack/netlink/TcpInfoTest.java
@@ -89,6 +89,8 @@
"0000000000000000"; // sndBufLimited = 0
private static final byte[] TCP_INFO_BYTES =
HexEncoding.decode(TCP_INFO_HEX.toCharArray(), false);
+ private static final TcpInfo TEST_TCPINFO =
+ new TcpInfo(0 /* retransmits */, 0 /* lost */, 2 /* segsOut */, 1 /* segsIn */);
private static final String EXPANDED_TCP_INFO_HEX = TCP_INFO_HEX
+ "00000000" // tcpi_delivered
@@ -100,40 +102,48 @@
@Test
public void testParseTcpInfo() {
final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES);
- final Map<TcpInfo.Field, Number> expected = makeTestTcpInfoHash();
- final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1);
+ // Length is less than required
+ final TcpInfo nullInfo = TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO);
+ assertEquals(nullInfo, null);
- assertEquals(parsedInfo, new TcpInfo(expected));
+ final TcpInfo parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1);
+ assertEquals(parsedInfo, TEST_TCPINFO);
+
+ // Make a data that TcpInfo is not started from the begining of the buffer.
+ final ByteBuffer bufferWithHeader =
+ ByteBuffer.allocate(EXPANDED_TCP_INFO_BYTES.length + TCP_INFO_BYTES.length);
+ bufferWithHeader.put(EXPANDED_TCP_INFO_BYTES);
+ bufferWithHeader.put(TCP_INFO_BYTES);
+ final TcpInfo infoWithHeader = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1);
+ bufferWithHeader.position(EXPANDED_TCP_INFO_BYTES.length);
+ assertEquals(parsedInfo, TEST_TCPINFO);
+ }
+
+ @Test
+ public void testFieldOffset() {
+ assertEquals(TcpInfo.RETRANSMITS_OFFSET, 2);
+ assertEquals(TcpInfo.LOST_OFFSET, 32);
+ assertEquals(TcpInfo.SEGS_OUT_OFFSET, 136);
+ assertEquals(TcpInfo.SEGS_IN_OFFSET, 140);
}
@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(parsedInfo, TEST_TCPINFO);
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(parsedInfoShorterLen, TEST_TCPINFO);
assertEquals(TCP_INFO_LENGTH_V1, buffer.position());
}
@Test
- public void testValidOffset() {
- final ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES);
-
- final Map<TcpInfo.Field, Number> expected = makeShortTestTcpInfoHash();
- final TcpInfo parsedInfo = TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO);
-
- assertEquals(parsedInfo, new TcpInfo(expected));
- }
-
- @Test
public void testTcpStateName() {
assertEquals(TcpInfo.getTcpStateName(4), TCP_FIN_WAIT1);
assertEquals(TcpInfo.getTcpStateName(1), TCP_ESTABLISHED);
@@ -156,39 +166,14 @@
@Test
public void testMalformedTcpInfo() {
final ByteBuffer buffer = ByteBuffer.wrap(MALFORMED_TCP_INFO_BYTES);
- final Map<TcpInfo.Field, Number> expected = makeShortTestTcpInfoHash();
TcpInfo parsedInfo = TcpInfo.parse(buffer, SHORT_TEST_TCP_INFO);
- assertEquals(parsedInfo, new TcpInfo(expected));
+ assertEquals(parsedInfo, null);
parsedInfo = TcpInfo.parse(buffer, TCP_INFO_LENGTH_V1);
assertEquals(parsedInfo, null);
}
- @Test
- public void testGetValue() {
- ByteBuffer buffer = ByteBuffer.wrap(TCP_INFO_BYTES);
-
- final Map<TcpInfo.Field, Number> expected = makeShortTestTcpInfoHash();
- expected.put(TcpInfo.Field.MAX_PACING_RATE, 10_000L);
- expected.put(TcpInfo.Field.FACKETS, 10);
-
- final TcpInfo expectedInfo = new TcpInfo(expected);
- assertEquals((byte) 0x01, expectedInfo.getValue(TcpInfo.Field.STATE));
- assertEquals((byte) 0x00, expectedInfo.getValue(TcpInfo.Field.CASTATE));
- assertEquals((byte) 0x00, expectedInfo.getValue(TcpInfo.Field.RETRANSMITS));
- assertEquals((byte) 0x00, expectedInfo.getValue(TcpInfo.Field.PROBES));
- assertEquals((byte) 0x00, expectedInfo.getValue(TcpInfo.Field.BACKOFF));
- assertEquals((byte) 0x07, expectedInfo.getValue(TcpInfo.Field.OPTIONS));
- assertEquals((byte) 0x88, expectedInfo.getValue(TcpInfo.Field.WSCALE));
- assertEquals((byte) 0x00, expectedInfo.getValue(TcpInfo.Field.DELIVERY_RATE_APP_LIMITED));
-
- assertEquals(10_000L, expectedInfo.getValue(TcpInfo.Field.MAX_PACING_RATE));
- assertEquals(10, expectedInfo.getValue(TcpInfo.Field.FACKETS));
- assertEquals(null, expectedInfo.getValue(TcpInfo.Field.RTT));
-
- }
-
// Make a TcpInfo contains only first 8 bytes.
private Map<TcpInfo.Field, Number> makeShortTestTcpInfoHash() {
final Map<TcpInfo.Field, Number> info = new LinkedHashMap<>();
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
index a21e7cf..6a09f12 100644
--- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
+++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -61,7 +61,6 @@
import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.HashMap;
// TODO: Add more tests for missing coverage.
@RunWith(AndroidJUnit4.class)
@@ -174,6 +173,8 @@
"0000000000000000"; // deliverRate = 0
private static final byte[] SOCK_DIAG_TCP_INET_BYTES =
HexEncoding.decode(SOCK_DIAG_TCP_INET_HEX.toCharArray(), false);
+ private static final TcpInfo TEST_TCPINFO =
+ new TcpInfo(5 /* retransmits */, 0 /* lost */, 10 /* segsOut */, 0 /* segsIn */);
private static final String TEST_RESPONSE_HEX = SOCK_DIAG_TCP_INET_HEX
// struct nlmsghdr
@@ -253,52 +254,8 @@
buffer.position(SOCKDIAG_MSG_HEADER_SIZE);
final TcpSocketTracker.SocketInfo parsed =
tst.parseSockInfo(buffer, AF_INET, 276, 100L);
- final HashMap<TcpInfo.Field, Number> expected = new HashMap<>();
- expected.put(TcpInfo.Field.STATE, (byte) 0x01);
- expected.put(TcpInfo.Field.CASTATE, (byte) 0x00);
- expected.put(TcpInfo.Field.RETRANSMITS, (byte) 0x05);
- expected.put(TcpInfo.Field.PROBES, (byte) 0x00);
- expected.put(TcpInfo.Field.BACKOFF, (byte) 0x00);
- expected.put(TcpInfo.Field.OPTIONS, (byte) 0x07);
- expected.put(TcpInfo.Field.WSCALE, (byte) 0x88);
- expected.put(TcpInfo.Field.DELIVERY_RATE_APP_LIMITED, (byte) 0x00);
- expected.put(TcpInfo.Field.RTO, 1806666);
- expected.put(TcpInfo.Field.ATO, 0);
- expected.put(TcpInfo.Field.SND_MSS, 1326);
- expected.put(TcpInfo.Field.RCV_MSS, 536);
- expected.put(TcpInfo.Field.UNACKED, 0);
- expected.put(TcpInfo.Field.SACKED, 0);
- 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);
- expected.put(TcpInfo.Field.LAST_ACK_SENT, 0);
- expected.put(TcpInfo.Field.LAST_DATA_RECV, 187);
- expected.put(TcpInfo.Field.LAST_ACK_RECV, 187);
- expected.put(TcpInfo.Field.PMTU, 1500);
- expected.put(TcpInfo.Field.RCV_SSTHRESH, 87600);
- expected.put(TcpInfo.Field.RTT, 601150);
- expected.put(TcpInfo.Field.RTTVAR, 300575);
- expected.put(TcpInfo.Field.SND_SSTHRESH, 1400);
- expected.put(TcpInfo.Field.SND_CWND, 10);
- expected.put(TcpInfo.Field.ADVMSS, 1448);
- expected.put(TcpInfo.Field.REORDERING, 3);
- expected.put(TcpInfo.Field.RCV_RTT, 0);
- expected.put(TcpInfo.Field.RCV_SPACE, 87600);
- expected.put(TcpInfo.Field.TOTAL_RETRANS, 0);
- expected.put(TcpInfo.Field.PACING_RATE, 44115L);
- expected.put(TcpInfo.Field.MAX_PACING_RATE, -1L);
- expected.put(TcpInfo.Field.BYTES_ACKED, 1L);
- expected.put(TcpInfo.Field.BYTES_RECEIVED, 0L);
- expected.put(TcpInfo.Field.SEGS_OUT, 10);
- expected.put(TcpInfo.Field.SEGS_IN, 0);
- expected.put(TcpInfo.Field.NOTSENT_BYTES, 0);
- expected.put(TcpInfo.Field.MIN_RTT, 601150);
- expected.put(TcpInfo.Field.DATA_SEGS_IN, 0);
- expected.put(TcpInfo.Field.DATA_SEGS_OUT, 0);
- expected.put(TcpInfo.Field.DELIVERY_RATE, 0L);
- assertEquals(parsed.tcpInfo, new TcpInfo(expected));
+ assertEquals(parsed.tcpInfo, TEST_TCPINFO);
assertEquals(parsed.fwmark, 789125);
assertEquals(parsed.updateTime, 100);
assertEquals(parsed.ipFamily, AF_INET);
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index e2c0b04..157d257 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -130,7 +130,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -232,6 +231,9 @@
private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ private static final int NOTIFY_NETWORK_TESTED_VALIDATION_RESULT_MASK = 0x3;
+ private static final int NOTIFY_NETWORK_TESTED_SUCCESSFUL_PROBES_MASK = 0xFFFC;
+
/**
* Fakes DNS responses.
*
@@ -795,7 +797,7 @@
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertTrue(wrappedMonitor.isDataStall());
verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
- argThat(getDataStallDnsBundleMatcher()));
+ bundleForDnsDataStall(DEFAULT_DNS_TIMEOUT_THRESHOLD));
}
@Test
@@ -808,7 +810,7 @@
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertTrue(wrappedMonitor.isDataStall());
verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
- argThat(getDataStallDnsBundleMatcher()));
+ bundleForDnsDataStall(DEFAULT_DNS_TIMEOUT_THRESHOLD));
}
@Test
@@ -824,8 +826,10 @@
makeDnsTimeoutEvent(wrappedMonitor, 3);
assertTrue(wrappedMonitor.isDataStall());
+
+ // The expected timeout count is the previous 2 DNS timeouts + the most recent 3 timeouts
verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
- argThat(getDataStallDnsBundleMatcher()));
+ bundleForDnsDataStall(5));
// Set the value to larger than the default dns log size.
setConsecutiveDnsTimeoutThreshold(51);
@@ -836,8 +840,10 @@
makeDnsTimeoutEvent(wrappedMonitor, 1);
assertTrue(wrappedMonitor.isDataStall());
- verify(mCallbacks, times(2)).notifyDataStallSuspected(anyLong(),
- eq(DETECTION_METHOD_DNS_EVENTS), argThat(getDataStallDnsBundleMatcher()));
+
+ // The expected timeout count is the previous 50 DNS timeouts + the most recent timeout
+ verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
+ bundleForDnsDataStall(51));
}
@Test
@@ -863,7 +869,7 @@
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
assertTrue(wrappedMonitor.isDataStall());
verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_DNS_EVENTS),
- argThat(getDataStallDnsBundleMatcher()));
+ bundleForDnsDataStall(DEFAULT_DNS_TIMEOUT_THRESHOLD));
// Test dns events happened before valid dns time threshold.
setValidDataStallDnsTimeThreshold(0);
@@ -898,7 +904,7 @@
HandlerUtilsKt.waitForIdle(wrappedMonitor.getHandler(), HANDLER_TIMEOUT_MS);
assertTrue(wrappedMonitor.isDataStall());
verify(mCallbacks).notifyDataStallSuspected(anyLong(), eq(DETECTION_METHOD_TCP_METRICS),
- argThat(getDataStallTcpBundleMatcher()));
+ bundleForTcpDataStall());
}
@Test
@@ -961,12 +967,13 @@
setStatus(mHttpsConnection, 204);
setStatus(mHttpConnection, 204);
+ final int expectedResult = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP
+ | NETWORK_VALIDATION_RESULT_VALID;
resetCallbacks();
nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_HTTP | NETWORK_VALIDATION_RESULT_VALID), any(),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ .notifyNetworkTestedWithExtras(eq(expectedResult), any(), anyLong(),
+ bundleForNotifyNetworkTested(expectedResult));
assertEquals(0, mRegisteredReceivers.size());
}
@@ -975,6 +982,8 @@
setStatus(mHttpsConnection, 204);
setStatus(mHttpConnection, 204);
+ final int expectedResult = VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS;
+
// Verify dns query only get v6 address.
mFakeDns.setAnswer("dns6.google", new String[]{"2001:db8::53"}, TYPE_AAAA);
WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
@@ -982,9 +991,8 @@
new InetAddress[0]));
wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
- | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ .notifyNetworkTestedWithExtras(eq(expectedResult), eq(null), anyLong(),
+ bundleForNotifyNetworkTested(expectedResult));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
@@ -994,9 +1002,8 @@
wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns4.google",
new InetAddress[0]));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
- | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ .notifyNetworkTestedWithExtras(eq(expectedResult), eq(null), anyLong(),
+ bundleForNotifyNetworkTested(expectedResult));
// NetworkMonitor will check if the probes has changed or not, if the probes has not
// changed, the callback won't be fired.
verify(mCallbacks, never()).notifyProbeStatusChanged(
@@ -1008,9 +1015,8 @@
mFakeDns.setAnswer("dns.google", new String[]{"192.0.2.3"}, TYPE_A);
wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
- | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ .notifyNetworkTestedWithExtras(eq(expectedResult), eq(null), anyLong(),
+ bundleForNotifyNetworkTested(expectedResult));
verify(mCallbacks, never()).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
}
@@ -1026,7 +1032,8 @@
wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ anyLong(), bundleForNotifyNetworkTested(NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTPS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1041,7 +1048,8 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
.notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
| NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ bundleForNotifyNetworkTested(VALIDATION_RESULT_VALID
+ | NETWORK_VALIDATION_PROBE_PRIVDNS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
}
@@ -1057,7 +1065,8 @@
wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTestedWithExtras(
eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ anyLong(), bundleForNotifyNetworkTested(NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTPS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1070,7 +1079,8 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
.notifyNetworkTestedWithExtras(eq(VALIDATION_RESULT_VALID
| NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ bundleForNotifyNetworkTested(VALIDATION_RESULT_VALID
+ | NETWORK_VALIDATION_PROBE_PRIVDNS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
@@ -1084,7 +1094,8 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
.notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTPS), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ bundleForNotifyNetworkTested(NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTPS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTPS));
@@ -1097,7 +1108,8 @@
new InetAddress[0]));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS)).notifyNetworkTestedWithExtras(
eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ anyLong(), bundleForNotifyNetworkTested(NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTPS));
// NetworkMonitor will check if the probes has changed or not, if the probes has not
// changed, the callback won't be fired.
verify(mCallbacks, never()).notifyProbeStatusChanged(
@@ -1111,7 +1123,8 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
.notifyNetworkTestedWithExtras(
eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ anyLong(), bundleForNotifyNetworkTested(VALIDATION_RESULT_VALID
+ | NETWORK_VALIDATION_PROBE_PRIVDNS));
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyProbeStatusChanged(
eq(VALIDATION_RESULT_PRIVDNS_VALID), eq(VALIDATION_RESULT_PRIVDNS_VALID));
}
@@ -1176,12 +1189,13 @@
// Expect to send HTTP, HTTPS, FALLBACK probe and evaluation result notifications to CS.
final NetworkMonitor nm = runNetworkTest(VALIDATION_RESULT_PARTIAL);
+ final int expectedResult = VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID;
resetCallbacks();
nm.setAcceptPartialConnectivity();
// Expect to update evaluation result notifications to CS.
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
- eq(VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ eq(expectedResult), eq(null), anyLong(), bundleForNotifyNetworkTested(
+ expectedResult));
}
@Test
@@ -1245,6 +1259,9 @@
@Test
public void testNotifyNetwork_WithforceReevaluation() throws Exception {
+ final int expectedResult = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_FALLBACK
+ | NETWORK_VALIDATION_RESULT_PARTIAL;
+
final NetworkMonitor nm = runValidatedNetworkTest();
// Verify forceReevalution will not reset the validation result but only probe result until
// getting the validation result.
@@ -1256,9 +1273,8 @@
final ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
// Expect to send HTTP, HTTPs, FALLBACK and evaluation results.
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
- .notifyNetworkTestedWithExtras(eq(NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_FALLBACK | NETWORK_VALIDATION_RESULT_PARTIAL),
- any(), anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ .notifyNetworkTestedWithExtras(eq(expectedResult), any(), anyLong(),
+ bundleForNotifyNetworkTested(expectedResult));
}
@Test
@@ -1313,20 +1329,23 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
| NETWORK_VALIDATION_RESULT_PARTIAL), eq(null), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ bundleForNotifyNetworkTested(NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTPS | NETWORK_VALIDATION_RESULT_PARTIAL));
nm.getEvaluationState().reportEvaluationResult(
NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL,
null /* redirectUrl */);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null),
- anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ anyLong(), bundleForNotifyNetworkTested(VALIDATION_RESULT_VALID
+ | NETWORK_VALIDATION_RESULT_PARTIAL));
nm.getEvaluationState().reportEvaluationResult(VALIDATION_RESULT_INVALID,
TEST_REDIRECT_URL);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTestedWithExtras(
eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
- eq(TEST_REDIRECT_URL), anyLong(), argThat(getNotifyNetworkTestedBundleMatcher()));
+ eq(TEST_REDIRECT_URL), anyLong(), bundleForNotifyNetworkTested(
+ NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS));
}
@Test
@@ -1482,7 +1501,7 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS))
.notifyNetworkTestedWithExtras(eq(testResult),
mNetworkTestedRedirectUrlCaptor.capture(), anyLong(),
- argThat(getNotifyNetworkTestedBundleMatcher()));
+ bundleForNotifyNetworkTested(testResult));
} catch (RemoteException e) {
fail("Unexpected exception: " + e);
}
@@ -1514,21 +1533,32 @@
}
}
- private ArgumentMatcher<PersistableBundle> getNotifyNetworkTestedBundleMatcher() {
- return bundle ->
+ private PersistableBundle bundleForNotifyNetworkTested(final int result) {
+ // result = KEY_NETWORK_PROBES_SUCCEEDED_BITMASK | KEY_NETWORK_VALIDATION_RESULT
+ // See NetworkMonitor.EvaluationState#getNetworkTestResult
+ final int validationResult = result & NOTIFY_NETWORK_TESTED_VALIDATION_RESULT_MASK;
+ final int probesSucceeded = result & NOTIFY_NETWORK_TESTED_SUCCESSFUL_PROBES_MASK;
+
+ return argThat(bundle ->
bundle.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)
&& bundle.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)
- && bundle.containsKey(KEY_NETWORK_VALIDATION_RESULT);
+ && (bundle.getInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK) & probesSucceeded)
+ == probesSucceeded
+ && bundle.containsKey(KEY_NETWORK_VALIDATION_RESULT)
+ && (bundle.getInt(KEY_NETWORK_VALIDATION_RESULT) & validationResult)
+ == validationResult);
}
- private ArgumentMatcher<PersistableBundle> getDataStallDnsBundleMatcher() {
- return bundle -> bundle.containsKey(KEY_DNS_CONSECUTIVE_TIMEOUTS);
+ private PersistableBundle bundleForDnsDataStall(final int timeoutCount) {
+ return argThat(bundle ->
+ bundle.containsKey(KEY_DNS_CONSECUTIVE_TIMEOUTS)
+ && bundle.getInt(KEY_DNS_CONSECUTIVE_TIMEOUTS) == timeoutCount);
}
- private ArgumentMatcher<PersistableBundle> getDataStallTcpBundleMatcher() {
- return bundle ->
+ private PersistableBundle bundleForTcpDataStall() {
+ return argThat(bundle ->
bundle.containsKey(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS)
- && bundle.containsKey(KEY_TCP_PACKET_FAIL_RATE);
+ && bundle.containsKey(KEY_TCP_PACKET_FAIL_RATE));
}
}