Merge "Cleanup the public API getActiveNetworkForUid on AOSP"
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/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 69471a1..5584db2 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -49,7 +49,6 @@
import com.android.internal.util.StateMachine;
import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
import com.android.networkstack.apishim.common.ConnectivityManagerShim;
-import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
import java.util.HashMap;
import java.util.HashSet;
@@ -162,12 +161,7 @@
}
ConnectivityManagerShim mCmShim = ConnectivityManagerShimImpl.newInstance(mContext);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
- try {
- mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
- } catch (UnsupportedApiLevelException e) {
- Log.wtf(TAG, "registerSystemDefaultNetworkCallback is not supported");
- return;
- }
+ mCmShim.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
if (mEntitlementMgr == null) {
mEntitlementMgr = entitle;
}
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/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 5caa11b..2cd0220 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1,17 +1,89 @@
-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
+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.** 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
+rule android.net.INetd* 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/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index a30d4f1..9537786 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -49,6 +49,7 @@
import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.net.module.util.NetworkCapabilitiesUtils.TRANSPORT_USB;
import static com.android.testutils.MiscAsserts.assertEmpty;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
@@ -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/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/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index f59d0d2..e28f3c4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -176,6 +176,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static java.util.Arrays.asList;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -309,7 +311,6 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -1603,9 +1604,8 @@
MockitoAnnotations.initMocks(this);
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
+ when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO));
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(asList(PRIMARY_USER_HANDLE));
when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
// canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
// it was started from, i.e., PRIMARY_USER.
@@ -1813,7 +1813,7 @@
eq(UserHandle.getCallingUserId()))).thenReturn(myPackageInfo);
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
+ asList(new PackageInfo[] {
buildPackageInfo(/* SYSTEM */ false, APP1_UID),
buildPackageInfo(/* SYSTEM */ false, APP2_UID),
buildPackageInfo(/* SYSTEM */ false, VPN_UID)
@@ -1830,7 +1830,7 @@
ResolveInfo rInfo = new ResolveInfo();
rInfo.serviceInfo = new ServiceInfo();
rInfo.serviceInfo.metaData = new Bundle();
- final List<ResolveInfo> services = Arrays.asList(new ResolveInfo[]{rInfo});
+ final List<ResolveInfo> services = asList(new ResolveInfo[]{rInfo});
when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
eq(userId))).thenReturn(services);
when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
@@ -4847,8 +4847,8 @@
final ContentResolver cr = mServiceContext.getContentResolver();
final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
- for (int config : Arrays.asList(0, 3, 2)) {
- for (String setting: Arrays.asList(null, "0", "2", "1")) {
+ for (int config : asList(0, 3, 2)) {
+ for (String setting: asList(null, "0", "2", "1")) {
mPolicyTracker.mConfigMeteredMultipathPreference = config;
Settings.Global.putString(cr, settingName, setting);
mPolicyTracker.reevaluate();
@@ -6007,10 +6007,10 @@
networkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, networkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
- Arrays.asList(myIpv4DefaultRoute));
+ checkDirectlyConnectedRoutes(cbi.getLp(), asList(myIpv4Address),
+ asList(myIpv4DefaultRoute));
checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
- Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
+ asList(myIpv4Address), asList(myIpv4DefaultRoute));
// Verify direct routes are added during subsequent link properties updates.
LinkProperties newLp = new LinkProperties(lp);
@@ -6022,8 +6022,8 @@
cbi = networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent);
networkCallback.assertNoCallback();
checkDirectlyConnectedRoutes(cbi.getLp(),
- Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
- Arrays.asList(myIpv4DefaultRoute));
+ asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
+ asList(myIpv4DefaultRoute));
mCm.unregisterNetworkCallback(networkCallback);
}
@@ -6351,9 +6351,9 @@
mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
+ assertTrue(CollectionUtils.contains(resolvrParams.servers, "2001:db8::1"));
// Opportunistic mode.
- assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
+ assertTrue(CollectionUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
reset(mMockDnsResolver);
cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
@@ -6363,12 +6363,12 @@
mResolverParamsParcelCaptor.capture());
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
// Opportunistic mode.
assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
reset(mMockDnsResolver);
final String TLS_SPECIFIER = "tls.example.com";
@@ -6383,8 +6383,8 @@
mResolverParamsParcelCaptor.capture());
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
reset(mMockDnsResolver);
}
@@ -6491,12 +6491,12 @@
mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
+ assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
// Opportunistic mode.
assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
+ assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
reset(mMockDnsResolver);
cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
@@ -6513,8 +6513,8 @@
mResolverParamsParcelCaptor.capture());
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
+ assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
@@ -6523,11 +6523,11 @@
mResolverParamsParcelCaptor.capture());
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
+ assertTrue(new ArraySet<>(resolvrParams.servers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
+ assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
+ asList("2001:db8::1", "192.0.2.1")));
reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
@@ -7563,7 +7563,7 @@
// Start the restricted profile, and check that the UID within it loses network access.
when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
.thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+ when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO,
RESTRICTED_USER_INFO));
// TODO: check that VPN app within restricted profile still has access, etc.
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
@@ -7574,7 +7574,7 @@
assertNull(mCm.getActiveNetworkForUid(restrictedUid));
// Stop the restricted profile, and check that the UID within it has network access again.
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+ when(mUserManager.getAliveUsers()).thenReturn(asList(PRIMARY_USER_INFO));
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
@@ -7999,7 +7999,7 @@
// networks, ConnectivityService does not guarantee the order in which callbacks are fired.
private void assertBlockedCallbackInAnyOrder(TestNetworkCallback callback, boolean blocked,
TestNetworkAgentWrapper... agents) {
- final List<Network> expectedNetworks = Arrays.asList(agents).stream()
+ final List<Network> expectedNetworks = asList(agents).stream()
.map((agent) -> agent.getNetwork())
.collect(Collectors.toList());
@@ -8695,7 +8695,7 @@
mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
+ assertTrue(CollectionUtils.contains(resolvrParams.servers, "8.8.8.8"));
for (final LinkProperties stackedLp : stackedLpsAfterChange) {
verify(mDeps).reportNetworkInterfaceForTransports(
@@ -9368,7 +9368,7 @@
InOrder inOrder = inOrder(mMockNetd);
// Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
+ final Set<UidRange> newRanges = new HashSet<>(asList(
new UidRange(vpnRange.start, APP1_UID - 1),
new UidRange(APP1_UID + 1, vpnRange.stop)));
mMockVpn.setUids(newRanges);
@@ -10510,7 +10510,7 @@
verify(mProxyTracker, never()).sendProxyBroadcast();
// Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
+ final Set<UidRange> newRanges = new HashSet<>(asList(
new UidRange(vpnRange.start, APP1_UID - 1),
new UidRange(APP1_UID + 1, vpnRange.stop)));
mMockVpn.setUids(newRanges);
@@ -11111,7 +11111,7 @@
final int secondUserTestPackageUid = UserHandle.getUid(SECONDARY_USER, TEST_PACKAGE_UID);
final int thirdUserTestPackageUid = UserHandle.getUid(TERTIARY_USER, TEST_PACKAGE_UID);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
+ asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
// Arrange PackageManager mocks testing for users who have and don't have a package.
mockGetApplicationInfoThrowsNameNotFound(TEST_PACKAGE_NAME, PRIMARY_USER_HANDLE);
@@ -12058,7 +12058,7 @@
final int secondUser = 10;
final UserHandle secondUserHandle = new UserHandle(secondUser);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+ asList(PRIMARY_USER_HANDLE, secondUserHandle));
// Arrange PackageManager mocks
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
@@ -12099,7 +12099,7 @@
final int secondUser = 10;
final UserHandle secondUserHandle = new UserHandle(secondUser);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
+ asList(PRIMARY_USER_HANDLE));
// Arrange PackageManager mocks
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
@@ -12127,7 +12127,7 @@
// Send a broadcast indicating a user was added.
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+ asList(PRIMARY_USER_HANDLE, secondUserHandle));
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
processBroadcast(addedIntent);
@@ -12140,7 +12140,7 @@
// Send a broadcast indicating a user was removed.
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
+ asList(PRIMARY_USER_HANDLE));
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
processBroadcast(removedIntent);