Merge "Deflake test to ensure system default network as expected"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 0ce43cc..54291a1 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,5 +1,8 @@
{
"presubmit": [
+ {
+ "name": "ConnectivityCoverageTests"
+ },
// Run in addition to mainline-presubmit as mainline-presubmit is not
// supported in every branch.
// CtsNetTestCasesLatestSdk uses stable API shims, so does not exercise
@@ -19,11 +22,6 @@
"name": "TetheringIntegrationTests"
}
],
- "postsubmit": [
- {
- "name": "ConnectivityCoverageTests"
- }
- ],
"mainline-presubmit": [
{
"name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
@@ -32,6 +30,9 @@
"exclude-annotation": "com.android.testutils.SkipPresubmit"
}
]
+ },
+ {
+ "name": "ConnectivityCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
"mainline-postsubmit": [
@@ -42,9 +43,6 @@
},
{
"name": "TetheringCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
- },
- {
- "name": "ConnectivityCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
"imports": [
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index 611c828..f537e90 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -371,6 +371,7 @@
} catch (IllegalStateException e) {
// Silent if the rule already exists. Note that the errno EEXIST was rethrown as
// IllegalStateException. See BpfMap#insertEntry.
+ return false;
}
return true;
}
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index 08ab9ca..3c2ce0f 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -141,6 +141,11 @@
/**
* Adds a tethering IPv4 offload rule to appropriate BPF map.
+ *
+ * @param downstream true if downstream, false if upstream.
+ * @param key the key to add.
+ * @param value the value to add.
+ * @return true iff the map was modified, false if the key exists or there was an error.
*/
public abstract boolean tetherOffloadRuleAdd(boolean downstream, @NonNull Tether4Key key,
@NonNull Tether4Value value);
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 822bdf6..859f23a 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -26,6 +26,7 @@
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+import static com.android.networkstack.tethering.UpstreamNetworkState.isVcnInterface;
import android.net.INetd;
import android.net.INetworkStackStatusCallback;
@@ -755,6 +756,9 @@
// deprecation of any existing RA data.
setRaParams(params);
+ // Be aware that updateIpv6ForwardingRules use mLastIPv6LinkProperties, so this line should
+ // be eariler than updateIpv6ForwardingRules.
+ // TODO: avoid this dependencies and move this logic into BpfCoordinator.
mLastIPv6LinkProperties = v6only;
updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
@@ -892,12 +896,20 @@
mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex);
}
+ private boolean isIpv6VcnNetworkInterface() {
+ if (mLastIPv6LinkProperties == null) return false;
+
+ return isVcnInterface(mLastIPv6LinkProperties.getInterfaceName());
+ }
+
// Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
// changes or if a neighbor event is received.
private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
NeighborEvent e) {
- // If we no longer have an upstream, clear forwarding rules and do nothing else.
- if (upstreamIfindex == 0) {
+ // If no longer have an upstream or it is virtual network, clear forwarding rules and do
+ // nothing else.
+ // TODO: Rather than always clear rules, ensure whether ipv6 ever enable first.
+ if (upstreamIfindex == 0 || isIpv6VcnNetworkInterface()) {
clearIpv6ForwardingRules();
return;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 2c1fd29..f4a6916 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -31,6 +31,7 @@
import static com.android.networkstack.tethering.BpfUtils.DOWNSTREAM;
import static com.android.networkstack.tethering.BpfUtils.UPSTREAM;
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
+import static com.android.networkstack.tethering.UpstreamNetworkState.isVcnInterface;
import android.app.usage.NetworkStatsManager;
import android.net.INetd;
@@ -123,10 +124,21 @@
return makeMapPath((downstream ? "downstream" : "upstream") + ipVersion);
}
+ // TODO: probably to remember what the timeout updated things to last is. But that requires
+ // either r/w map entries (which seems bad/racy) or a separate map to keep track of all flows
+ // and remember when they were updated and with what timeout.
@VisibleForTesting
- static final int POLLING_CONNTRACK_TIMEOUT_MS = 60_000;
+ static final int CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS = 60_000;
@VisibleForTesting
- static final int NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED = 432000;
+ static final int CONNTRACK_TIMEOUT_UPDATE_SLACK_MS = 20_000;
+
+ // Default timeouts sync from /proc/sys/net/netfilter/nf_conntrack_*
+ // See also kernel document nf_conntrack-sysctl.txt.
+ @VisibleForTesting
+ static final int NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED = 432_000;
+ static final int NF_CONNTRACK_TCP_TIMEOUT_UNACKNOWLEDGED = 300;
+ // The default value is 120 for 5.10 and that thus the periodicity of the updates of 60s is
+ // low enough to support all ACK kernels.
@VisibleForTesting
static final int NF_CONNTRACK_UDP_TIMEOUT_STREAM = 180;
@@ -249,10 +261,10 @@
maybeSchedulePollingStats();
};
- // Runnable that used by scheduling next polling of conntrack timeout.
- private final Runnable mScheduledPollingConntrackTimeout = () -> {
- maybeRefreshConntrackTimeout();
- maybeSchedulePollingConntrackTimeout();
+ // Runnable that used by scheduling next refreshing of conntrack timeout.
+ private final Runnable mScheduledConntrackTimeoutUpdate = () -> {
+ refreshAllConntrackTimeouts();
+ maybeScheduleConntrackTimeoutUpdate();
};
// TODO: add BpfMap<TetherDownstream64Key, TetherDownstream64Value> retrieving function.
@@ -434,7 +446,7 @@
mPollingStarted = true;
maybeSchedulePollingStats();
- maybeSchedulePollingConntrackTimeout();
+ maybeScheduleConntrackTimeoutUpdate();
mLog.i("Polling started");
}
@@ -451,8 +463,8 @@
if (!mPollingStarted) return;
// Stop scheduled polling conntrack timeout.
- if (mHandler.hasCallbacks(mScheduledPollingConntrackTimeout)) {
- mHandler.removeCallbacks(mScheduledPollingConntrackTimeout);
+ if (mHandler.hasCallbacks(mScheduledConntrackTimeoutUpdate)) {
+ mHandler.removeCallbacks(mScheduledConntrackTimeoutUpdate);
}
// Stop scheduled polling stats and poll the latest stats from BPF maps.
if (mHandler.hasCallbacks(mScheduledPollingStats)) {
@@ -666,6 +678,8 @@
if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
+ if (isVcnInterface(upstreamIface)) return;
+
// The same interface index to name mapping may be added by different IpServer objects or
// re-added by reconnection on the same upstream interface. Ignore the duplicate one.
final String iface = mInterfaceNames.get(upstreamIfindex);
@@ -833,9 +847,10 @@
// TODO: need to consider 464xlat.
if (ns != null && ns.linkProperties != null && ns.linkProperties.hasIpv4Address()) {
// TODO: support ether ip upstream interface.
- final InterfaceParams params = mDeps.getInterfaceParams(
- ns.linkProperties.getInterfaceName());
- if (params != null && !params.hasMacAddress /* raw ip upstream only */) {
+ final String ifaceName = ns.linkProperties.getInterfaceName();
+ final InterfaceParams params = mDeps.getInterfaceParams(ifaceName);
+ final boolean isVcn = isVcnInterface(ifaceName);
+ if (!isVcn && params != null && !params.hasMacAddress /* raw ip upstream only */) {
upstreamIndex = params.index;
}
}
@@ -879,6 +894,8 @@
* TODO: consider error handling if the attach program failed.
*/
public void maybeAttachProgram(@NonNull String intIface, @NonNull String extIface) {
+ if (isVcnInterface(extIface)) return;
+
if (forwardingPairExists(intIface, extIface)) return;
boolean firstDownstreamForThisUpstream = !isAnyForwardingPairOnUpstream(extIface);
@@ -1051,6 +1068,15 @@
}
}
+ private String l4protoToString(int proto) {
+ if (proto == OsConstants.IPPROTO_TCP) {
+ return "tcp";
+ } else if (proto == OsConstants.IPPROTO_UDP) {
+ return "udp";
+ }
+ return String.format("unknown(%d)", proto);
+ }
+
private String ipv4RuleToString(long now, boolean downstream,
Tether4Key key, Tether4Value value) {
final String src4, public4, dst4;
@@ -1069,12 +1095,11 @@
throw new AssertionError("IP address array not valid IPv4 address!");
}
- final String protoStr = (key.l4proto == OsConstants.IPPROTO_TCP) ? "tcp" : "udp";
final String ageStr = (value.lastUsed == 0) ? "-"
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
- protoStr, key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
- value.oif, getIfName(value.oif),
+ l4protoToString(key.l4proto), key.dstMac, key.iif, getIfName(key.iif),
+ src4, key.srcPort, value.oif, getIfName(value.oif),
public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageStr);
}
@@ -1443,25 +1468,6 @@
return addr6;
}
- @Nullable
- private Inet4Address ipv4MappedAddressBytesToIpv4Address(final byte[] addr46) {
- if (addr46.length != 16) return null;
- if (addr46[0] != 0 || addr46[1] != 0 || addr46[2] != 0 || addr46[3] != 0
- || addr46[4] != 0 || addr46[5] != 0 || addr46[6] != 0 || addr46[7] != 0
- || addr46[8] != 0 && addr46[9] != 0 || (addr46[10] & 0xff) != 0xff
- || (addr46[11] & 0xff) != 0xff) {
- return null;
- }
-
- final byte[] addr4 = new byte[4];
- addr4[0] = addr46[12];
- addr4[1] = addr46[13];
- addr4[2] = addr46[14];
- addr4[3] = addr46[15];
-
- return parseIPv4Address(addr4);
- }
-
// TODO: parse CTA_PROTOINFO of conntrack event in ConntrackMonitor. For TCP, only add rules
// while TCP status is established.
@VisibleForTesting
@@ -1572,8 +1578,34 @@
final Tether4Key downstream4Key = makeTetherDownstream4Key(e, tetherClient,
upstreamIndex);
- if (e.msgType == (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
- | NetlinkConstants.IPCTNL_MSG_CT_DELETE)) {
+ final boolean isConntrackEventDelete =
+ e.msgType == (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
+ | NetlinkConstants.IPCTNL_MSG_CT_DELETE);
+
+ // Using the timeout to distinguish tcp state is not a decent way. Need to fix.
+ // The received IPCTNL_MSG_CT_NEW must pass ConntrackMonitor#isEstablishedNatSession
+ // which checks CTA_STATUS. It implies that this entry has at least reached tcp
+ // state "established". For safety, treat any timeout which is equal or larger than 300
+ // seconds (UNACKNOWLEDGED, ESTABLISHED, ..) to be "established".
+ // TODO: parse tcp state in conntrack monitor.
+ final boolean isTcpEstablished =
+ e.msgType == (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
+ | NetlinkConstants.IPCTNL_MSG_CT_NEW)
+ && e.tupleOrig.protoNum == OsConstants.IPPROTO_TCP
+ && (e.timeoutSec >= NF_CONNTRACK_TCP_TIMEOUT_UNACKNOWLEDGED);
+
+ final boolean isTcpNonEstablished =
+ e.msgType == (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8
+ | NetlinkConstants.IPCTNL_MSG_CT_NEW)
+ && e.tupleOrig.protoNum == OsConstants.IPPROTO_TCP
+ && (e.timeoutSec < NF_CONNTRACK_TCP_TIMEOUT_UNACKNOWLEDGED);
+
+ // Delete the BPF rules:
+ // 1. Contrack event IPCTNL_MSG_CT_DELETE received.
+ // 2. For TCP conntrack entry, the tcp state has left "established" and going to be
+ // closed.
+ // TODO: continue to offload half-closed tcp connections.
+ if (isConntrackEventDelete || isTcpNonEstablished) {
final boolean deletedUpstream = mBpfCoordinatorShim.tetherOffloadRuleRemove(
UPSTREAM, upstream4Key);
final boolean deletedDownstream = mBpfCoordinatorShim.tetherOffloadRuleRemove(
@@ -1588,6 +1620,7 @@
Log.wtf(TAG, "The bidirectional rules should be removed concurrently ("
+ "upstream: " + deletedUpstream
+ ", downstream: " + deletedDownstream + ")");
+ // TODO: consider better error handling for the stubs {rule, limit, ..}.
return;
}
@@ -1598,11 +1631,41 @@
final Tether4Value upstream4Value = makeTetherUpstream4Value(e, upstreamIndex);
final Tether4Value downstream4Value = makeTetherDownstream4Value(e, tetherClient,
upstreamIndex);
-
maybeAddDevMap(upstreamIndex, tetherClient.downstreamIfindex);
maybeSetLimit(upstreamIndex);
- mBpfCoordinatorShim.tetherOffloadRuleAdd(UPSTREAM, upstream4Key, upstream4Value);
- mBpfCoordinatorShim.tetherOffloadRuleAdd(DOWNSTREAM, downstream4Key, downstream4Value);
+
+ final boolean upstreamAdded = mBpfCoordinatorShim.tetherOffloadRuleAdd(UPSTREAM,
+ upstream4Key, upstream4Value);
+ final boolean downstreamAdded = mBpfCoordinatorShim.tetherOffloadRuleAdd(DOWNSTREAM,
+ downstream4Key, downstream4Value);
+
+ if (upstreamAdded != downstreamAdded) {
+ mLog.e("The bidirectional rules should be added or not added concurrently ("
+ + "upstream: " + upstreamAdded
+ + ", downstream: " + downstreamAdded + "). "
+ + "Remove the added rules.");
+ if (upstreamAdded) {
+ mBpfCoordinatorShim.tetherOffloadRuleRemove(UPSTREAM, upstream4Key);
+ }
+ if (downstreamAdded) {
+ mBpfCoordinatorShim.tetherOffloadRuleRemove(DOWNSTREAM, downstream4Key);
+ }
+ return;
+ }
+
+ // Update TCP timeout iif it is first time we're adding the rules. Needed because a
+ // payload data packet may have gone through non-offload path, before we added offload
+ // rules, and that this may result in in-kernel conntrack state being in ESTABLISHED
+ // but pending ACK (ie. UNACKED) state. But the in-kernel conntrack might never see the
+ // ACK because we just added offload rules. As such after adding the rules we need to
+ // force the timeout back to the normal ESTABLISHED timeout of 5 days. Note that
+ // updating the timeout will trigger another netlink event with the updated timeout.
+ // TODO: Remove this once the tcp state is parsed.
+ if (isTcpEstablished && upstreamAdded && downstreamAdded) {
+ updateConntrackTimeout((byte) upstream4Key.l4proto,
+ parseIPv4Address(upstream4Key.src4), (short) upstream4Key.srcPort,
+ parseIPv4Address(upstream4Key.dst4), (short) upstream4Key.dstPort);
+ }
}
}
@@ -1861,7 +1924,7 @@
try {
final InetAddress ia = Inet4Address.getByAddress(addrBytes);
if (ia instanceof Inet4Address) return (Inet4Address) ia;
- } catch (UnknownHostException | IllegalArgumentException e) {
+ } catch (UnknownHostException e) {
mLog.e("Failed to parse IPv4 address: " + e);
}
return null;
@@ -1871,12 +1934,21 @@
// coming a conntrack event to notify updated timeout.
private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
Inet4Address dst4, short dstPort) {
- if (src4 == null || dst4 == null) return;
+ if (src4 == null || dst4 == null) {
+ mLog.e("Either source or destination IPv4 address is invalid ("
+ + "proto: " + proto + ", "
+ + "src4: " + src4 + ", "
+ + "srcPort: " + Short.toUnsignedInt(srcPort) + ", "
+ + "dst4: " + dst4 + ", "
+ + "dstPort: " + Short.toUnsignedInt(dstPort) + ")");
+ return;
+ }
// TODO: consider acquiring the timeout setting from nf_conntrack_* variables.
// - proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
// - proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream
// See kernel document nf_conntrack-sysctl.txt.
+ // TODO: we should account for the fact that lastUsed is in the past and not exactly now.
final int timeoutSec = (proto == OsConstants.IPPROTO_TCP)
? NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED
: NF_CONNTRACK_UDP_TIMEOUT_STREAM;
@@ -1885,38 +1957,67 @@
try {
NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg);
} catch (ErrnoException e) {
- mLog.e("Error updating conntrack entry ("
+ // Lower the log level for the entry not existing. The conntrack entry may have been
+ // deleted and not handled by the conntrack event monitor yet. In other words, the
+ // rule has not been deleted from the BPF map yet. Deleting a non-existent entry may
+ // happen during the conntrack timeout refreshing iteration. Note that ENOENT may be
+ // a real error but is hard to distinguish.
+ // TODO: Figure out a better way to handle this.
+ final String errMsg = "Failed to update conntrack entry ("
+ "proto: " + proto + ", "
+ "src4: " + src4 + ", "
+ "srcPort: " + Short.toUnsignedInt(srcPort) + ", "
+ "dst4: " + dst4 + ", "
+ "dstPort: " + Short.toUnsignedInt(dstPort) + "), "
+ "msg: " + NetlinkConstants.hexify(msg) + ", "
- + "e: " + e);
+ + "e: " + e;
+ if (OsConstants.ENOENT == e.errno) {
+ mLog.w(errMsg);
+ } else {
+ mLog.e(errMsg);
+ }
}
}
- private void maybeRefreshConntrackTimeout() {
- final long now = mDeps.elapsedRealtimeNanos();
+ boolean requireConntrackTimeoutUpdate(long nowNs, long lastUsedNs, int proto) {
+ // Refreshing tcp timeout without checking tcp state may make the conntrack entry live
+ // 5 days (432000s) even while the session is being closed. Its BPF rule may not be
+ // deleted for 5 days because the tcp state gets stuck and conntrack delete message is
+ // not sent. Note that both the conntrack monitor and refreshing timeout updater are
+ // in the same thread. Beware while the tcp status may be changed running in refreshing
+ // timeout updater and may read out-of-date tcp stats.
+ // See nf_conntrack_tcp_timeout_established in kernel document.
+ // TODO: support refreshing TCP conntrack timeout.
+ if (proto == OsConstants.IPPROTO_TCP) return false;
- // Reverse the source and destination {address, port} from downstream value because
- // #updateConntrackTimeout refresh the timeout of netlink attribute CTA_TUPLE_ORIG
- // which is opposite direction for downstream map value.
- mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
- if ((now - v.lastUsed) / 1_000_000 < POLLING_CONNTRACK_TIMEOUT_MS) {
- updateConntrackTimeout((byte) k.l4proto,
- ipv4MappedAddressBytesToIpv4Address(v.dst46), (short) v.dstPort,
- ipv4MappedAddressBytesToIpv4Address(v.src46), (short) v.srcPort);
- }
- });
+ // The timeout requirement check needs the slack time because the scheduled timer may
+ // be not precise. The timeout update has a chance to be missed.
+ return (nowNs - lastUsedNs) < (long) (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS
+ + CONNTRACK_TIMEOUT_UPDATE_SLACK_MS) * 1_000_000;
+ }
+
+ private void refreshAllConntrackTimeouts() {
+ final long now = mDeps.elapsedRealtimeNanos();
// TODO: Consider ignoring TCP traffic on upstream and monitor on downstream only
// because TCP is a bidirectional traffic. Probably don't need to extend timeout by
// both directions for TCP.
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
- if ((now - v.lastUsed) / 1_000_000 < POLLING_CONNTRACK_TIMEOUT_MS) {
- updateConntrackTimeout((byte) k.l4proto, parseIPv4Address(k.src4),
- (short) k.srcPort, parseIPv4Address(k.dst4), (short) k.dstPort);
+ if (requireConntrackTimeoutUpdate(now, v.lastUsed, k.l4proto)) {
+ updateConntrackTimeout((byte) k.l4proto,
+ parseIPv4Address(k.src4), (short) k.srcPort,
+ parseIPv4Address(k.dst4), (short) k.dstPort);
+ }
+ });
+
+ // Reverse the source and destination {address, port} from downstream value because
+ // #updateConntrackTimeout refreshes the timeout of netlink attribute CTA_TUPLE_ORIG
+ // which is opposite direction for downstream map value.
+ mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
+ if (requireConntrackTimeoutUpdate(now, v.lastUsed, k.l4proto)) {
+ updateConntrackTimeout((byte) k.l4proto,
+ parseIPv4Address(v.dst46), (short) v.dstPort,
+ parseIPv4Address(v.src46), (short) v.srcPort);
}
});
}
@@ -1931,14 +2032,15 @@
mHandler.postDelayed(mScheduledPollingStats, getPollingInterval());
}
- private void maybeSchedulePollingConntrackTimeout() {
+ private void maybeScheduleConntrackTimeoutUpdate() {
if (!mPollingStarted) return;
- if (mHandler.hasCallbacks(mScheduledPollingConntrackTimeout)) {
- mHandler.removeCallbacks(mScheduledPollingConntrackTimeout);
+ if (mHandler.hasCallbacks(mScheduledConntrackTimeoutUpdate)) {
+ mHandler.removeCallbacks(mScheduledConntrackTimeoutUpdate);
}
- mHandler.postDelayed(mScheduledPollingConntrackTimeout, POLLING_CONNTRACK_TIMEOUT_MS);
+ mHandler.postDelayed(mScheduledConntrackTimeoutUpdate,
+ CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
}
// Return forwarding rule map. This is used for testing only.
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java
index bab9f84..986c3f7 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java
@@ -15,6 +15,8 @@
*/
package com.android.networkstack.tethering;
+import static android.net.INetd.IPSEC_INTERFACE_PREFIX;
+
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -48,4 +50,9 @@
networkCapabilities == null ? "null" : networkCapabilities,
linkProperties == null ? "null" : linkProperties);
}
+
+ /** Check whether the interface is VCN. */
+ public static boolean isVcnInterface(@NonNull String iface) {
+ return iface.startsWith(IPSEC_INTERFACE_PREFIX);
+ }
}
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 378a21c..6bf6a9f 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -146,8 +146,10 @@
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
+ private static final String IPSEC_IFACE = "ipsec0";
private static final int UPSTREAM_IFINDEX = 101;
private static final int UPSTREAM_IFINDEX2 = 102;
+ private static final int IPSEC_IFINDEX = 103;
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
private static final int DHCP_LEASE_TIME_SECS = 3600;
@@ -160,6 +162,8 @@
private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS,
1500 /* defaultMtu */);
+ private static final InterfaceParams IPSEC_IFACE_PARAMS = new InterfaceParams(
+ IPSEC_IFACE, IPSEC_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
@@ -208,6 +212,7 @@
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
+ when(mDependencies.getInterfaceParams(IPSEC_IFACE)).thenReturn(IPSEC_IFACE_PARAMS);
mInterfaceConfiguration = new InterfaceConfigurationParcel();
mInterfaceConfiguration.flags = new String[0];
@@ -1453,4 +1458,23 @@
public void testDadProxyUpdates_EnabledAfterR() throws Exception {
checkDadProxyEnabled(true);
}
+
+ @Test
+ public void testSkipVirtualNetworkInBpf() throws Exception {
+ initTetheredStateMachine(TETHERING_BLUETOOTH, null);
+ final LinkProperties v6Only = new LinkProperties();
+ v6Only.setInterfaceName(IPSEC_IFACE);
+ dispatchTetherConnectionChanged(IPSEC_IFACE, v6Only, 0);
+
+ verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, IPSEC_IFACE);
+ verify(mNetd).tetherAddForward(IFACE_NAME, IPSEC_IFACE);
+ verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, IPSEC_IFACE);
+
+ final int myIfindex = TEST_IFACE_PARAMS.index;
+ final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1");
+ final MacAddress mac = MacAddress.fromString("00:00:00:00:00:0a");
+ recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, mac);
+ verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(IPSEC_IFINDEX, neigh, mac));
+ }
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 914e0d4..ab542d6 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -40,9 +40,10 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker;
+import static com.android.networkstack.tethering.BpfCoordinator.CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS;
+import static com.android.networkstack.tethering.BpfCoordinator.CONNTRACK_TIMEOUT_UPDATE_SLACK_MS;
import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED;
import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_UDP_TIMEOUT_STREAM;
-import static com.android.networkstack.tethering.BpfCoordinator.POLLING_CONNTRACK_TIMEOUT_MS;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
@@ -1128,6 +1129,7 @@
final String intIface1 = "wlan1";
final String intIface2 = "rndis0";
final String extIface = "rmnet_data0";
+ final String virtualIface = "ipsec0";
final BpfUtils mockMarkerBpfUtils = staticMockMarker(BpfUtils.class);
final BpfCoordinator coordinator = makeBpfCoordinator();
@@ -1163,6 +1165,14 @@
ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface1));
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
+
+ // [6] Skip attaching if upstream is virtual interface.
+ coordinator.maybeAttachProgram(intIface1, virtualIface);
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface, DOWNSTREAM), never());
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM), never());
+ ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
+ ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
+
} finally {
mockSession.finishMocking();
}
@@ -1369,8 +1379,14 @@
}
final int status = (msgType == IPCTNL_MSG_CT_NEW) ? ESTABLISHED_MASK : DYING_MASK;
- final int timeoutSec = (msgType == IPCTNL_MSG_CT_NEW) ? 100 /* nonzero, new */
- : 0 /* unused, delete */;
+ int timeoutSec;
+ if (msgType == IPCTNL_MSG_CT_NEW) {
+ timeoutSec = (proto == IPPROTO_TCP)
+ ? NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED
+ : NF_CONNTRACK_UDP_TIMEOUT_STREAM;
+ } else {
+ timeoutSec = 0; /* unused, CT_DELETE */
+ }
return new ConntrackEvent(
(short) (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 | msgType),
new Tuple(new TupleIpv4(PRIVATE_ADDR, REMOTE_ADDR),
@@ -1526,23 +1542,27 @@
}
private void checkRefreshConntrackTimeout(final TestBpfMap<Tether4Key, Tether4Value> bpfMap,
- final Tether4Key tcpKey, final Tether4Value tcpValue, final Tether4Key udpKey,
- final Tether4Value udpValue) throws Exception {
+ int proto, final Tether4Key key, final Tether4Value value) throws Exception {
+ if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
+ fail("Not support protocol " + proto);
+ }
// Both system elapsed time since boot and the rule last used time are used to measure
// the rule expiration. In this test, all test rules are fixed the last used time to 0.
// Set the different testing elapsed time to make the rule to be valid or expired.
//
// Timeline:
- // 0 60 (seconds)
- // +---+---+---+---+--...--+---+---+---+---+---+- ..
- // | POLLING_CONNTRACK_TIMEOUT_MS |
- // +---+---+---+---+--...--+---+---+---+---+---+- ..
- // |<- valid diff ->|
- // |<- expired diff ->|
- // ^ ^ ^
- // last used time elapsed time (valid) elapsed time (expired)
- final long validTime = (POLLING_CONNTRACK_TIMEOUT_MS - 1) * 1_000_000L;
- final long expiredTime = (POLLING_CONNTRACK_TIMEOUT_MS + 1) * 1_000_000L;
+ // CONNTRACK_TIMEOUT_UPDATE_SLACK_MS
+ // ->| |<-
+ // +---+---+---+---+---+--...--+---+---+---+---+---+-..-+---+-- ..
+ // | CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS |
+ // +---+---+---+---+---+--...--+---+---+---+---+---+-..-+---+-- ..
+ // |<- valid diff ->|
+ // |<- expired diff ->|
+ // ^ ^ ^
+ // last used time elapsed time (valid) elapsed time (expired)
+ final long validTimeNs = CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS * 1_000_000L;
+ final long expiredTimeNs = (CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS
+ + CONNTRACK_TIMEOUT_UPDATE_SLACK_MS + 1) * 1_000_000L;
// Static mocking for NetlinkSocket.
MockitoSession mockSession = ExtendedMockito.mockitoSession()
@@ -1551,36 +1571,33 @@
try {
final BpfCoordinator coordinator = makeBpfCoordinator();
coordinator.startPolling();
- bpfMap.insertEntry(tcpKey, tcpValue);
- bpfMap.insertEntry(udpKey, udpValue);
+ bpfMap.insertEntry(key, value);
// [1] Don't refresh contrack timeout.
- setElapsedRealtimeNanos(expiredTime);
- mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+ setElapsedRealtimeNanos(expiredTimeNs);
+ mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
- // [2] Refresh contrack timeout.
- setElapsedRealtimeNanos(validTime);
- mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+ // [2] Refresh contrack timeout. UDP Only.
+ setElapsedRealtimeNanos(validTimeNs);
+ mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
- final byte[] expectedNetlinkTcp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
- IPPROTO_TCP, PRIVATE_ADDR, (int) PRIVATE_PORT, REMOTE_ADDR,
- (int) REMOTE_PORT, NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED);
- final byte[] expectedNetlinkUdp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
- IPPROTO_UDP, PRIVATE_ADDR, (int) PRIVATE_PORT, REMOTE_ADDR,
- (int) REMOTE_PORT, NF_CONNTRACK_UDP_TIMEOUT_STREAM);
- ExtendedMockito.verify(() -> NetlinkSocket.sendOneShotKernelMessage(
- eq(NETLINK_NETFILTER), eq(expectedNetlinkTcp)));
- ExtendedMockito.verify(() -> NetlinkSocket.sendOneShotKernelMessage(
- eq(NETLINK_NETFILTER), eq(expectedNetlinkUdp)));
+
+ if (proto == IPPROTO_UDP) {
+ final byte[] expectedNetlinkUdp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
+ IPPROTO_UDP, PRIVATE_ADDR, (int) PRIVATE_PORT, REMOTE_ADDR,
+ (int) REMOTE_PORT, NF_CONNTRACK_UDP_TIMEOUT_STREAM);
+ ExtendedMockito.verify(() -> NetlinkSocket.sendOneShotKernelMessage(
+ eq(NETLINK_NETFILTER), eq(expectedNetlinkUdp)));
+ }
ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
// [3] Don't refresh contrack timeout if polling stopped.
coordinator.stopPolling();
- mTestLooper.moveTimeForward(POLLING_CONNTRACK_TIMEOUT_MS);
+ mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
@@ -1591,33 +1608,57 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.R)
- public void testRefreshConntrackTimeout_Upstream4Map() throws Exception {
+ public void testRefreshConntrackTimeout_Upstream4MapTcp() throws Exception {
// TODO: Replace the dependencies BPF map with a non-mocked TestBpfMap object.
final TestBpfMap<Tether4Key, Tether4Value> bpfUpstream4Map =
new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
doReturn(bpfUpstream4Map).when(mDeps).getBpfUpstream4Map();
- final Tether4Key tcpKey = makeUpstream4Key(IPPROTO_TCP);
- final Tether4Key udpKey = makeUpstream4Key(IPPROTO_UDP);
- final Tether4Value tcpValue = makeUpstream4Value();
- final Tether4Value udpValue = makeUpstream4Value();
+ final Tether4Key key = makeUpstream4Key(IPPROTO_TCP);
+ final Tether4Value value = makeUpstream4Value();
- checkRefreshConntrackTimeout(bpfUpstream4Map, tcpKey, tcpValue, udpKey, udpValue);
+ checkRefreshConntrackTimeout(bpfUpstream4Map, IPPROTO_TCP, key, value);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.R)
- public void testRefreshConntrackTimeout_Downstream4Map() throws Exception {
+ public void testRefreshConntrackTimeout_Upstream4MapUdp() throws Exception {
+ // TODO: Replace the dependencies BPF map with a non-mocked TestBpfMap object.
+ final TestBpfMap<Tether4Key, Tether4Value> bpfUpstream4Map =
+ new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
+ doReturn(bpfUpstream4Map).when(mDeps).getBpfUpstream4Map();
+
+ final Tether4Key key = makeUpstream4Key(IPPROTO_UDP);
+ final Tether4Value value = makeUpstream4Value();
+
+ checkRefreshConntrackTimeout(bpfUpstream4Map, IPPROTO_UDP, key, value);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testRefreshConntrackTimeout_Downstream4MapTcp() throws Exception {
// TODO: Replace the dependencies BPF map with a non-mocked TestBpfMap object.
final TestBpfMap<Tether4Key, Tether4Value> bpfDownstream4Map =
new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
doReturn(bpfDownstream4Map).when(mDeps).getBpfDownstream4Map();
- final Tether4Key tcpKey = makeDownstream4Key(IPPROTO_TCP);
- final Tether4Key udpKey = makeDownstream4Key(IPPROTO_UDP);
- final Tether4Value tcpValue = makeDownstream4Value();
- final Tether4Value udpValue = makeDownstream4Value();
+ final Tether4Key key = makeDownstream4Key(IPPROTO_TCP);
+ final Tether4Value value = makeDownstream4Value();
- checkRefreshConntrackTimeout(bpfDownstream4Map, tcpKey, tcpValue, udpKey, udpValue);
+ checkRefreshConntrackTimeout(bpfDownstream4Map, IPPROTO_TCP, key, value);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testRefreshConntrackTimeout_Downstream4MapUdp() throws Exception {
+ // TODO: Replace the dependencies BPF map with a non-mocked TestBpfMap object.
+ final TestBpfMap<Tether4Key, Tether4Value> bpfDownstream4Map =
+ new TestBpfMap<>(Tether4Key.class, Tether4Value.class);
+ doReturn(bpfDownstream4Map).when(mDeps).getBpfDownstream4Map();
+
+ final Tether4Key key = makeDownstream4Key(IPPROTO_UDP);
+ final Tether4Value value = makeDownstream4Value();
+
+ checkRefreshConntrackTimeout(bpfDownstream4Map, IPPROTO_UDP, key, value);
}
}
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 715a532..13ecb12 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -68,7 +68,6 @@
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
- method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 14ec608..eecd12c 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1187,7 +1187,8 @@
*
* @return a {@link Network} object for the current default network for the
* given UID or {@code null} if no default network is currently active
- * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
+ *
+ * @hide
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@Nullable
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 5caa11b..4ba6837 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1,17 +1,97 @@
-rule android.sysprop.** com.android.connectivity.sysprop.@1
-rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
-rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
+rule android.sysprop.** com.android.connectivity.@0
+rule com.android.net.module.util.** com.android.connectivity.@0
+rule com.android.modules.utils.** com.android.connectivity.@0
-# internal util classes
-# Exclude AsyncChannel. TODO: remove AsyncChannel usage in ConnectivityService
-rule com.android.internal.util.AsyncChannel* @0
-# Exclude LocationPermissionChecker. This is going to be moved to libs/net
-rule com.android.internal.util.LocationPermissionChecker* @0
-rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1
+# internal util classes from framework-connectivity-shared-srcs
+rule android.util.LocalLog* com.android.connectivity.@0
# android.util.IndentingPrintWriter* should use a different package name from
# the one in com.android.internal.util
-rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1
-rule com.android.internal.util.** com.android.connectivity.util.@1
+rule android.util.IndentingPrintWriter* com.android.connectivity.@0
+rule com.android.internal.util.IndentingPrintWriter* com.android.connectivity.@0
+rule com.android.internal.util.IState* com.android.connectivity.@0
+rule com.android.internal.util.MessageUtils* com.android.connectivity.@0
+rule com.android.internal.util.State* com.android.connectivity.@0
+rule com.android.internal.util.StateMachine* com.android.connectivity.@0
+rule com.android.internal.util.WakeupMessage* com.android.connectivity.@0
-rule com.android.internal.messages.** com.android.connectivity.messages.@1
-rule com.google.protobuf.** com.android.connectivity.protobuf.@1
+rule com.android.internal.messages.** com.android.connectivity.@0
+rule com.google.protobuf.** com.android.connectivity.@0
+
+# From dnsresolver_aidl_interface (newer AIDLs should go to android.net.resolv.aidl)
+rule android.net.resolv.aidl.** com.android.connectivity.@0
+rule android.net.IDnsResolver* com.android.connectivity.@0
+rule android.net.ResolverHostsParcel* com.android.connectivity.@0
+rule android.net.ResolverOptionsParcel* com.android.connectivity.@0
+rule android.net.ResolverParamsParcel* com.android.connectivity.@0
+rule android.net.ResolverParamsParcel* com.android.connectivity.@0
+# Also includes netd event listener AIDL, but this is handled by netd-client rules
+
+# From net-utils-device-common
+rule android.net.NetworkFactory* com.android.connectivity.@0
+
+# From netd-client (newer AIDLs should go to android.net.netd.aidl)
+rule android.net.netd.aidl.** com.android.connectivity.@0
+# Avoid including android.net.INetdEventCallback, used in tests but not part of the module
+rule android.net.INetd com.android.connectivity.@0
+rule android.net.INetd$* com.android.connectivity.@0
+rule android.net.INetdUnsolicitedEventListener* com.android.connectivity.@0
+rule android.net.InterfaceConfigurationParcel* com.android.connectivity.@0
+rule android.net.MarkMaskParcel* com.android.connectivity.@0
+rule android.net.NativeNetworkConfig* com.android.connectivity.@0
+rule android.net.NativeNetworkType* com.android.connectivity.@0
+rule android.net.NativeVpnType* com.android.connectivity.@0
+rule android.net.RouteInfoParcel* com.android.connectivity.@0
+rule android.net.TetherConfigParcel* com.android.connectivity.@0
+rule android.net.TetherOffloadRuleParcel* com.android.connectivity.@0
+rule android.net.TetherStatsParcel* com.android.connectivity.@0
+rule android.net.UidRangeParcel* com.android.connectivity.@0
+rule android.net.metrics.INetdEventListener* com.android.connectivity.@0
+
+# From netlink-client
+rule android.net.netlink.** com.android.connectivity.@0
+
+# From networkstack-client (newer AIDLs should go to android.net.[networkstack|ipmemorystore].aidl)
+rule android.net.networkstack.aidl.** com.android.connectivity.@0
+rule android.net.ipmemorystore.aidl.** com.android.connectivity.@0
+rule android.net.ipmemorystore.aidl.** com.android.connectivity.@0
+rule android.net.DataStallReportParcelable* com.android.connectivity.@0
+rule android.net.DhcpResultsParcelable* com.android.connectivity.@0
+rule android.net.IIpMemoryStore* com.android.connectivity.@0
+rule android.net.INetworkMonitor* com.android.connectivity.@0
+rule android.net.INetworkStackConnector* com.android.connectivity.@0
+rule android.net.INetworkStackStatusCallback* com.android.connectivity.@0
+rule android.net.InformationElementParcelable* com.android.connectivity.@0
+rule android.net.InitialConfigurationParcelable* com.android.connectivity.@0
+rule android.net.IpMemoryStore* com.android.connectivity.@0
+rule android.net.Layer2InformationParcelable* com.android.connectivity.@0
+rule android.net.Layer2PacketParcelable* com.android.connectivity.@0
+rule android.net.NattKeepalivePacketDataParcelable* com.android.connectivity.@0
+rule android.net.NetworkMonitorManager* com.android.connectivity.@0
+rule android.net.NetworkTestResultParcelable* com.android.connectivity.@0
+rule android.net.PrivateDnsConfigParcel* com.android.connectivity.@0
+rule android.net.ProvisioningConfigurationParcelable* com.android.connectivity.@0
+rule android.net.ScanResultInfoParcelable* com.android.connectivity.@0
+rule android.net.TcpKeepalivePacketDataParcelable* com.android.connectivity.@0
+rule android.net.dhcp.DhcpLeaseParcelable* com.android.connectivity.@0
+rule android.net.dhcp.DhcpServingParamsParcel* com.android.connectivity.@0
+rule android.net.dhcp.IDhcpEventCallbacks* com.android.connectivity.@0
+rule android.net.dhcp.IDhcpServer* com.android.connectivity.@0
+rule android.net.ip.IIpClient* com.android.connectivity.@0
+rule android.net.ip.IpClientCallbacks* com.android.connectivity.@0
+rule android.net.ip.IpClientManager* com.android.connectivity.@0
+rule android.net.ip.IpClientUtil* com.android.connectivity.@0
+rule android.net.ipmemorystore.** com.android.connectivity.@0
+rule android.net.networkstack.** com.android.connectivity.@0
+rule android.net.shared.** com.android.connectivity.@0
+rule android.net.util.KeepalivePacketDataUtil* com.android.connectivity.@0
+
+# From connectivity-module-utils
+rule android.net.util.InterfaceParams* com.android.connectivity.@0
+rule android.net.util.SharedLog* com.android.connectivity.@0
+rule android.net.shared.** com.android.connectivity.@0
+
+# From services-connectivity-shared-srcs
+rule android.net.util.NetworkConstants* com.android.connectivity.@0
+
+# Remaining are connectivity sources in com.android.server and com.android.server.connectivity:
+# TODO: move to a subpackage of com.android.connectivity (such as com.android.connectivity.server)
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 41b093e..770aa8a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -428,7 +428,7 @@
// PREFERENCE_PRIORITY_NONE when sending to netd.
static final int PREFERENCE_PRIORITY_DEFAULT = 1000;
// As a security feature, VPNs have the top priority.
- static final int PREFERENCE_PRIORITY_VPN = 1;
+ static final int PREFERENCE_PRIORITY_VPN = 0; // Netd supports only 0 for VPN.
// Priority of per-app OEM preference. See {@link #setOemNetworkPreference}.
@VisibleForTesting
static final int PREFERENCE_PRIORITY_OEM = 10;
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index 512d767..3b5a706 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -153,7 +153,7 @@
* Get device first sdk version.
*/
public int getDeviceFirstSdkInt() {
- return Build.VERSION.FIRST_SDK_INT;
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT;
}
/**
@@ -281,7 +281,14 @@
@VisibleForTesting
synchronized void updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids) {
mUidsAllowedOnRestrictedNetworks.clear();
- mUidsAllowedOnRestrictedNetworks.addAll(uids);
+ // This is necessary for the app id to match in isUidAllowedOnRestrictedNetworks, and will
+ // grant the permission to all uids associated with the app ID. This is safe even if the app
+ // is only installed on some users because the uid cannot match some other app – this uid is
+ // in effect not installed and can't be run.
+ // TODO (b/192431153): Change appIds back to uids.
+ for (int uid : uids) {
+ mUidsAllowedOnRestrictedNetworks.add(UserHandle.getAppId(uid));
+ }
}
@VisibleForTesting
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index a30d4f1..493a201 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -42,6 +42,7 @@
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_USB;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
@@ -973,6 +974,11 @@
assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps());
}
+ private int getMaxTransport() {
+ if (!isAtLeastS() && MAX_TRANSPORT == TRANSPORT_USB) return MAX_TRANSPORT - 1;
+ return MAX_TRANSPORT;
+ }
+
@Test
public void testSignalStrength() {
final NetworkCapabilities nc = new NetworkCapabilities();
@@ -984,7 +990,7 @@
}
private void assertNoTransport(NetworkCapabilities nc) {
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
+ for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
assertFalse(nc.hasTransport(i));
}
}
@@ -1001,7 +1007,7 @@
assertFalse(nc.hasTransport(i));
}
}
- for (int i = MAX_TRANSPORT; i > maxTransportType; i--) {
+ for (int i = getMaxTransport(); i > maxTransportType; i--) {
if (positiveSequence) {
assertFalse(nc.hasTransport(i));
} else {
@@ -1015,12 +1021,12 @@
final NetworkCapabilities nc = new NetworkCapabilities();
assertNoTransport(nc);
// Test adding multiple transport types.
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
+ for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
nc.addTransportType(i);
checkCurrentTransportTypes(nc, i, true /* positiveSequence */);
}
// Test removing multiple transport types.
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
+ for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
nc.removeTransportType(i);
checkCurrentTransportTypes(nc, i, false /* positiveSequence */);
}
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index 86642ea..f9427f8 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -38,6 +38,7 @@
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
+import androidx.test.filters.SdkSuppress;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
@@ -58,6 +59,7 @@
* Test for BatteryStatsManager.
*/
@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // BatteryStatsManager did not exist on Q
public class BatteryStatsManagerTest{
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index a2ad645..0738966 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -159,6 +159,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
+import com.android.modules.utils.build.SdkLevel;
import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
import com.android.networkstack.apishim.ConstantsShim;
import com.android.networkstack.apishim.NetworkInformationShimImpl;
@@ -1698,7 +1699,10 @@
return;
}
- final int firstSdk = Build.VERSION.FIRST_SDK_INT;
+ final int firstSdk = SdkLevel.isAtLeastS()
+ ? Build.VERSION.DEVICE_INITIAL_SDK_INT
+ // FIRST_SDK_INT was a @TestApi field renamed to DEVICE_INITIAL_SDK_INT in S
+ : Build.VERSION.class.getField("FIRST_SDK_INT").getInt(null);
if (firstSdk < Build.VERSION_CODES.Q) {
Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching"
+ " before Q: " + firstSdk);
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 7959c3c..fd0cd18 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -54,6 +54,7 @@
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
+import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.SystemClock;
import android.system.Os;
@@ -290,6 +291,9 @@
Log.w(TAG, "connect failed with " + error + "; waiting before retry");
SystemClock.sleep(WIFI_CONNECT_INTERVAL_MS);
}
+
+ fail("Failed to connect to " + config.SSID
+ + " after " + MAX_WIFI_CONNECT_RETRIES + "retries");
}
private static class ConnectWifiListener implements WifiManager.ActionListener {
@@ -722,16 +726,28 @@
* {@code onAvailable}.
*/
public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
- private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
+ private final ConditionVariable mAvailableCv = new ConditionVariable(false);
private final CountDownLatch mLostLatch = new CountDownLatch(1);
private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
public Network currentNetwork;
public Network lastLostNetwork;
+ /**
+ * Wait for a network to be available.
+ *
+ * If onAvailable was previously called but was followed by onLost, this will wait for the
+ * next available network.
+ */
public Network waitForAvailable() throws InterruptedException {
- return mAvailableLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
- ? currentNetwork : null;
+ final long timeoutMs = TimeUnit.SECONDS.toMillis(CONNECTIVITY_CHANGE_TIMEOUT_SECS);
+ while (mAvailableCv.block(timeoutMs)) {
+ final Network n = currentNetwork;
+ if (n != null) return n;
+ Log.w(TAG, "onAvailable called but network was lost before it could be returned."
+ + " Waiting for the next call to onAvailable.");
+ }
+ return null;
}
public Network waitForLost() throws InterruptedException {
@@ -743,17 +759,17 @@
return mUnavailableLatch.await(2, TimeUnit.SECONDS);
}
-
@Override
public void onAvailable(Network network) {
currentNetwork = network;
- mAvailableLatch.countDown();
+ mAvailableCv.open();
}
@Override
public void onLost(Network network) {
lastLostNetwork = network;
if (network.equals(currentNetwork)) {
+ mAvailableCv.close();
currentNetwork = null;
}
mLostLatch.countDown();
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp
index 5fe478f..7c42811 100644
--- a/tests/integration/Android.bp
+++ b/tests/integration/Android.bp
@@ -37,7 +37,7 @@
"kotlin-reflect",
"mockito-target-extended-minus-junit4",
"net-tests-utils",
- "service-connectivity",
+ "service-connectivity-pre-jarjar",
"services.core",
"services.net",
"testables",
@@ -52,6 +52,7 @@
"libnativehelper_compat_libc++",
"libnetworkstackutilsjni",
],
+ jarjar_rules: ":connectivity-jarjar-rules",
}
// Utilities for testing framework code both in integration and unit tests.
diff --git a/tests/unit/java/android/net/IpSecAlgorithmTest.java b/tests/unit/java/android/net/IpSecAlgorithmTest.java
index cac8c2d..c2a759b 100644
--- a/tests/unit/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/unit/java/android/net/IpSecAlgorithmTest.java
@@ -123,7 +123,7 @@
@Test
public void testValidationForAlgosAddedInS() throws Exception {
- if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.R) {
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
return;
}
@@ -196,13 +196,13 @@
private static Set<String> getMandatoryAlgos() {
return CollectionUtils.filter(
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
- i -> Build.VERSION.FIRST_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+ i -> Build.VERSION.DEVICE_INITIAL_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
}
private static Set<String> getOptionalAlgos() {
return CollectionUtils.filter(
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
- i -> Build.VERSION.FIRST_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+ i -> Build.VERSION.DEVICE_INITIAL_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
}
@Test
diff --git a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
index ed4f61d..8498b6f 100644
--- a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
@@ -168,8 +168,8 @@
assertEquals(resultData.tos, tos);
assertEquals(resultData.ttl, ttl);
- final String expected = ""
- + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
+ final String expected = TcpKeepalivePacketDataParcelable.class.getName()
+ + "{srcAddress: [10, 0, 0, 1],"
+ " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
+ " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
assertEquals(expected, resultData.toString());
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index e28f3c4..4961024 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -1529,7 +1529,7 @@
}
private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
- when(mDeps.getCallingUid()).thenReturn(uid);
+ doReturn(uid).when(mDeps).getCallingUid();
try {
return what.get();
} finally {
@@ -9860,9 +9860,9 @@
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
final UnderlyingNetworkInfo underlyingNetworkInfo =
- new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+ new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<>());
mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
- when(mDeps.getConnectionOwnerUid(anyInt(), any(), any())).thenReturn(42);
+ doReturn(42).when(mDeps).getConnectionOwnerUid(anyInt(), any(), any());
}
private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -10254,13 +10254,13 @@
}
private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) {
- TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo();
+ TestTransportInfo ti = getTestTransportInfo(nc);
return nc.getUids() == null
&& nc.getAdministratorUids().length == 0
&& nc.getOwnerUid() == Process.INVALID_UID
- && getTestTransportInfo(nc).locationRedacted
- && getTestTransportInfo(nc).localMacAddressRedacted
- && getTestTransportInfo(nc).settingsRedacted;
+ && ti.locationRedacted
+ && ti.localMacAddressRedacted
+ && ti.settingsRedacted;
}
@Test