Merge "Evaluation delay = 8 secs for explicitly selected networks"
diff --git a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
index 007bf23..a9add20 100644
--- a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
+++ b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
@@ -25,17 +25,14 @@
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringTester.buildTcpPacket;
+import static android.net.TetheringTester.buildUdpPacket;
+import static android.net.TetheringTester.isAddressIpv4;
import static android.net.TetheringTester.isExpectedIcmpPacket;
import static android.net.TetheringTester.isExpectedTcpPacket;
import static android.net.TetheringTester.isExpectedUdpPacket;
-import static android.system.OsConstants.IPPROTO_IP;
-import static android.system.OsConstants.IPPROTO_IPV6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.net.module.util.HexDump.dumpHexString;
-import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
-import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK;
import static com.android.net.module.util.NetworkStackConstants.TCPHDR_SYN;
@@ -67,11 +64,9 @@
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.modules.utils.build.SdkLevel;
-import com.android.net.module.util.PacketBuilder;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.Ipv6Header;
import com.android.testutils.HandlerUtils;
@@ -128,25 +123,11 @@
(Inet6Address) parseNumericAddress("64:ff9b::808:808");
protected static final IpPrefix TEST_NAT64PREFIX = new IpPrefix("64:ff9b::/96");
- // IPv4 header definition.
- protected static final short ID = 27149;
- protected static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0
- protected static final byte TIME_TO_LIVE = (byte) 0x40;
- protected static final byte TYPE_OF_SERVICE = 0;
-
- // IPv6 header definition.
- private static final short HOP_LIMIT = 0x40;
- // version=6, traffic class=0x0, flowlabel=0x0;
- private static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x60000000;
-
- // UDP and TCP header definition.
// LOCAL_PORT is used by public port and private port. Assume port 9876 has not been used yet
// before the testing that public port and private port are the same in the testing. Note that
// NAT port forwarding could be different between private port and public port.
protected static final short LOCAL_PORT = 9876;
protected static final short REMOTE_PORT = 433;
- private static final short WINDOW = (short) 0x2000;
- private static final short URGENT_POINTER = 0;
// Payload definition.
protected static final ByteBuffer EMPTY_PAYLOAD = ByteBuffer.wrap(new byte[0]);
@@ -654,72 +635,6 @@
return runAsShell(MANAGE_TEST_NETWORKS, () -> initTestNetwork(mContext, lp, TIMEOUT_MS));
}
- private short getEthType(@NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp) {
- return isAddressIpv4(srcIp, dstIp) ? (short) ETHER_TYPE_IPV4 : (short) ETHER_TYPE_IPV6;
- }
-
- private int getIpProto(@NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp) {
- return isAddressIpv4(srcIp, dstIp) ? IPPROTO_IP : IPPROTO_IPV6;
- }
-
- @NonNull
- protected ByteBuffer buildUdpPacket(
- @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
- @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
- short srcPort, short dstPort, @Nullable final ByteBuffer payload)
- throws Exception {
- final int ipProto = getIpProto(srcIp, dstIp);
- final boolean hasEther = (srcMac != null && dstMac != null);
- final int payloadLen = (payload == null) ? 0 : payload.limit();
- final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_UDP,
- payloadLen);
- final PacketBuilder packetBuilder = new PacketBuilder(buffer);
-
- // [1] Ethernet header
- if (hasEther) {
- packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
- }
-
- // [2] IP header
- if (ipProto == IPPROTO_IP) {
- packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
- TIME_TO_LIVE, (byte) IPPROTO_UDP, (Inet4Address) srcIp, (Inet4Address) dstIp);
- } else {
- packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, (byte) IPPROTO_UDP,
- HOP_LIMIT, (Inet6Address) srcIp, (Inet6Address) dstIp);
- }
-
- // [3] UDP header
- packetBuilder.writeUdpHeader(srcPort, dstPort);
-
- // [4] Payload
- if (payload != null) {
- buffer.put(payload);
- // in case data might be reused by caller, restore the position and
- // limit of bytebuffer.
- payload.clear();
- }
-
- return packetBuilder.finalizePacket();
- }
-
- @NonNull
- protected ByteBuffer buildUdpPacket(@NonNull final InetAddress srcIp,
- @NonNull final InetAddress dstIp, short srcPort, short dstPort,
- @Nullable final ByteBuffer payload) throws Exception {
- return buildUdpPacket(null /* srcMac */, null /* dstMac */, srcIp, dstIp, srcPort,
- dstPort, payload);
- }
-
- private boolean isAddressIpv4(@NonNull final InetAddress srcIp,
- @NonNull final InetAddress dstIp) {
- if (srcIp instanceof Inet4Address && dstIp instanceof Inet4Address) return true;
- if (srcIp instanceof Inet6Address && dstIp instanceof Inet6Address) return false;
-
- fail("Unsupported conditions: srcIp " + srcIp + ", dstIp " + dstIp);
- return false; // unreachable
- }
-
protected void sendDownloadPacketUdp(@NonNull final InetAddress srcIp,
@NonNull final InetAddress dstIp, @NonNull final TetheringTester tester,
boolean is6To4) throws Exception {
@@ -761,45 +676,6 @@
});
}
-
- @NonNull
- private ByteBuffer buildTcpPacket(
- @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
- @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
- short srcPort, short dstPort, final short seq, final short ack,
- final byte tcpFlags, @NonNull final ByteBuffer payload) throws Exception {
- final int ipProto = getIpProto(srcIp, dstIp);
- final boolean hasEther = (srcMac != null && dstMac != null);
- final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_TCP,
- payload.limit());
- final PacketBuilder packetBuilder = new PacketBuilder(buffer);
-
- // [1] Ethernet header
- if (hasEther) {
- packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
- }
-
- // [2] IP header
- if (ipProto == IPPROTO_IP) {
- packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
- TIME_TO_LIVE, (byte) IPPROTO_TCP, (Inet4Address) srcIp, (Inet4Address) dstIp);
- } else {
- packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, (byte) IPPROTO_TCP,
- HOP_LIMIT, (Inet6Address) srcIp, (Inet6Address) dstIp);
- }
-
- // [3] TCP header
- packetBuilder.writeTcpHeader(srcPort, dstPort, seq, ack, tcpFlags, WINDOW, URGENT_POINTER);
-
- // [4] Payload
- buffer.put(payload);
- // in case data might be reused by caller, restore the position and
- // limit of bytebuffer.
- payload.clear();
-
- return packetBuilder.finalizePacket();
- }
-
protected void sendDownloadPacketTcp(@NonNull final InetAddress srcIp,
@NonNull final InetAddress dstIp, short seq, short ack, byte tcpFlags,
@NonNull final ByteBuffer payload, @NonNull final TetheringTester tester,
diff --git a/Tethering/tests/integration/base/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java
index 1c0803e..33baf93 100644
--- a/Tethering/tests/integration/base/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/base/android/net/TetheringTester.java
@@ -17,8 +17,12 @@
package android.net;
import static android.net.InetAddresses.parseNumericAddress;
+import static android.system.OsConstants.ICMP_ECHO;
+import static android.system.OsConstants.ICMP_ECHOREPLY;
import static android.system.OsConstants.IPPROTO_ICMP;
import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IPPROTO_IPV6;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
@@ -27,6 +31,8 @@
import static com.android.net.module.util.DnsPacket.NSSECTION;
import static com.android.net.module.util.DnsPacket.QDSECTION;
import static com.android.net.module.util.HexDump.dumpHexString;
+import static com.android.net.module.util.IpUtils.icmpChecksum;
+import static com.android.net.module.util.IpUtils.ipChecksum;
import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
@@ -38,6 +44,10 @@
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.net.module.util.NetworkStackConstants.ICMP_CHECKSUM_OFFSET;
+import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET;
+import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
+import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET;
import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST;
import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE;
import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED;
@@ -58,6 +68,7 @@
import com.android.net.module.util.DnsPacket;
import com.android.net.module.util.Ipv6Utils;
+import com.android.net.module.util.PacketBuilder;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv4Header;
@@ -101,6 +112,23 @@
DhcpPacket.DHCP_LEASE_TIME,
};
private static final InetAddress LINK_LOCAL = parseNumericAddress("fe80::1");
+ // IPv4 header definition.
+ protected static final short ID = 27149;
+ protected static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0
+ protected static final byte TIME_TO_LIVE = (byte) 0x40;
+ protected static final byte TYPE_OF_SERVICE = 0;
+
+ // IPv6 header definition.
+ private static final short HOP_LIMIT = 0x40;
+ // version=6, traffic class=0x0, flowlabel=0x0;
+ private static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x60000000;
+
+ // UDP and TCP header definition.
+ private static final short WINDOW = (short) 0x2000;
+ private static final short URGENT_POINTER = 0;
+
+ // ICMP definition.
+ private static final short ICMPECHO_CODE = 0x0;
public static final String DHCP_HOSTNAME = "testhostname";
@@ -628,6 +656,190 @@
return false;
}
+ @NonNull
+ public static ByteBuffer buildUdpPacket(
+ @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
+ @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
+ short srcPort, short dstPort, @Nullable final ByteBuffer payload)
+ throws Exception {
+ final int ipProto = getIpProto(srcIp, dstIp);
+ final boolean hasEther = (srcMac != null && dstMac != null);
+ final int payloadLen = (payload == null) ? 0 : payload.limit();
+ final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_UDP,
+ payloadLen);
+ final PacketBuilder packetBuilder = new PacketBuilder(buffer);
+
+ // [1] Ethernet header
+ if (hasEther) {
+ packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
+ }
+
+ // [2] IP header
+ if (ipProto == IPPROTO_IP) {
+ packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
+ TIME_TO_LIVE, (byte) IPPROTO_UDP, (Inet4Address) srcIp, (Inet4Address) dstIp);
+ } else {
+ packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, (byte) IPPROTO_UDP,
+ HOP_LIMIT, (Inet6Address) srcIp, (Inet6Address) dstIp);
+ }
+
+ // [3] UDP header
+ packetBuilder.writeUdpHeader(srcPort, dstPort);
+
+ // [4] Payload
+ if (payload != null) {
+ buffer.put(payload);
+ // in case data might be reused by caller, restore the position and
+ // limit of bytebuffer.
+ payload.clear();
+ }
+
+ return packetBuilder.finalizePacket();
+ }
+
+ @NonNull
+ public static ByteBuffer buildUdpPacket(@NonNull final InetAddress srcIp,
+ @NonNull final InetAddress dstIp, short srcPort, short dstPort,
+ @Nullable final ByteBuffer payload) throws Exception {
+ return buildUdpPacket(null /* srcMac */, null /* dstMac */, srcIp, dstIp, srcPort,
+ dstPort, payload);
+ }
+
+ @NonNull
+ public static ByteBuffer buildTcpPacket(
+ @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
+ @NonNull final InetAddress srcIp, @NonNull final InetAddress dstIp,
+ short srcPort, short dstPort, final short seq, final short ack,
+ final byte tcpFlags, @NonNull final ByteBuffer payload) throws Exception {
+ final int ipProto = getIpProto(srcIp, dstIp);
+ final boolean hasEther = (srcMac != null && dstMac != null);
+ final ByteBuffer buffer = PacketBuilder.allocate(hasEther, ipProto, IPPROTO_TCP,
+ payload.limit());
+ final PacketBuilder packetBuilder = new PacketBuilder(buffer);
+
+ // [1] Ethernet header
+ if (hasEther) {
+ packetBuilder.writeL2Header(srcMac, dstMac, getEthType(srcIp, dstIp));
+ }
+
+ // [2] IP header
+ if (ipProto == IPPROTO_IP) {
+ packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET,
+ TIME_TO_LIVE, (byte) IPPROTO_TCP, (Inet4Address) srcIp, (Inet4Address) dstIp);
+ } else {
+ packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, (byte) IPPROTO_TCP,
+ HOP_LIMIT, (Inet6Address) srcIp, (Inet6Address) dstIp);
+ }
+
+ // [3] TCP header
+ packetBuilder.writeTcpHeader(srcPort, dstPort, seq, ack, tcpFlags, WINDOW, URGENT_POINTER);
+
+ // [4] Payload
+ buffer.put(payload);
+ // in case data might be reused by caller, restore the position and
+ // limit of bytebuffer.
+ payload.clear();
+
+ return packetBuilder.finalizePacket();
+ }
+
+ // PacketBuilder doesn't support IPv4 ICMP packet. It may need to refactor PacketBuilder first
+ // because ICMP is a specific layer 3 protocol for PacketBuilder which expects packets always
+ // have layer 3 (IP) and layer 4 (TCP, UDP) for now. Since we don't use IPv4 ICMP packet too
+ // much in this test, we just write a ICMP packet builder here.
+ @NonNull
+ public static ByteBuffer buildIcmpEchoPacketV4(
+ @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
+ @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp,
+ int type, short id, short seq) throws Exception {
+ if (type != ICMP_ECHO && type != ICMP_ECHOREPLY) {
+ fail("Unsupported ICMP type: " + type);
+ }
+
+ // Build ICMP echo id and seq fields as payload. Ignore the data field.
+ final ByteBuffer payload = ByteBuffer.allocate(4);
+ payload.putShort(id);
+ payload.putShort(seq);
+ payload.rewind();
+
+ final boolean hasEther = (srcMac != null && dstMac != null);
+ final int etherHeaderLen = hasEther ? Struct.getSize(EthernetHeader.class) : 0;
+ final int ipv4HeaderLen = Struct.getSize(Ipv4Header.class);
+ final int Icmpv4HeaderLen = Struct.getSize(Icmpv4Header.class);
+ final int payloadLen = payload.limit();
+ final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv4HeaderLen
+ + Icmpv4HeaderLen + payloadLen);
+
+ // [1] Ethernet header
+ if (hasEther) {
+ final EthernetHeader ethHeader = new EthernetHeader(dstMac, srcMac, ETHER_TYPE_IPV4);
+ ethHeader.writeToByteBuffer(packet);
+ }
+
+ // [2] IP header
+ final Ipv4Header ipv4Header = new Ipv4Header(TYPE_OF_SERVICE,
+ (short) 0 /* totalLength, calculate later */, ID,
+ FLAGS_AND_FRAGMENT_OFFSET, TIME_TO_LIVE, (byte) IPPROTO_ICMP,
+ (short) 0 /* checksum, calculate later */, srcIp, dstIp);
+ ipv4Header.writeToByteBuffer(packet);
+
+ // [3] ICMP header
+ final Icmpv4Header icmpv4Header = new Icmpv4Header((byte) type, ICMPECHO_CODE,
+ (short) 0 /* checksum, calculate later */);
+ icmpv4Header.writeToByteBuffer(packet);
+
+ // [4] Payload
+ packet.put(payload);
+ packet.flip();
+
+ // [5] Finalize packet
+ // Used for updating IP header fields. If there is Ehternet header, IPv4 header offset
+ // in buffer equals ethernet header length because IPv4 header is located next to ethernet
+ // header. Otherwise, IPv4 header offset is 0.
+ final int ipv4HeaderOffset = hasEther ? etherHeaderLen : 0;
+
+ // Populate the IPv4 totalLength field.
+ packet.putShort(ipv4HeaderOffset + IPV4_LENGTH_OFFSET,
+ (short) (ipv4HeaderLen + Icmpv4HeaderLen + payloadLen));
+
+ // Populate the IPv4 header checksum field.
+ packet.putShort(ipv4HeaderOffset + IPV4_CHECKSUM_OFFSET,
+ ipChecksum(packet, ipv4HeaderOffset /* headerOffset */));
+
+ // Populate the ICMP checksum field.
+ packet.putShort(ipv4HeaderOffset + IPV4_HEADER_MIN_LEN + ICMP_CHECKSUM_OFFSET,
+ icmpChecksum(packet, ipv4HeaderOffset + IPV4_HEADER_MIN_LEN,
+ Icmpv4HeaderLen + payloadLen));
+ return packet;
+ }
+
+ @NonNull
+ public static ByteBuffer buildIcmpEchoPacketV4(@NonNull final Inet4Address srcIp,
+ @NonNull final Inet4Address dstIp, int type, short id, short seq)
+ throws Exception {
+ return buildIcmpEchoPacketV4(null /* srcMac */, null /* dstMac */, srcIp, dstIp,
+ type, id, seq);
+ }
+
+ private static short getEthType(@NonNull final InetAddress srcIp,
+ @NonNull final InetAddress dstIp) {
+ return isAddressIpv4(srcIp, dstIp) ? (short) ETHER_TYPE_IPV4 : (short) ETHER_TYPE_IPV6;
+ }
+
+ private static int getIpProto(@NonNull final InetAddress srcIp,
+ @NonNull final InetAddress dstIp) {
+ return isAddressIpv4(srcIp, dstIp) ? IPPROTO_IP : IPPROTO_IPV6;
+ }
+
+ public static boolean isAddressIpv4(@NonNull final InetAddress srcIp,
+ @NonNull final InetAddress dstIp) {
+ if (srcIp instanceof Inet4Address && dstIp instanceof Inet4Address) return true;
+ if (srcIp instanceof Inet6Address && dstIp instanceof Inet6Address) return false;
+
+ fail("Unsupported conditions: srcIp " + srcIp + ", dstIp " + dstIp);
+ return false; // unreachable
+ }
+
public void sendUploadPacket(ByteBuffer packet) throws Exception {
mDownstreamReader.sendResponse(packet);
}
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 5d57aa5..eed308c 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -20,23 +20,17 @@
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringTester.TestDnsPacket;
+import static android.net.TetheringTester.buildIcmpEchoPacketV4;
+import static android.net.TetheringTester.buildUdpPacket;
import static android.net.TetheringTester.isExpectedIcmpPacket;
import static android.net.TetheringTester.isExpectedUdpDnsPacket;
import static android.system.OsConstants.ICMP_ECHO;
import static android.system.OsConstants.ICMP_ECHOREPLY;
-import static android.system.OsConstants.IPPROTO_ICMP;
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
import static com.android.net.module.util.HexDump.dumpHexString;
-import static com.android.net.module.util.IpUtils.icmpChecksum;
-import static com.android.net.module.util.IpUtils.ipChecksum;
-import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
-import static com.android.net.module.util.NetworkStackConstants.ICMP_CHECKSUM_OFFSET;
-import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET;
-import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
-import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -53,14 +47,11 @@
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.Struct;
-import com.android.net.module.util.structs.EthernetHeader;
-import com.android.net.module.util.structs.Icmpv4Header;
import com.android.net.module.util.structs.Ipv4Header;
import com.android.net.module.util.structs.UdpHeader;
import com.android.testutils.DevSdkIgnoreRule;
@@ -96,7 +87,6 @@
private static final String TAG = EthernetTetheringTest.class.getSimpleName();
private static final short DNS_PORT = 53;
- private static final short ICMPECHO_CODE = 0x0;
private static final short ICMPECHO_ID = 0x0;
private static final short ICMPECHO_SEQ = 0x0;
@@ -564,85 +554,6 @@
runClatUdpTest();
}
- // PacketBuilder doesn't support IPv4 ICMP packet. It may need to refactor PacketBuilder first
- // because ICMP is a specific layer 3 protocol for PacketBuilder which expects packets always
- // have layer 3 (IP) and layer 4 (TCP, UDP) for now. Since we don't use IPv4 ICMP packet too
- // much in this test, we just write a ICMP packet builder here.
- // TODO: move ICMPv4 packet build function to common utilis.
- @NonNull
- private ByteBuffer buildIcmpEchoPacketV4(
- @Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
- @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp,
- int type, short id, short seq) throws Exception {
- if (type != ICMP_ECHO && type != ICMP_ECHOREPLY) {
- fail("Unsupported ICMP type: " + type);
- }
-
- // Build ICMP echo id and seq fields as payload. Ignore the data field.
- final ByteBuffer payload = ByteBuffer.allocate(4);
- payload.putShort(id);
- payload.putShort(seq);
- payload.rewind();
-
- final boolean hasEther = (srcMac != null && dstMac != null);
- final int etherHeaderLen = hasEther ? Struct.getSize(EthernetHeader.class) : 0;
- final int ipv4HeaderLen = Struct.getSize(Ipv4Header.class);
- final int Icmpv4HeaderLen = Struct.getSize(Icmpv4Header.class);
- final int payloadLen = payload.limit();
- final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv4HeaderLen
- + Icmpv4HeaderLen + payloadLen);
-
- // [1] Ethernet header
- if (hasEther) {
- final EthernetHeader ethHeader = new EthernetHeader(dstMac, srcMac, ETHER_TYPE_IPV4);
- ethHeader.writeToByteBuffer(packet);
- }
-
- // [2] IP header
- final Ipv4Header ipv4Header = new Ipv4Header(TYPE_OF_SERVICE,
- (short) 0 /* totalLength, calculate later */, ID,
- FLAGS_AND_FRAGMENT_OFFSET, TIME_TO_LIVE, (byte) IPPROTO_ICMP,
- (short) 0 /* checksum, calculate later */, srcIp, dstIp);
- ipv4Header.writeToByteBuffer(packet);
-
- // [3] ICMP header
- final Icmpv4Header icmpv4Header = new Icmpv4Header((byte) type, ICMPECHO_CODE,
- (short) 0 /* checksum, calculate later */);
- icmpv4Header.writeToByteBuffer(packet);
-
- // [4] Payload
- packet.put(payload);
- packet.flip();
-
- // [5] Finalize packet
- // Used for updating IP header fields. If there is Ehternet header, IPv4 header offset
- // in buffer equals ethernet header length because IPv4 header is located next to ethernet
- // header. Otherwise, IPv4 header offset is 0.
- final int ipv4HeaderOffset = hasEther ? etherHeaderLen : 0;
-
- // Populate the IPv4 totalLength field.
- packet.putShort(ipv4HeaderOffset + IPV4_LENGTH_OFFSET,
- (short) (ipv4HeaderLen + Icmpv4HeaderLen + payloadLen));
-
- // Populate the IPv4 header checksum field.
- packet.putShort(ipv4HeaderOffset + IPV4_CHECKSUM_OFFSET,
- ipChecksum(packet, ipv4HeaderOffset /* headerOffset */));
-
- // Populate the ICMP checksum field.
- packet.putShort(ipv4HeaderOffset + IPV4_HEADER_MIN_LEN + ICMP_CHECKSUM_OFFSET,
- icmpChecksum(packet, ipv4HeaderOffset + IPV4_HEADER_MIN_LEN,
- Icmpv4HeaderLen + payloadLen));
- return packet;
- }
-
- @NonNull
- private ByteBuffer buildIcmpEchoPacketV4(@NonNull final Inet4Address srcIp,
- @NonNull final Inet4Address dstIp, int type, short id, short seq)
- throws Exception {
- return buildIcmpEchoPacketV4(null /* srcMac */, null /* dstMac */, srcIp, dstIp,
- type, id, seq);
- }
-
@Test
public void testIcmpv4Echo() throws Exception {
final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
index d538368..80c315a 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
@@ -29,16 +29,16 @@
namespace bpf {
namespace internal {
-void NetworkTracePoller::SchedulePolling() {
- // Schedules another run of ourselves to recursively poll periodically.
- mTaskRunner->PostDelayedTask(
- [this]() {
- mMutex.lock();
- SchedulePolling();
- ConsumeAllLocked();
- mMutex.unlock();
- },
- mPollMs);
+void NetworkTracePoller::PollAndSchedule(perfetto::base::TaskRunner* runner,
+ uint32_t poll_ms) {
+ // Always schedule another run of ourselves to recursively poll periodically.
+ // The task runner is sequential so these can't run on top of each other.
+ runner->PostDelayedTask([=]() { PollAndSchedule(runner, poll_ms); }, poll_ms);
+
+ if (mMutex.try_lock()) {
+ ConsumeAllLocked();
+ mMutex.unlock();
+ }
}
bool NetworkTracePoller::Start(uint32_t pollMs) {
@@ -81,7 +81,7 @@
// Start a task runner to run ConsumeAll every mPollMs milliseconds.
mTaskRunner = perfetto::Platform::GetDefaultPlatform()->CreateTaskRunner({});
mPollMs = pollMs;
- SchedulePolling();
+ PollAndSchedule(mTaskRunner.get(), mPollMs);
mSessionCount++;
return true;
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
index adde51e..8433934 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTracePoller.h
@@ -53,7 +53,12 @@
bool ConsumeAll() EXCLUDES(mMutex);
private:
- void SchedulePolling() REQUIRES(mMutex);
+ // Poll the ring buffer for new data and schedule another run of ourselves
+ // after poll_ms (essentially polling periodically until stopped). This takes
+ // in the runner and poll duration to prevent a hard requirement on the lock
+ // and thus a deadlock while resetting the TaskRunner. The runner pointer is
+ // always valid within tasks run by that runner.
+ void PollAndSchedule(perfetto::base::TaskRunner* runner, uint32_t poll_ms);
bool ConsumeAllLocked() REQUIRES(mMutex);
std::mutex mMutex;
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 25aa693..754a60b 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -1317,10 +1317,9 @@
final NsdServiceInfo info = buildNsdServiceInfoFromMdnsEvent(event, code);
// Errors are already logged if null
if (info == null) return false;
- if (DBG) {
- Log.d(TAG, String.format("MdnsDiscoveryManager event code=%s transactionId=%d",
- NsdManager.nameOf(code), transactionId));
- }
+ mServiceLogs.log(String.format(
+ "MdnsDiscoveryManager event code=%s transactionId=%d",
+ NsdManager.nameOf(code), transactionId));
switch (code) {
case NsdManager.SERVICE_FOUND:
clientInfo.onServiceFound(clientId, info);
@@ -1722,6 +1721,7 @@
private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback {
@Override
public void onRegisterServiceSucceeded(int serviceId, NsdServiceInfo registeredInfo) {
+ mServiceLogs.log("onRegisterServiceSucceeded: serviceId " + serviceId);
final ClientInfo clientInfo = getClientInfoOrLog(serviceId);
if (clientInfo == null) return;
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index 22d9b01..f30abc6 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -135,10 +135,17 @@
<!-- Whether to cancel network notifications automatically when tapped -->
<bool name="config_autoCancelNetworkNotifications">true</bool>
- <!-- When no internet or partial connectivity is detected on a network, and a high priority
- (heads up) notification would be shown due to the network being explicitly selected,
- directly show the dialog that would normally be shown when tapping the notification
- instead of showing the notification. -->
+ <!-- Configuration to let OEMs customize what to do when :
+ • Partial connectivity is detected on the network
+ • No internet is detected on the network, and
+ - the network was explicitly selected
+ - the system is configured to actively prefer bad wifi (see config_activelyPreferBadWifi)
+ The default behavior (false) is to post a notification with a PendingIntent so
+ the user is informed and can act if they wish.
+ Making this true instead will have the system fire the intent immediately instead
+ of showing a notification. OEMs who do this should have some intent receiver
+ listening to the intent and take the action they prefer (e.g. show a dialog,
+ show a customized notification etc). -->
<bool name="config_notifyNoInternetAsDialogWhenHighPriority">false</bool>
<!-- When showing notifications indicating partial connectivity, display the same notifications
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index 90cddda..b315235 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -44,7 +44,9 @@
import com.android.server.ConnectivityService;
import java.io.IOException;
+import java.net.Inet4Address;
import java.net.Inet6Address;
+import java.net.UnknownHostException;
import java.util.Objects;
/**
@@ -99,7 +101,8 @@
private IpPrefix mNat64PrefixFromRa;
private String mBaseIface;
private String mIface;
- private Inet6Address mIPv6Address;
+ @VisibleForTesting
+ Inet6Address mIPv6Address;
private State mState = State.IDLE;
private final ClatCoordinator mClatCoordinator; // non-null iff T+
@@ -239,6 +242,7 @@
mNat64PrefixInUse = null;
mIface = null;
mBaseIface = null;
+ mIPv6Address = null;
if (!mPrefixDiscoveryRunning) {
setPrefix64(null);
@@ -541,6 +545,52 @@
}
/**
+ * Translate the input v4 address to v6 clat address.
+ */
+ @Nullable
+ public Inet6Address translateV4toV6(@NonNull Inet4Address addr) {
+ // Variables in Nat464Xlat should only be accessed from handler thread.
+ ensureRunningOnHandlerThread();
+ if (!isStarted()) return null;
+
+ return convertv4ToClatv6(mNat64PrefixInUse, addr);
+ }
+
+ @Nullable
+ private static Inet6Address convertv4ToClatv6(
+ @NonNull IpPrefix prefix, @NonNull Inet4Address addr) {
+ final byte[] v6Addr = new byte[16];
+ // Generate a v6 address from Nat64 prefix. Prefix should be 12 bytes long.
+ System.arraycopy(prefix.getAddress().getAddress(), 0, v6Addr, 0, 12);
+ System.arraycopy(addr.getAddress(), 0, v6Addr, 12, 4);
+
+ try {
+ return (Inet6Address) Inet6Address.getByAddress(v6Addr);
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "getByAddress should never throw for a numeric address");
+ return null;
+ }
+ }
+
+ /**
+ * Get the generated v6 address of clat.
+ */
+ @Nullable
+ public Inet6Address getClatv6SrcAddress() {
+ // Variables in Nat464Xlat should only be accessed from handler thread.
+ ensureRunningOnHandlerThread();
+
+ return mIPv6Address;
+ }
+
+ private void ensureRunningOnHandlerThread() {
+ if (mNetwork.handler().getLooper().getThread() != Thread.currentThread()) {
+ throw new IllegalStateException(
+ "Not running on handler thread: " + Thread.currentThread().getName());
+ }
+ }
+
+ /**
* Dump the NAT64 xlat information.
*
* @param pw print writer.
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 85282cb..08c1455 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -68,6 +68,8 @@
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1033,6 +1035,22 @@
}
/**
+ * Get the generated v6 address of clat.
+ */
+ @Nullable
+ public Inet6Address getClatv6SrcAddress() {
+ return clatd.getClatv6SrcAddress();
+ }
+
+ /**
+ * Translate the input v4 address to v6 clat address.
+ */
+ @Nullable
+ public Inet6Address translateV4toClatV6(@NonNull Inet4Address addr) {
+ return clatd.translateV4toV6(addr);
+ }
+
+ /**
* Get the NetworkMonitorManager in this NetworkAgentInfo.
*
* <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called.
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
index 8b0cb7c..bc13592 100644
--- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -322,7 +322,8 @@
private boolean maybeNotifyViaDialog(Resources res, NotificationType notifyType,
PendingIntent intent) {
- if (notifyType != NotificationType.NO_INTERNET
+ if (notifyType != NotificationType.LOST_INTERNET
+ && notifyType != NotificationType.NO_INTERNET
&& notifyType != NotificationType.PARTIAL_CONNECTIVITY) {
return false;
}
@@ -432,7 +433,8 @@
* A notification with a higher number will take priority over a notification with a lower
* number.
*/
- private static int priority(NotificationType t) {
+ @VisibleForTesting
+ public static int priority(NotificationType t) {
if (t == null) {
return 0;
}
diff --git a/service/src/com/android/server/connectivity/ProxyTracker.java b/service/src/com/android/server/connectivity/ProxyTracker.java
index bda4b8f..6a0918b 100644
--- a/service/src/com/android/server/connectivity/ProxyTracker.java
+++ b/service/src/com/android/server/connectivity/ProxyTracker.java
@@ -86,6 +86,7 @@
private final Handler mConnectivityServiceHandler;
+ @Nullable
private final PacProxyManager mPacProxyManager;
private class PacProxyInstalledListener implements PacProxyManager.PacProxyInstalledListener {
@@ -109,9 +110,11 @@
mConnectivityServiceHandler = connectivityServiceInternalHandler;
mPacProxyManager = context.getSystemService(PacProxyManager.class);
- PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
- mPacProxyManager.addPacProxyInstalledListener(
+ if (mPacProxyManager != null) {
+ PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
+ mPacProxyManager.addPacProxyInstalledListener(
mConnectivityServiceHandler::post, listener);
+ }
}
// Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
@@ -205,7 +208,7 @@
mGlobalProxy = proxyProperties;
}
- if (!TextUtils.isEmpty(pacFileUrl)) {
+ if (!TextUtils.isEmpty(pacFileUrl) && mPacProxyManager != null) {
mConnectivityServiceHandler.post(
() -> mPacProxyManager.setCurrentProxyScriptUrl(proxyProperties));
}
@@ -251,7 +254,10 @@
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ?
defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
- mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo);
+
+ if (mPacProxyManager != null) {
+ mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo);
+ }
if (!shouldSendBroadcast(proxyInfo)) {
return;
diff --git a/tests/common/OWNERS b/tests/common/OWNERS
new file mode 100644
index 0000000..3101da5
--- /dev/null
+++ b/tests/common/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
\ No newline at end of file
diff --git a/tests/cts/OWNERS b/tests/cts/OWNERS
index 8388cb7..8c2408b 100644
--- a/tests/cts/OWNERS
+++ b/tests/cts/OWNERS
@@ -1,4 +1,5 @@
# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
set noparent
file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 03e74e0..a0508e1 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -847,7 +847,7 @@
assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
- Network wifiNetwork = mCtsNetUtils.connectToWifi();
+ Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
Network cellNetwork = mCtsNetUtils.connectToCell();
// This server returns the requestor's IP address as the response body.
URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
@@ -3152,7 +3152,8 @@
}
@AppModeFull(reason = "Need WiFi support to test the default active network")
- @Test
+ // NetworkActivityTracker is not mainlined before S.
+ @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public void testDefaultNetworkActiveListener() throws Exception {
final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI);
final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
@@ -3236,7 +3237,8 @@
newMobileDataPreferredUids.add(uid);
ConnectivitySettingsManager.setMobileDataPreferredUids(
mContext, newMobileDataPreferredUids);
- waitForAvailable(defaultTrackingCb, cellNetwork);
+ defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> cellNetwork.equals(entry.getNetwork()));
// No change for system default network. Expect no callback except CapabilitiesChanged
// or LinkPropertiesChanged which may be triggered randomly from wifi network.
assertNoCallbackExceptCapOrLpChange(systemDefaultCb);
@@ -3248,7 +3250,8 @@
newMobileDataPreferredUids.remove(uid);
ConnectivitySettingsManager.setMobileDataPreferredUids(
mContext, newMobileDataPreferredUids);
- waitForAvailable(defaultTrackingCb, wifiNetwork);
+ defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> wifiNetwork.equals(entry.getNetwork()));
// No change for system default network. Expect no callback except CapabilitiesChanged
// or LinkPropertiesChanged which may be triggered randomly from wifi network.
assertNoCallbackExceptCapOrLpChange(systemDefaultCb);
diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
index 4854901..b462f71 100644
--- a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
@@ -44,12 +44,15 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.RequiredFeatureRule;
+
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.TestHttpServer;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -76,6 +79,11 @@
private ServerSocket mServerSocket;
private Instrumentation mInstrumentation;
+ // Devices without WebView/JavaScript cannot support PAC proxies.
+ @Rule
+ public RequiredFeatureRule mRequiredWebviewFeatureRule =
+ new RequiredFeatureRule(PackageManager.FEATURE_WEBVIEW);
+
private static final String PAC_FILE = "function FindProxyForURL(url, host)"
+ "{"
+ " return \"PROXY 192.168.0.1:9091\";"
@@ -152,9 +160,6 @@
@AppModeFull(reason = "Instant apps can't bind sockets to localhost for a test proxy server")
@Test
public void testSetCurrentProxyScriptUrl() throws Exception {
- // Devices without WebView/JavaScript cannot support PAC proxies
- assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW));
-
// Register a PacProxyInstalledListener
final TestPacProxyInstalledListener listener = new TestPacProxyInstalledListener();
final Executor executor = (Runnable r) -> r.run();
diff --git a/tests/integration/OWNERS b/tests/integration/OWNERS
new file mode 100644
index 0000000..3101da5
--- /dev/null
+++ b/tests/integration/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
\ No newline at end of file
diff --git a/tests/mts/OWNERS b/tests/mts/OWNERS
new file mode 100644
index 0000000..3101da5
--- /dev/null
+++ b/tests/mts/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
\ No newline at end of file
diff --git a/tests/native/connectivity_native_test/OWNERS b/tests/native/connectivity_native_test/OWNERS
index 8dfa455..fbfcf92 100644
--- a/tests/native/connectivity_native_test/OWNERS
+++ b/tests/native/connectivity_native_test/OWNERS
@@ -1,3 +1,4 @@
-# Bug component: 31808
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
set noparent
file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
diff --git a/tests/unit/OWNERS b/tests/unit/OWNERS
new file mode 100644
index 0000000..3101da5
--- /dev/null
+++ b/tests/unit/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: http://b/new?component=31808
+# TODO: move bug template config to common owners file once b/226427845 is resolved
\ No newline at end of file
diff --git a/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
index 06e0d6d..58c0114 100644
--- a/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -20,10 +20,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
@@ -72,6 +74,7 @@
static final String STACKED_IFACE = "v4-test0";
static final LinkAddress V6ADDR = new LinkAddress("2001:db8:1::f00/64");
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
+ static final String CLAT_V6 = "64:ff9b::1";
static final String NAT64_PREFIX = "64:ff9b::/96";
static final String OTHER_NAT64_PREFIX = "2001:db8:0:64::/96";
static final int NETID = 42;
@@ -132,6 +135,8 @@
when(mNetd.interfaceGetCfg(eq(STACKED_IFACE))).thenReturn(mConfig);
mConfig.ipv4Addr = ADDR.getAddress().getHostAddress();
mConfig.prefixLength = ADDR.getPrefixLength();
+ doReturn(CLAT_V6).when(mClatCoordinator).clatStart(
+ BASE_IFACE, NETID, new IpPrefix(NAT64_PREFIX));
}
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
@@ -286,7 +291,8 @@
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
assertIdle(nat);
-
+ // Verify the generated v6 is reset when clat is stopped.
+ assertNull(nat.mIPv6Address);
// Stacked interface removed notification arrives and is ignored.
nat.interfaceRemoved(STACKED_IFACE);
mLooper.dispatchNext();
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index a27a0bf..967083e 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -62,6 +62,7 @@
import android.util.DisplayMetrics;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.test.filters.SmallTest;
@@ -386,14 +387,37 @@
}
@Test
- public void testNotifyNoInternetAsDialogWhenHighPriority() throws Exception {
- doReturn(true).when(mResources).getBoolean(
+ public void testNotifyNoInternet_asNotification() throws Exception {
+ doTestNotifyNotificationAsDialogWhenHighPriority(false, NO_INTERNET);
+ }
+ @Test
+ public void testNotifyNoInternet_asDialog() throws Exception {
+ doTestNotifyNotificationAsDialogWhenHighPriority(true, NO_INTERNET);
+ }
+
+ @Test
+ public void testNotifyLostInternet_asNotification() throws Exception {
+ doTestNotifyNotificationAsDialogWhenHighPriority(false, LOST_INTERNET);
+ }
+
+ @Test
+ public void testNotifyLostInternet_asDialog() throws Exception {
+ doTestNotifyNotificationAsDialogWhenHighPriority(true, LOST_INTERNET);
+ }
+
+ public void doTestNotifyNotificationAsDialogWhenHighPriority(final boolean configActive,
+ @NonNull final NotificationType notifType) throws Exception {
+ doReturn(configActive).when(mResources).getBoolean(
R.bool.config_notifyNoInternetAsDialogWhenHighPriority);
final Instrumentation instr = InstrumentationRegistry.getInstrumentation();
final UiDevice uiDevice = UiDevice.getInstance(instr);
final Context ctx = instr.getContext();
final PowerManager pm = ctx.getSystemService(PowerManager.class);
+ // If the prio of this notif is < that of NETWORK_SWITCH, it's the lowest prio and
+ // therefore it can't be tested whether it cancels other lower-prio notifs.
+ final boolean isLowestPrioNotif = NetworkNotificationManager.priority(notifType)
+ < NetworkNotificationManager.priority(NETWORK_SWITCH);
// Wake up the device (it has no effect if the device is already awake).
uiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
@@ -409,9 +433,13 @@
uiDevice.wait(Until.hasObject(By.pkg(launcherPackageName)),
UI_AUTOMATOR_WAIT_TIME_MILLIS));
- mManager.showNotification(TEST_NOTIF_ID, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
- // Non-"no internet" notifications are not affected
- verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(NETWORK_SWITCH.eventId), any());
+ if (!isLowestPrioNotif) {
+ mManager.showNotification(TEST_NOTIF_ID, NETWORK_SWITCH, mWifiNai, mCellNai,
+ null, false);
+ // Non-"no internet" notifications are not affected
+ verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(NETWORK_SWITCH.eventId),
+ any());
+ }
final String testAction = "com.android.connectivity.coverage.TEST_DIALOG";
final Intent intent = new Intent(testAction)
@@ -420,22 +448,30 @@
final PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0 /* requestCode */,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- mManager.showNotification(TEST_NOTIF_ID, NO_INTERNET, mWifiNai, null /* switchToNai */,
+ mManager.showNotification(TEST_NOTIF_ID, notifType, mWifiNai, null /* switchToNai */,
pendingIntent, true /* highPriority */);
- // Previous notifications are still dismissed
- verify(mNotificationManager).cancel(TEST_NOTIF_TAG, NETWORK_SWITCH.eventId);
+ if (!isLowestPrioNotif) {
+ // Previous notifications are still dismissed
+ verify(mNotificationManager).cancel(TEST_NOTIF_TAG, NETWORK_SWITCH.eventId);
+ }
- // Verify that the activity is shown (the activity shows the action on screen)
- final UiObject actionText = uiDevice.findObject(new UiSelector().text(testAction));
- assertTrue("Activity not shown", actionText.waitForExists(TEST_TIMEOUT_MS));
+ if (configActive) {
+ // Verify that the activity is shown (the activity shows the action on screen)
+ final UiObject actionText = uiDevice.findObject(new UiSelector().text(testAction));
+ assertTrue("Activity not shown", actionText.waitForExists(TEST_TIMEOUT_MS));
- // Tapping the text should dismiss the dialog
- actionText.click();
- assertTrue("Activity not dismissed", actionText.waitUntilGone(TEST_TIMEOUT_MS));
+ // Tapping the text should dismiss the dialog
+ actionText.click();
+ assertTrue("Activity not dismissed", actionText.waitUntilGone(TEST_TIMEOUT_MS));
- // Verify no NO_INTERNET notification was posted
- verify(mNotificationManager, never()).notify(any(), eq(NO_INTERNET.eventId), any());
+ // Verify that the notification was not posted
+ verify(mNotificationManager, never()).notify(any(), eq(notifType.eventId), any());
+ } else {
+ // Notification should have been posted, and will have overridden the previous
+ // one because it has the same id (hence no cancel).
+ verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(notifType.eventId), any());
+ }
}
private void doNotificationTextTest(NotificationType type, @StringRes int expectedTitleRes,