Merge "Add TrunkStable.bp" into udc-mainline-prod
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d33453c..fafd3bb 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,7 +1,12 @@
{
"presubmit": [
{
- "name": "ConnectivityCoverageTests"
+ "name": "ConnectivityCoverageTests",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
+ }
+ ]
},
{
// In addition to ConnectivityCoverageTests, runs non-connectivity-module tests
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index e917464..4d92512 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -96,6 +96,7 @@
},
binaries: [
"clatd",
+ "netbpfload",
"ot-daemon",
],
canned_fs_config: "canned_fs_config",
diff --git a/Tethering/apex/canned_fs_config b/Tethering/apex/canned_fs_config
index 5a03347..1f5fcfa 100644
--- a/Tethering/apex/canned_fs_config
+++ b/Tethering/apex/canned_fs_config
@@ -1,2 +1,3 @@
/bin/for-system 0 1000 0750
/bin/for-system/clatd 1029 1029 06755
+/bin/netbpfload 0 0 0750
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 a280046..4d1e7ef 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
@@ -167,7 +167,6 @@
@Override
public boolean addIpv6UpstreamRule(@NonNull final Ipv6UpstreamRule rule) {
- if (!isInitialized()) return false;
// RFC7421_PREFIX_LENGTH = 64 which is the most commonly used IPv6 subnet prefix length.
if (rule.sourcePrefix.getPrefixLength() != RFC7421_PREFIX_LENGTH) return false;
@@ -185,7 +184,6 @@
@Override
public boolean removeIpv6UpstreamRule(@NonNull final Ipv6UpstreamRule rule) {
- if (!isInitialized()) return false;
// RFC7421_PREFIX_LENGTH = 64 which is the most commonly used IPv6 subnet prefix length.
if (rule.sourcePrefix.getPrefixLength() != RFC7421_PREFIX_LENGTH) return false;
@@ -200,8 +198,6 @@
@Override
public boolean addIpv6DownstreamRule(@NonNull final Ipv6DownstreamRule rule) {
- if (!isInitialized()) return false;
-
final TetherDownstream6Key key = rule.makeTetherDownstream6Key();
final Tether6Value value = rule.makeTether6Value();
@@ -217,8 +213,6 @@
@Override
public boolean removeIpv6DownstreamRule(@NonNull final Ipv6DownstreamRule rule) {
- if (!isInitialized()) return false;
-
try {
mBpfDownstream6Map.deleteEntry(rule.makeTetherDownstream6Key());
} catch (ErrnoException e) {
@@ -234,8 +228,6 @@
@Override
@Nullable
public SparseArray<TetherStatsValue> tetherOffloadGetStats() {
- if (!isInitialized()) return null;
-
final SparseArray<TetherStatsValue> tetherStatsList = new SparseArray<TetherStatsValue>();
try {
// The reported tether stats are total data usage for all currently-active upstream
@@ -250,8 +242,6 @@
@Override
public boolean tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes) {
- if (!isInitialized()) return false;
-
// The common case is an update, where the stats already exist,
// hence we read first, even though writing with BPF_NOEXIST
// first would make the code simpler.
@@ -307,8 +297,6 @@
@Override
@Nullable
public TetherStatsValue tetherOffloadGetAndClearStats(int ifIndex) {
- if (!isInitialized()) return null;
-
// getAndClearTetherOffloadStats is called after all offload rules have already been
// deleted for the given upstream interface. Before starting to do cleanup stuff in this
// function, use synchronizeKernelRCU to make sure that all the current running eBPF
@@ -354,8 +342,6 @@
@Override
public boolean tetherOffloadRuleAdd(boolean downstream, @NonNull Tether4Key key,
@NonNull Tether4Value value) {
- if (!isInitialized()) return false;
-
try {
if (downstream) {
mBpfDownstream4Map.insertEntry(key, value);
@@ -379,8 +365,6 @@
@Override
public boolean tetherOffloadRuleRemove(boolean downstream, @NonNull Tether4Key key) {
- if (!isInitialized()) return false;
-
try {
if (downstream) {
if (!mBpfDownstream4Map.deleteEntry(key)) return false; // Rule did not exist
@@ -413,8 +397,6 @@
@Override
public void tetherOffloadRuleForEach(boolean downstream,
@NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action) {
- if (!isInitialized()) return;
-
try {
if (downstream) {
mBpfDownstream4Map.forEach(action);
@@ -428,8 +410,6 @@
@Override
public boolean attachProgram(String iface, boolean downstream, boolean ipv4) {
- if (!isInitialized()) return false;
-
try {
BpfUtils.attachProgram(iface, downstream, ipv4);
} catch (IOException e) {
@@ -441,8 +421,6 @@
@Override
public boolean detachProgram(String iface, boolean ipv4) {
- if (!isInitialized()) return false;
-
try {
BpfUtils.detachProgram(iface, ipv4);
} catch (IOException e) {
@@ -460,8 +438,6 @@
@Override
public boolean addDevMap(int ifIndex) {
- if (!isInitialized()) return false;
-
try {
mBpfDevMap.updateEntry(new TetherDevKey(ifIndex), new TetherDevValue(ifIndex));
} catch (ErrnoException e) {
@@ -473,8 +449,6 @@
@Override
public boolean removeDevMap(int ifIndex) {
- if (!isInitialized()) return false;
-
try {
mBpfDevMap.deleteEntry(new TetherDevKey(ifIndex));
} catch (ErrnoException e) {
diff --git a/Tethering/res/values-ky/strings.xml b/Tethering/res/values-ky/strings.xml
index 35e6453..4696a72 100644
--- a/Tethering/res/values-ky/strings.xml
+++ b/Tethering/res/values-ky/strings.xml
@@ -20,7 +20,7 @@
<string name="tethered_notification_message" msgid="2338023450330652098">"Тууралоо үчүн басыңыз."</string>
<string name="disable_tether_notification_title" msgid="3183576627492925522">"Модем режими өчүк"</string>
<string name="disable_tether_notification_message" msgid="6655882039707534929">"Кеңири маалымат үчүн администраторуңузга кайрылыңыз"</string>
- <string name="notification_channel_tethering_status" msgid="7030733422705019001">"Хотспот жана байланыш түйүнүүн статусу"</string>
+ <string name="notification_channel_tethering_status" msgid="7030733422705019001">"Байланыш түйүнү жана байланыш түйүнүүн статусу"</string>
<string name="no_upstream_notification_title" msgid="2052743091868702475"></string>
<string name="no_upstream_notification_message" msgid="6932020551635470134"></string>
<string name="no_upstream_notification_disable_button" msgid="8836277213343697023"></string>
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index a851410..e030902 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -127,6 +127,7 @@
// TODO: have this configurable
private static final int DHCP_LEASE_TIME_SECS = 3600;
+ private static final int NO_UPSTREAM = 0;
private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString("00:00:00:00:00:00");
private static final String TAG = "IpServer";
@@ -259,6 +260,12 @@
private int mLastError;
private int mServingMode;
private InterfaceSet mUpstreamIfaceSet; // may change over time
+ // mInterfaceParams can't be final now because IpServer will be created when receives
+ // WIFI_AP_STATE_CHANGED broadcasts or when it detects that the wifi interface has come up.
+ // In the latter case, the interface is not fully initialized and the MAC address might not
+ // be correct (it will be set with a randomized MAC address later).
+ // TODO: Consider create the IpServer only when tethering want to enable it, then we can
+ // make mInterfaceParams final.
private InterfaceParams mInterfaceParams;
// TODO: De-duplicate this with mLinkProperties above. Currently, these link
// properties are those selected by the IPv6TetheringCoordinator and relayed
@@ -740,7 +747,7 @@
RaParams params = null;
String upstreamIface = null;
InterfaceParams upstreamIfaceParams = null;
- int upstreamIfIndex = 0;
+ int upstreamIfIndex = NO_UPSTREAM;
if (v6only != null) {
upstreamIface = v6only.getInterfaceName();
@@ -772,7 +779,7 @@
// CMD_TETHER_CONNECTION_CHANGED. Adding the mapping update here to the avoid potential
// timing issue. It prevents that the IPv6 capability is updated later than
// CMD_TETHER_CONNECTION_CHANGED.
- mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
+ mBpfCoordinator.maybeAddUpstreamToLookupTable(upstreamIfIndex, upstreamIface);
// If v6only is null, we pass in null to setRaParams(), which handles
// deprecation of any existing RA data.
@@ -780,8 +787,7 @@
// Not support BPF on virtual upstream interface
final boolean upstreamSupportsBpf = upstreamIface != null && !isVcnInterface(upstreamIface);
- updateIpv6ForwardingRules(
- mLastIPv6UpstreamIfindex, upstreamIfIndex, upstreamSupportsBpf, null);
+ updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, upstreamSupportsBpf);
mLastIPv6LinkProperties = v6only;
mLastIPv6UpstreamIfindex = upstreamIfIndex;
mUpstreamSupportsBpf = upstreamSupportsBpf;
@@ -887,25 +893,23 @@
}
}
- // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
- // changes or if a neighbor event is received.
+ private int getInterfaceIndexForRule(int ifindex, boolean supportsBpf) {
+ return supportsBpf ? ifindex : NO_UPSTREAM;
+ }
+
+ // Handles updates to IPv6 forwarding rules if the upstream changes.
private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
- boolean upstreamSupportsBpf, NeighborEvent e) {
- // If no longer have an upstream or upstream not supports BPF, clear forwarding rules and do
- // nothing else.
- // TODO: Rather than always clear rules, ensure whether ipv6 ever enable first.
- if (upstreamIfindex == 0 || !upstreamSupportsBpf) {
- mBpfCoordinator.tetherOffloadRuleClear(this);
- return;
- }
-
+ boolean upstreamSupportsBpf) {
// If the upstream interface has changed, remove all rules and re-add them with the new
- // upstream interface.
+ // upstream interface. If upstream is a virtual network, treated as no upstream.
if (prevUpstreamIfindex != upstreamIfindex) {
- mBpfCoordinator.tetherOffloadRuleUpdate(this, upstreamIfindex);
+ mBpfCoordinator.updateAllIpv6Rules(this, this.mInterfaceParams,
+ getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf));
}
+ }
- // If we're here to process a NeighborEvent, do so now.
+ // Handles updates to IPv6 downstream rules if a neighbor event is received.
+ private void addOrRemoveIpv6Downstream(NeighborEvent e) {
// mInterfaceParams must be non-null or the event would not have arrived.
if (e == null) return;
if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress()
@@ -917,8 +921,9 @@
// Do this here instead of in the Ipv6DownstreamRule constructor to ensure that we
// never add rules with a null MAC, only delete them.
MacAddress dstMac = e.isValid() ? e.macAddr : NULL_MAC_ADDRESS;
- Ipv6DownstreamRule rule = new Ipv6DownstreamRule(upstreamIfindex, mInterfaceParams.index,
- (Inet6Address) e.ip, mInterfaceParams.macAddr, dstMac);
+ Ipv6DownstreamRule rule = new Ipv6DownstreamRule(
+ getInterfaceIndexForRule(mLastIPv6UpstreamIfindex, mUpstreamSupportsBpf),
+ mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, dstMac);
if (e.isValid()) {
mBpfCoordinator.addIpv6DownstreamRule(this, rule);
} else {
@@ -951,8 +956,7 @@
if (mInterfaceParams != null
&& mInterfaceParams.index == e.ifindex
&& mInterfaceParams.hasMacAddress) {
- updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, mLastIPv6UpstreamIfindex,
- mUpstreamSupportsBpf, e);
+ addOrRemoveIpv6Downstream(e);
updateClientInfoIpv4(e);
}
}
@@ -1285,6 +1289,7 @@
@Override
public void exit() {
cleanupUpstream();
+ mBpfCoordinator.clearAllIpv6Rules(IpServer.this);
super.exit();
}
@@ -1303,7 +1308,8 @@
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
mUpstreamIfaceSet = null;
- mBpfCoordinator.tetherOffloadRuleClear(IpServer.this);
+ mBpfCoordinator.updateAllIpv6Rules(
+ IpServer.this, IpServer.this.mInterfaceParams, NO_UPSTREAM);
}
private void cleanupUpstreamInterface(String upstreamIface) {
@@ -1370,7 +1376,7 @@
final InterfaceParams upstreamIfaceParams =
mDeps.getInterfaceParams(ifname);
if (upstreamIfaceParams != null) {
- mBpfCoordinator.addUpstreamNameToLookupTable(
+ mBpfCoordinator.maybeAddUpstreamToLookupTable(
upstreamIfaceParams.index, ifname);
}
}
@@ -1430,6 +1436,8 @@
class UnavailableState extends State {
@Override
public void enter() {
+ // TODO: move mIpNeighborMonitor.stop() to TetheredState#exit, and trigger a neighbours
+ // dump after starting mIpNeighborMonitor.
mIpNeighborMonitor.stop();
mLastError = TETHER_ERROR_NO_ERROR;
sendInterfaceState(STATE_UNAVAILABLE);
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 1b23a6c..46c815f 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -50,6 +50,7 @@
import android.system.ErrnoException;
import android.system.OsConstants;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -153,6 +154,7 @@
static final int NF_CONNTRACK_UDP_TIMEOUT_STREAM = 180;
@VisibleForTesting
static final int INVALID_MTU = 0;
+ static final int NO_UPSTREAM = 0;
// List of TCP port numbers which aren't offloaded because the packets require the netfilter
// conntrack helper. See also TetherController::setForwardRules in netd.
@@ -221,6 +223,23 @@
// TODO: Remove the unused interface name.
private final SparseArray<String> mInterfaceNames = new SparseArray<>();
+ // How IPv6 upstream rules and downstream rules are managed in BpfCoordinator:
+ // 1. Each upstream rule represents a downstream interface to an upstream interface forwarding.
+ // No upstream rule will be exist if there is no upstream interface.
+ // Note that there is at most one upstream interface for a given downstream interface.
+ // 2. Each downstream rule represents an IPv6 neighbor, regardless of the existence of the
+ // upstream interface. If the upstream is not present, the downstream rules have an upstream
+ // interface index of NO_UPSTREAM, only exist in BpfCoordinator and won't be written to the
+ // BPF map. When the upstream comes back, those downstream rules will be updated by calling
+ // Ipv6DownstreamRule#onNewUpstream and written to the BPF map again. We don't remove the
+ // downstream rules when upstream is lost is because the upstream may come back with the
+ // same prefix and we won't receive any neighbor update event in this case.
+ // TODO: Remove downstream rules when upstream is lost and dump neighbors table when upstream
+ // interface comes back in order to reconstruct the downstream rules.
+ // 3. It is the same thing for BpfCoordinator if there is no upstream interface or the upstream
+ // interface is a virtual interface (which currently not supports BPF). In this case,
+ // IpServer will update its upstream ifindex to NO_UPSTREAM to the BpfCoordinator.
+
// Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a
// given downstream. Each map:
// - Is owned by the IpServer that is responsible for that downstream.
@@ -240,6 +259,16 @@
private final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6DownstreamRule>>
mIpv6DownstreamRules = new LinkedHashMap<>();
+ // Map of IPv6 upstream rules maps. Each of these maps represents the IPv6 upstream rules for a
+ // given downstream. Each map:
+ // - Is owned by the IpServer that is responsible for that downstream.
+ // - Must only be modified by that IpServer.
+ // - Is created when the IpServer adds its first upstream rule, and deleted when the IpServer
+ // deletes its last upstream rule (or clears its upstream rules)
+ // - Each upstream rule in the ArraySet is corresponding to an upstream interface.
+ private final ArrayMap<IpServer, ArraySet<Ipv6UpstreamRule>>
+ mIpv6UpstreamRules = new ArrayMap<>();
+
// Map of downstream client maps. Each of these maps represents the IPv4 clients for a given
// downstream. Needed to build IPv4 forwarding rules when conntrack events are received.
// Each map:
@@ -603,130 +632,173 @@
}
/**
- * Add IPv6 downstream rule. After adding the first rule on a given upstream, must add the data
- * limit on the given upstream.
- * Note that this can be only called on handler thread.
+ * Add IPv6 upstream rule. After adding the first rule on a given upstream, must add the
+ * data limit on the given upstream.
*/
- public void addIpv6DownstreamRule(
- @NonNull final IpServer ipServer, @NonNull final Ipv6DownstreamRule rule) {
+ private void addIpv6UpstreamRule(
+ @NonNull final IpServer ipServer, @NonNull final Ipv6UpstreamRule rule) {
if (!isUsingBpf()) return;
- // TODO: Perhaps avoid to add a duplicate rule.
- if (!mBpfCoordinatorShim.addIpv6DownstreamRule(rule)) return;
-
- if (!mIpv6DownstreamRules.containsKey(ipServer)) {
- mIpv6DownstreamRules.put(ipServer, new LinkedHashMap<Inet6Address,
- Ipv6DownstreamRule>());
- }
- LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules = mIpv6DownstreamRules.get(ipServer);
-
// Add upstream and downstream interface index to dev map.
maybeAddDevMap(rule.upstreamIfindex, rule.downstreamIfindex);
// When the first rule is added to an upstream, setup upstream forwarding and data limit.
maybeSetLimit(rule.upstreamIfindex);
- if (!isAnyRuleFromDownstreamToUpstream(rule.downstreamIfindex, rule.upstreamIfindex)) {
- // TODO: support upstream forwarding on non-point-to-point interfaces.
- // TODO: get the MTU from LinkProperties and update the rules when it changes.
- Ipv6UpstreamRule upstreamRule = new Ipv6UpstreamRule(rule.upstreamIfindex,
- rule.downstreamIfindex, IPV6_ZERO_PREFIX64, rule.srcMac, NULL_MAC_ADDRESS,
- NULL_MAC_ADDRESS);
- if (!mBpfCoordinatorShim.addIpv6UpstreamRule(upstreamRule)) {
- mLog.e("Failed to add upstream IPv6 forwarding rule: " + upstreamRule);
- }
+ // TODO: support upstream forwarding on non-point-to-point interfaces.
+ // TODO: get the MTU from LinkProperties and update the rules when it changes.
+ if (!mBpfCoordinatorShim.addIpv6UpstreamRule(rule)) {
+ return;
}
- // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to
- // check if it is about adding a first rule for a given upstream.
+ ArraySet<Ipv6UpstreamRule> rules = mIpv6UpstreamRules.computeIfAbsent(
+ ipServer, k -> new ArraySet<Ipv6UpstreamRule>());
+ rules.add(rule);
+ }
+
+ /**
+ * Clear all IPv6 upstream rules for a given downstream. After removing the last rule on a given
+ * upstream, must clear data limit, update the last tether stats and remove the tether stats in
+ * the BPF maps.
+ */
+ private void clearIpv6UpstreamRules(@NonNull final IpServer ipServer) {
+ if (!isUsingBpf()) return;
+
+ final ArraySet<Ipv6UpstreamRule> upstreamRules = mIpv6UpstreamRules.remove(ipServer);
+ if (upstreamRules == null) return;
+
+ int upstreamIfindex = 0;
+ for (Ipv6UpstreamRule rule: upstreamRules) {
+ if (upstreamIfindex != 0 && rule.upstreamIfindex != upstreamIfindex) {
+ Log.wtf(TAG, "BUG: upstream rules point to more than one interface");
+ }
+ upstreamIfindex = rule.upstreamIfindex;
+ mBpfCoordinatorShim.removeIpv6UpstreamRule(rule);
+ }
+ // Clear the limit if there are no more rules on the given upstream.
+ // Using upstreamIfindex outside the loop is fine because all the rules for a given IpServer
+ // will always have the same upstream index (since they are always added all together by
+ // updateAllIpv6Rules).
+ // The upstreamIfindex can't be 0 because we won't add an Ipv6UpstreamRule with
+ // upstreamIfindex == 0 and if there is no Ipv6UpstreamRule for an IpServer, it will be
+ // removed from mIpv6UpstreamRules.
+ if (upstreamIfindex == 0) {
+ Log.wtf(TAG, "BUG: upstream rules have empty Set or rule.upstreamIfindex == 0");
+ return;
+ }
+ maybeClearLimit(upstreamIfindex);
+ }
+
+ /**
+ * Add IPv6 downstream rule.
+ * Note that this can be only called on handler thread.
+ */
+ public void addIpv6DownstreamRule(
+ @NonNull final IpServer ipServer, @NonNull final Ipv6DownstreamRule rule) {
+ if (!isUsingBpf()) return;
+
+ // TODO: Perhaps avoid to add a duplicate rule.
+ if (rule.upstreamIfindex != NO_UPSTREAM
+ && !mBpfCoordinatorShim.addIpv6DownstreamRule(rule)) return;
+
+ LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules =
+ mIpv6DownstreamRules.computeIfAbsent(ipServer,
+ k -> new LinkedHashMap<Inet6Address, Ipv6DownstreamRule>());
rules.put(rule.address, rule);
}
/**
- * Remove IPv6 downstream rule. After removing the last rule on a given upstream, must clear
- * data limit, update the last tether stats and remove the tether stats in the BPF maps.
+ * Remove IPv6 downstream rule.
* Note that this can be only called on handler thread.
*/
public void removeIpv6DownstreamRule(
@NonNull final IpServer ipServer, @NonNull final Ipv6DownstreamRule rule) {
if (!isUsingBpf()) return;
- if (!mBpfCoordinatorShim.removeIpv6DownstreamRule(rule)) return;
+ if (rule.upstreamIfindex != NO_UPSTREAM
+ && !mBpfCoordinatorShim.removeIpv6DownstreamRule(rule)) return;
LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules = mIpv6DownstreamRules.get(ipServer);
if (rules == null) return;
- // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if
- // the last rule is removed for a given upstream. If no rule is removed, return early.
- // Avoid unnecessary work on a non-existent rule which may have never been added or
- // removed already.
+ // If no rule is removed, return early. Avoid unnecessary work on a non-existent rule which
+ // may have never been added or removed already.
if (rules.remove(rule.address) == null) return;
// Remove the downstream entry if it has no more rule.
if (rules.isEmpty()) {
mIpv6DownstreamRules.remove(ipServer);
}
+ }
- // If no more rules between this upstream and downstream, stop upstream forwarding.
- if (!isAnyRuleFromDownstreamToUpstream(rule.downstreamIfindex, rule.upstreamIfindex)) {
- Ipv6UpstreamRule upstreamRule = new Ipv6UpstreamRule(rule.upstreamIfindex,
- rule.downstreamIfindex, IPV6_ZERO_PREFIX64, rule.srcMac, NULL_MAC_ADDRESS,
- NULL_MAC_ADDRESS);
- if (!mBpfCoordinatorShim.removeIpv6UpstreamRule(upstreamRule)) {
- mLog.e("Failed to remove upstream IPv6 forwarding rule: " + upstreamRule);
- }
+ /**
+ * Clear all downstream rules for a given IpServer and return a copy of all removed rules.
+ */
+ @Nullable
+ private Collection<Ipv6DownstreamRule> clearIpv6DownstreamRules(
+ @NonNull final IpServer ipServer) {
+ final LinkedHashMap<Inet6Address, Ipv6DownstreamRule> downstreamRules =
+ mIpv6DownstreamRules.remove(ipServer);
+ if (downstreamRules == null) return null;
+
+ final Collection<Ipv6DownstreamRule> removedRules = downstreamRules.values();
+ for (final Ipv6DownstreamRule rule : removedRules) {
+ if (rule.upstreamIfindex == NO_UPSTREAM) continue;
+ mBpfCoordinatorShim.removeIpv6DownstreamRule(rule);
}
-
- // Do cleanup functionality if there is no more rule on the given upstream.
- maybeClearLimit(rule.upstreamIfindex);
+ return removedRules;
}
/**
* Clear all forwarding rules for a given downstream.
* Note that this can be only called on handler thread.
- * TODO: rename to tetherOffloadRuleClear6 because of IPv6 only.
*/
- public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
+ public void clearAllIpv6Rules(@NonNull final IpServer ipServer) {
if (!isUsingBpf()) return;
- final LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules =
- mIpv6DownstreamRules.get(ipServer);
- if (rules == null) return;
-
- // Need to build a rule list because the rule map may be changed in the iteration.
- for (final Ipv6DownstreamRule rule : new ArrayList<Ipv6DownstreamRule>(rules.values())) {
- removeIpv6DownstreamRule(ipServer, rule);
- }
+ // Clear downstream rules first, because clearing upstream rules fetches the stats, and
+ // fetching the stats requires that no rules be forwarding traffic to or from the upstream.
+ clearIpv6DownstreamRules(ipServer);
+ clearIpv6UpstreamRules(ipServer);
}
/**
- * Update existing forwarding rules to new upstream for a given downstream.
+ * Delete all upstream and downstream rules for the passed-in IpServer, and if the new upstream
+ * is nonzero, reapply them to the new upstream.
* Note that this can be only called on handler thread.
*/
- public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
+ public void updateAllIpv6Rules(@NonNull final IpServer ipServer,
+ final InterfaceParams interfaceParams, int newUpstreamIfindex) {
if (!isUsingBpf()) return;
- final LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules =
- mIpv6DownstreamRules.get(ipServer);
- if (rules == null) return;
+ // Remove IPv6 downstream rules. Remove the old ones before adding the new rules, otherwise
+ // we need to keep a copy of the old rules.
+ // We still need to keep the downstream rules even when the upstream goes away because it
+ // may come back with the same prefixes (unlikely, but possible). Neighbor entries won't be
+ // deleted and we're not expected to receive new Neighbor events in this case.
+ // TODO: Add new rule first to reduce the latency which has no rule. But this is okay
+ // because if this is a new upstream, it will probably have different prefixes than
+ // the one these downstream rules are in. If so, they will never see any downstream
+ // traffic before new neighbor entries are created.
+ final Collection<Ipv6DownstreamRule> deletedDownstreamRules =
+ clearIpv6DownstreamRules(ipServer);
- // Need to build a rule list because the rule map may be changed in the iteration.
- // First remove all the old rules, then add all the new rules. This is because the upstream
- // forwarding code in addIpv6DownstreamRule cannot support rules on two upstreams at the
- // same time. Deleting the rules first ensures that upstream forwarding is disabled on the
- // old upstream when the last rule is removed from it, and re-enabled on the new upstream
- // when the first rule is added to it.
- // TODO: Once the IPv6 client processing code has moved from IpServer to BpfCoordinator, do
- // something smarter.
- final ArrayList<Ipv6DownstreamRule> rulesCopy = new ArrayList<>(rules.values());
- for (final Ipv6DownstreamRule rule : rulesCopy) {
- // Remove the old rule before adding the new one because the map uses the same key for
- // both rules. Reversing the processing order causes that the new rule is removed as
- // unexpected.
- // TODO: Add new rule first to reduce the latency which has no rule.
- removeIpv6DownstreamRule(ipServer, rule);
+ // Remove IPv6 upstream rules. Downstream rules must be removed first because
+ // BpfCoordinatorShimImpl#tetherOffloadGetAndClearStats will be called after the removal of
+ // the last upstream rule and it requires that no rules be forwarding traffic to or from
+ // that upstream.
+ clearIpv6UpstreamRules(ipServer);
+
+ // Add new upstream rules.
+ if (newUpstreamIfindex != 0 && interfaceParams != null && interfaceParams.macAddr != null) {
+ addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
+ newUpstreamIfindex, interfaceParams.index, IPV6_ZERO_PREFIX64,
+ interfaceParams.macAddr, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS));
}
- for (final Ipv6DownstreamRule rule : rulesCopy) {
+
+ // Add updated downstream rules.
+ if (deletedDownstreamRules == null) return;
+ for (final Ipv6DownstreamRule rule : deletedDownstreamRules) {
addIpv6DownstreamRule(ipServer, rule.onNewUpstream(newUpstreamIfindex));
}
}
@@ -737,7 +809,7 @@
* expects the interface name in NetworkStats object.
* Note that this can be only called on handler thread.
*/
- public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
+ public void maybeAddUpstreamToLookupTable(int upstreamIfindex, @Nullable String upstreamIface) {
if (!isUsingBpf()) return;
if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
@@ -1007,7 +1079,7 @@
* TODO: consider error handling if the attach program failed.
*/
public void maybeAttachProgram(@NonNull String intIface, @NonNull String extIface) {
- if (isVcnInterface(extIface)) return;
+ if (!isUsingBpf() || isVcnInterface(extIface)) return;
if (forwardingPairExists(intIface, extIface)) return;
@@ -1031,6 +1103,8 @@
* Detach BPF program
*/
public void maybeDetachProgram(@NonNull String intIface, @NonNull String extIface) {
+ if (!isUsingBpf()) return;
+
forwardingPairRemove(intIface, extIface);
// Detaching program may fail because the interface has been removed already.
@@ -1967,9 +2041,8 @@
}
private int getInterfaceIndexFromRules(@NonNull String ifName) {
- for (LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules :
- mIpv6DownstreamRules.values()) {
- for (Ipv6DownstreamRule rule : rules.values()) {
+ for (ArraySet<Ipv6UpstreamRule> rules : mIpv6UpstreamRules.values()) {
+ for (Ipv6UpstreamRule rule : rules) {
final int upstreamIfindex = rule.upstreamIfindex;
if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) {
return upstreamIfindex;
@@ -1987,6 +2060,7 @@
}
private boolean sendDataLimitToBpfMap(int ifIndex, long quotaBytes) {
+ if (!isUsingBpf()) return false;
if (ifIndex == 0) {
Log.wtf(TAG, "Invalid interface index.");
return false;
@@ -2060,28 +2134,14 @@
// TODO: Rename to isAnyIpv6RuleOnUpstream and define an isAnyRuleOnUpstream method that called
// both isAnyIpv6RuleOnUpstream and mBpfCoordinatorShim.isAnyIpv4RuleOnUpstream.
private boolean isAnyRuleOnUpstream(int upstreamIfindex) {
- for (LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules :
- mIpv6DownstreamRules.values()) {
- for (Ipv6DownstreamRule rule : rules.values()) {
+ for (ArraySet<Ipv6UpstreamRule> rules : mIpv6UpstreamRules.values()) {
+ for (Ipv6UpstreamRule rule : rules) {
if (upstreamIfindex == rule.upstreamIfindex) return true;
}
}
return false;
}
- private boolean isAnyRuleFromDownstreamToUpstream(int downstreamIfindex, int upstreamIfindex) {
- for (LinkedHashMap<Inet6Address, Ipv6DownstreamRule> rules :
- mIpv6DownstreamRules.values()) {
- for (Ipv6DownstreamRule rule : rules.values()) {
- if (downstreamIfindex == rule.downstreamIfindex
- && upstreamIfindex == rule.upstreamIfindex) {
- return true;
- }
- }
- }
- return false;
- }
-
// TODO: remove the index from map while the interface has been removed because the map size
// is 64 entries. See packages\modules\Connectivity\Tethering\bpf_progs\offload.c.
private void maybeAddDevMap(int upstreamIfindex, int downstreamIfindex) {
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index c0718d1..d497a4d 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -158,6 +158,7 @@
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 NO_UPSTREAM = 0;
private static final int UPSTREAM_IFINDEX = 101;
private static final int UPSTREAM_IFINDEX2 = 102;
private static final int IPSEC_IFINDEX = 103;
@@ -274,8 +275,18 @@
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(upstreamIface);
dispatchTetherConnectionChanged(upstreamIface, lp, 0);
+ if (usingBpfOffload) {
+ InterfaceParams interfaceParams = mDependencies.getInterfaceParams(upstreamIface);
+ assertNotNull("missing upstream interface: " + upstreamIface, interfaceParams);
+ verify(mBpfCoordinator).updateAllIpv6Rules(
+ mIpServer, TEST_IFACE_PARAMS, interfaceParams.index);
+ verifyStartUpstreamIpv6Forwarding(null, interfaceParams.index);
+ } else {
+ verifyNoUpstreamIpv6ForwardingChange(null);
+ }
}
- reset(mNetd, mCallback, mAddressCoordinator, mBpfCoordinator);
+ reset(mCallback, mAddressCoordinator);
+ resetNetdBpfMapAndCoordinator();
when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
anyBoolean())).thenReturn(mTestAddress);
}
@@ -531,7 +542,7 @@
InOrder inOrder = inOrder(mNetd, mBpfCoordinator);
// Add the forwarding pair <IFACE_NAME, UPSTREAM_IFACE>.
- inOrder.verify(mBpfCoordinator).addUpstreamNameToLookupTable(UPSTREAM_IFINDEX,
+ inOrder.verify(mBpfCoordinator).maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX,
UPSTREAM_IFACE);
inOrder.verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
@@ -553,7 +564,7 @@
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
// Add the forwarding pair <IFACE_NAME, UPSTREAM_IFACE2>.
- inOrder.verify(mBpfCoordinator).addUpstreamNameToLookupTable(UPSTREAM_IFINDEX2,
+ inOrder.verify(mBpfCoordinator).maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX2,
UPSTREAM_IFACE2);
inOrder.verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
@@ -578,7 +589,7 @@
// Add the forwarding pair <IFACE_NAME, UPSTREAM_IFACE2> and expect that failed on
// tetherAddForward.
- inOrder.verify(mBpfCoordinator).addUpstreamNameToLookupTable(UPSTREAM_IFINDEX2,
+ inOrder.verify(mBpfCoordinator).maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX2,
UPSTREAM_IFACE2);
inOrder.verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
@@ -606,7 +617,7 @@
// Add the forwarding pair <IFACE_NAME, UPSTREAM_IFACE2> and expect that failed on
// ipfwdAddInterfaceForward.
- inOrder.verify(mBpfCoordinator).addUpstreamNameToLookupTable(UPSTREAM_IFINDEX2,
+ inOrder.verify(mBpfCoordinator).maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX2,
UPSTREAM_IFACE2);
inOrder.verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
@@ -627,7 +638,15 @@
inOrder.verify(mBpfCoordinator).maybeDetachProgram(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
+ inOrder.verify(mBpfCoordinator).updateAllIpv6Rules(
+ mIpServer, TEST_IFACE_PARAMS, NO_UPSTREAM);
+ if (!mBpfDeps.isAtLeastS()) {
+ inOrder.verify(mNetd).tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX);
+ }
+ // When tethering stops, upstream interface is set to zero and thus clearing all upstream
+ // rules. Downstream rules are needed to be cleared explicitly by calling
+ // BpfCoordinator#clearAllIpv6Rules in TetheredState#exit.
+ inOrder.verify(mBpfCoordinator).clearAllIpv6Rules(mIpServer);
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
@@ -1064,13 +1083,12 @@
recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfDownstream6Map, mBpfUpstream6Map);
- // Events on this interface are received and sent to netd.
+ // Events on this interface are received and sent to BpfCoordinator.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
verify(mBpfCoordinator).addIpv6DownstreamRule(
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighA, macA));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
- verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
resetNetdBpfMapAndCoordinator();
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
@@ -1078,7 +1096,6 @@
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighB, macB));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
- verifyNoUpstreamIpv6ForwardingChange(null);
resetNetdBpfMapAndCoordinator();
// Link-local and multicast neighbors are ignored.
@@ -1094,7 +1111,6 @@
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighA, macNull));
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macNull);
- verifyNoUpstreamIpv6ForwardingChange(null);
resetNetdBpfMapAndCoordinator();
// A neighbor that is deleted causes the rule to be removed.
@@ -1103,12 +1119,10 @@
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighB, macNull));
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macNull);
- verifyStopUpstreamIpv6Forwarding(null);
resetNetdBpfMapAndCoordinator();
// Upstream changes result in updating the rules.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
resetNetdBpfMapAndCoordinator();
@@ -1116,89 +1130,100 @@
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
- verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
+ verify(mBpfCoordinator).updateAllIpv6Rules(mIpServer, TEST_IFACE_PARAMS, UPSTREAM_IFINDEX2);
verifyTetherOffloadRuleRemove(inOrder,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
verifyTetherOffloadRuleRemove(inOrder,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
verifyStopUpstreamIpv6Forwarding(inOrder);
- verifyTetherOffloadRuleAdd(inOrder,
- UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighA, macA);
verifyStartUpstreamIpv6Forwarding(inOrder, UPSTREAM_IFINDEX2);
verifyTetherOffloadRuleAdd(inOrder,
+ UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighA, macA);
+ verifyTetherOffloadRuleAdd(inOrder,
UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighB, macB);
- verifyNoUpstreamIpv6ForwardingChange(inOrder);
resetNetdBpfMapAndCoordinator();
// When the upstream is lost, rules are removed.
dispatchTetherConnectionChanged(null, null, 0);
- // Clear function is called two times by:
+ // Upstream clear function is called two times by:
// - processMessage CMD_TETHER_CONNECTION_CHANGED for the upstream is lost.
// - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost.
// See dispatchTetherConnectionChanged.
- verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
+ verify(mBpfCoordinator, times(2)).updateAllIpv6Rules(
+ mIpServer, TEST_IFACE_PARAMS, NO_UPSTREAM);
+ verifyStopUpstreamIpv6Forwarding(inOrder);
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighA, macA);
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX2, UPSTREAM_IFACE_PARAMS2.macAddr, neighB, macB);
- verifyStopUpstreamIpv6Forwarding(inOrder);
+ // Upstream lost doesn't clear the downstream rules from BpfCoordinator.
+ // Do that here.
+ recvDelNeigh(myIfindex, neighA, NUD_STALE, macA);
+ recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
+ verify(mBpfCoordinator).removeIpv6DownstreamRule(
+ mIpServer, makeDownstreamRule(NO_UPSTREAM, neighA, macNull));
+ verify(mBpfCoordinator).removeIpv6DownstreamRule(
+ mIpServer, makeDownstreamRule(NO_UPSTREAM, neighB, macNull));
resetNetdBpfMapAndCoordinator();
- // If the upstream is IPv4-only, no rules are added.
+ // If the upstream is IPv4-only, no IPv6 rules are added to BPF map.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
resetNetdBpfMapAndCoordinator();
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- // Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost.
- verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
verifyNoUpstreamIpv6ForwardingChange(null);
+ // Downstream rules are only added to BpfCoordinator but not BPF map.
+ verify(mBpfCoordinator).addIpv6DownstreamRule(
+ mIpServer, makeDownstreamRule(NO_UPSTREAM, neighA, macA));
+ verifyNeverTetherOffloadRuleAdd();
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfDownstream6Map, mBpfUpstream6Map);
- // Rules can be added again once upstream IPv6 connectivity is available.
+ // Rules can be added again once upstream IPv6 connectivity is available. The existing rules
+ // with an upstream of NO_UPSTREAM are reapplied.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
+ verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
+ verify(mBpfCoordinator).addIpv6DownstreamRule(
+ mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighA, macA));
+ verifyTetherOffloadRuleAdd(null,
+ UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
verify(mBpfCoordinator).addIpv6DownstreamRule(
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighB, macB));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
- verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
- verify(mBpfCoordinator, never()).addIpv6DownstreamRule(
- mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighA, macA));
- verifyNeverTetherOffloadRuleAdd(
- UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
// If upstream IPv6 connectivity is lost, rules are removed.
resetNetdBpfMapAndCoordinator();
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
- verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
+ verify(mBpfCoordinator).updateAllIpv6Rules(mIpServer, TEST_IFACE_PARAMS, NO_UPSTREAM);
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
verifyStopUpstreamIpv6Forwarding(null);
- // When the interface goes down, rules are removed.
+ // When upstream IPv6 connectivity comes back, upstream rules are added and downstream rules
+ // are reapplied.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
- recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
verify(mBpfCoordinator).addIpv6DownstreamRule(
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighA, macA));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
- verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
verify(mBpfCoordinator).addIpv6DownstreamRule(
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neighB, macB));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
resetNetdBpfMapAndCoordinator();
+ // When the downstream interface goes down, rules are removed.
mIpServer.stop();
mLooper.dispatchAll();
- verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
+ verify(mBpfCoordinator).clearAllIpv6Rules(mIpServer);
+ verifyStopUpstreamIpv6Forwarding(null);
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighA, macA);
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neighB, macB);
- verifyStopUpstreamIpv6Forwarding(null);
verify(mIpNeighborMonitor).stop();
resetNetdBpfMapAndCoordinator();
}
@@ -1228,7 +1253,6 @@
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neigh, macA));
verifyTetherOffloadRuleAdd(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neigh, macA);
- verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX);
resetNetdBpfMapAndCoordinator();
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
@@ -1236,7 +1260,14 @@
mIpServer, makeDownstreamRule(UPSTREAM_IFINDEX, neigh, macNull));
verifyTetherOffloadRuleRemove(null,
UPSTREAM_IFINDEX, UPSTREAM_IFACE_PARAMS.macAddr, neigh, macNull);
- verifyStopUpstreamIpv6Forwarding(null);
+ resetNetdBpfMapAndCoordinator();
+
+ // Upstream IPv6 connectivity change causes upstream rules change.
+ LinkProperties lp2 = new LinkProperties();
+ lp2.setInterfaceName(UPSTREAM_IFACE2);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
+ verify(mBpfCoordinator).updateAllIpv6Rules(mIpServer, TEST_IFACE_PARAMS, UPSTREAM_IFINDEX2);
+ verifyStartUpstreamIpv6Forwarding(null, UPSTREAM_IFINDEX2);
resetNetdBpfMapAndCoordinator();
// [2] Disable BPF offload.
@@ -1247,12 +1278,16 @@
recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
verifyNeverTetherOffloadRuleAdd();
- verifyNoUpstreamIpv6ForwardingChange(null);
resetNetdBpfMapAndCoordinator();
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
verifyNeverTetherOffloadRuleRemove();
+ resetNetdBpfMapAndCoordinator();
+
+ // Upstream IPv6 connectivity change doesn't cause the rule to be added or removed.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
verifyNoUpstreamIpv6ForwardingChange(null);
+ verifyNeverTetherOffloadRuleRemove();
resetNetdBpfMapAndCoordinator();
}
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 04eb430..601f587 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -169,6 +169,8 @@
private static final String UPSTREAM_IFACE = "rmnet0";
private static final String UPSTREAM_XLAT_IFACE = "v4-rmnet0";
private static final String UPSTREAM_IFACE2 = "wlan0";
+ private static final String DOWNSTREAM_IFACE = "downstream1";
+ private static final String DOWNSTREAM_IFACE2 = "downstream2";
private static final MacAddress DOWNSTREAM_MAC = MacAddress.fromString("12:34:56:78:90:ab");
private static final MacAddress DOWNSTREAM_MAC2 = MacAddress.fromString("ab:90:78:56:34:12");
@@ -213,6 +215,11 @@
private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.fromString("44:55:66:00:00:0c"),
NetworkStackConstants.ETHER_MTU);
+ private static final InterfaceParams DOWNSTREAM_IFACE_PARAMS = new InterfaceParams(
+ DOWNSTREAM_IFACE, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC, NetworkStackConstants.ETHER_MTU);
+ private static final InterfaceParams DOWNSTREAM_IFACE_PARAMS2 = new InterfaceParams(
+ DOWNSTREAM_IFACE2, DOWNSTREAM_IFINDEX2, DOWNSTREAM_MAC2,
+ NetworkStackConstants.ETHER_MTU);
private static final Map<Integer, UpstreamInformation> UPSTREAM_INFORMATIONS = Map.of(
UPSTREAM_IFINDEX, new UpstreamInformation(UPSTREAM_IFACE_PARAMS,
@@ -640,24 +647,6 @@
}
}
- private void verifyStartUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex,
- MacAddress downstreamMac, int upstreamIfindex) throws Exception {
- if (!mDeps.isAtLeastS()) return;
- final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac, 0);
- final Tether6Value value = new Tether6Value(upstreamIfindex,
- MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS,
- ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
- verifyWithOrder(inOrder, mBpfUpstream6Map).insertEntry(key, value);
- }
-
- private void verifyStopUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex,
- MacAddress downstreamMac)
- throws Exception {
- if (!mDeps.isAtLeastS()) return;
- final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac, 0);
- verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(key);
- }
-
private void verifyNoUpstreamIpv6ForwardingChange(@Nullable InOrder inOrder) throws Exception {
if (!mDeps.isAtLeastS()) return;
if (inOrder != null) {
@@ -671,6 +660,13 @@
}
}
+ private void verifyAddUpstreamRule(@Nullable InOrder inOrder,
+ @NonNull Ipv6UpstreamRule rule) throws Exception {
+ if (!mDeps.isAtLeastS()) return;
+ verifyWithOrder(inOrder, mBpfUpstream6Map).insertEntry(
+ rule.makeTetherUpstream6Key(), rule.makeTether6Value());
+ }
+
private void verifyAddDownstreamRule(@Nullable InOrder inOrder,
@NonNull Ipv6DownstreamRule rule) throws Exception {
if (mDeps.isAtLeastS()) {
@@ -681,6 +677,11 @@
}
}
+ private void verifyNeverAddUpstreamRule() throws Exception {
+ if (!mDeps.isAtLeastS()) return;
+ verify(mBpfUpstream6Map, never()).insertEntry(any(), any());
+ }
+
private void verifyNeverAddDownstreamRule() throws Exception {
if (mDeps.isAtLeastS()) {
verify(mBpfDownstream6Map, never()).updateEntry(any(), any());
@@ -689,6 +690,13 @@
}
}
+ private void verifyRemoveUpstreamRule(@Nullable InOrder inOrder,
+ @NonNull final Ipv6UpstreamRule rule) throws Exception {
+ if (!mDeps.isAtLeastS()) return;
+ verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(
+ rule.makeTetherUpstream6Key());
+ }
+
private void verifyRemoveDownstreamRule(@Nullable InOrder inOrder,
@NonNull final Ipv6DownstreamRule rule) throws Exception {
if (mDeps.isAtLeastS()) {
@@ -699,6 +707,11 @@
}
}
+ private void verifyNeverRemoveUpstreamRule() throws Exception {
+ if (!mDeps.isAtLeastS()) return;
+ verify(mBpfUpstream6Map, never()).deleteEntry(any());
+ }
+
private void verifyNeverRemoveDownstreamRule() throws Exception {
if (mDeps.isAtLeastS()) {
verify(mBpfDownstream6Map, never()).deleteEntry(any());
@@ -763,24 +776,31 @@
final String mobileIface = "rmnet_data0";
final Integer mobileIfIndex = 100;
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
// InOrder is required because mBpfStatsMap may be accessed by both
// BpfCoordinator#tetherOffloadRuleAdd and BpfCoordinator#tetherOffloadGetAndClearStats.
// The #verifyTetherOffloadGetAndClearStats can't distinguish who has ever called
// mBpfStatsMap#getValue and get a wrong calling count which counts all.
- final InOrder inOrder = inOrder(mNetd, mBpfDownstream6Map, mBpfLimitMap, mBpfStatsMap);
- final Ipv6DownstreamRule rule = buildTestDownstreamRule(mobileIfIndex, NEIGH_A, MAC_A);
- coordinator.addIpv6DownstreamRule(mIpServer, rule);
- verifyAddDownstreamRule(inOrder, rule);
+ final InOrder inOrder = inOrder(mNetd, mBpfUpstream6Map, mBpfDownstream6Map, mBpfLimitMap,
+ mBpfStatsMap);
+ final Ipv6UpstreamRule upstreamRule = buildTestUpstreamRule(
+ mobileIfIndex, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
+ final Ipv6DownstreamRule downstreamRule = buildTestDownstreamRule(
+ mobileIfIndex, NEIGH_A, MAC_A);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, mobileIfIndex);
verifyTetherOffloadSetInterfaceQuota(inOrder, mobileIfIndex, QUOTA_UNLIMITED,
true /* isInit */);
+ verifyAddUpstreamRule(inOrder, upstreamRule);
+ coordinator.addIpv6DownstreamRule(mIpServer, downstreamRule);
+ verifyAddDownstreamRule(inOrder, downstreamRule);
- // Removing the last rule on current upstream immediately sends the cleanup stuff to netd.
+ // Removing the last rule on current upstream immediately sends the cleanup stuff to BPF.
updateStatsEntryForTetherOffloadGetAndClearStats(
buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0));
- coordinator.removeIpv6DownstreamRule(mIpServer, rule);
- verifyRemoveDownstreamRule(inOrder, rule);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, 0);
+ verifyRemoveDownstreamRule(inOrder, downstreamRule);
+ verifyRemoveUpstreamRule(inOrder, upstreamRule);
verifyTetherOffloadGetAndClearStats(inOrder, mobileIfIndex);
}
@@ -806,7 +826,7 @@
final String mobileIface = "rmnet_data0";
final Integer mobileIfIndex = 100;
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
updateStatsEntriesAndWaitForUpdate(new TetherStatsParcel[] {
buildTestTetherStatsParcel(mobileIfIndex, 1000, 100, 2000, 200)});
@@ -847,8 +867,8 @@
// Add interface name to lookup table. In realistic case, the upstream interface name will
// be added by IpServer when IpServer has received with a new IPv6 upstream update event.
- coordinator.addUpstreamNameToLookupTable(wlanIfIndex, wlanIface);
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(wlanIfIndex, wlanIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
// [1] Both interface stats are changed.
// Setup the tether stats of wlan and mobile interface. Note that move forward the time of
@@ -912,7 +932,7 @@
final String mobileIface = "rmnet_data0";
final Integer mobileIfIndex = 100;
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
// Verify that set quota to 0 will immediately triggers a callback.
mTetherStatsProvider.onSetAlert(0);
@@ -978,9 +998,10 @@
}
@NonNull
- private static Ipv6UpstreamRule buildTestUpstreamRule(int upstreamIfindex) {
- return new Ipv6UpstreamRule(upstreamIfindex, DOWNSTREAM_IFINDEX,
- IPV6_ZERO_PREFIX, DOWNSTREAM_MAC, MacAddress.ALL_ZEROS_ADDRESS,
+ private static Ipv6UpstreamRule buildTestUpstreamRule(
+ int upstreamIfindex, int downstreamIfindex, @NonNull MacAddress inDstMac) {
+ return new Ipv6UpstreamRule(upstreamIfindex, downstreamIfindex,
+ IPV6_ZERO_PREFIX, inDstMac, MacAddress.ALL_ZEROS_ADDRESS,
MacAddress.ALL_ZEROS_ADDRESS);
}
@@ -1027,17 +1048,18 @@
final String mobileIface = "rmnet_data0";
final int mobileIfIndex = 100;
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
// [1] Default limit.
// Set the unlimited quota as default if the service has never applied a data limit for a
// given upstream. Note that the data limit only be applied on an upstream which has rules.
- final Ipv6DownstreamRule rule = buildTestDownstreamRule(mobileIfIndex, NEIGH_A, MAC_A);
- final InOrder inOrder = inOrder(mNetd, mBpfDownstream6Map, mBpfLimitMap, mBpfStatsMap);
- coordinator.addIpv6DownstreamRule(mIpServer, rule);
- verifyAddDownstreamRule(inOrder, rule);
+ final Ipv6UpstreamRule rule = buildTestUpstreamRule(
+ mobileIfIndex, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
+ final InOrder inOrder = inOrder(mNetd, mBpfUpstream6Map, mBpfLimitMap, mBpfStatsMap);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, mobileIfIndex);
verifyTetherOffloadSetInterfaceQuota(inOrder, mobileIfIndex, QUOTA_UNLIMITED,
true /* isInit */);
+ verifyAddUpstreamRule(inOrder, rule);
inOrder.verifyNoMoreInteractions();
// [2] Specific limit.
@@ -1062,7 +1084,6 @@
}
}
- // TODO: Test the case in which the rules are changed from different IpServer objects.
@Test
public void testSetDataLimitOnRule6Change() throws Exception {
setupFunctioningNetdInterface();
@@ -1071,39 +1092,41 @@
final String mobileIface = "rmnet_data0";
final int mobileIfIndex = 100;
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
// Applying a data limit to the current upstream does not take any immediate action.
// The data limit could be only set on an upstream which has rules.
final long limit = 12345;
- final InOrder inOrder = inOrder(mNetd, mBpfDownstream6Map, mBpfLimitMap, mBpfStatsMap);
+ final InOrder inOrder = inOrder(mNetd, mBpfUpstream6Map, mBpfLimitMap, mBpfStatsMap);
mTetherStatsProvider.onSetLimit(mobileIface, limit);
waitForIdle();
verifyNeverTetherOffloadSetInterfaceQuota(inOrder);
- // Adding the first rule on current upstream immediately sends the quota to netd.
- final Ipv6DownstreamRule ruleA = buildTestDownstreamRule(mobileIfIndex, NEIGH_A, MAC_A);
- coordinator.addIpv6DownstreamRule(mIpServer, ruleA);
- verifyAddDownstreamRule(inOrder, ruleA);
+ // Adding the first rule on current upstream immediately sends the quota to BPF.
+ final Ipv6UpstreamRule ruleA = buildTestUpstreamRule(
+ mobileIfIndex, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, mobileIfIndex);
verifyTetherOffloadSetInterfaceQuota(inOrder, mobileIfIndex, limit, true /* isInit */);
+ verifyAddUpstreamRule(inOrder, ruleA);
inOrder.verifyNoMoreInteractions();
- // Adding the second rule on current upstream does not send the quota to netd.
- final Ipv6DownstreamRule ruleB = buildTestDownstreamRule(mobileIfIndex, NEIGH_B, MAC_B);
- coordinator.addIpv6DownstreamRule(mIpServer, ruleB);
- verifyAddDownstreamRule(inOrder, ruleB);
+ // Adding the second rule on current upstream does not send the quota to BPF.
+ final Ipv6UpstreamRule ruleB = buildTestUpstreamRule(
+ mobileIfIndex, DOWNSTREAM_IFINDEX2, DOWNSTREAM_MAC2);
+ coordinator.updateAllIpv6Rules(mIpServer2, DOWNSTREAM_IFACE_PARAMS2, mobileIfIndex);
+ verifyAddUpstreamRule(inOrder, ruleB);
verifyNeverTetherOffloadSetInterfaceQuota(inOrder);
- // Removing the second rule on current upstream does not send the quota to netd.
- coordinator.removeIpv6DownstreamRule(mIpServer, ruleB);
- verifyRemoveDownstreamRule(inOrder, ruleB);
+ // Removing the second rule on current upstream does not send the quota to BPF.
+ coordinator.updateAllIpv6Rules(mIpServer2, DOWNSTREAM_IFACE_PARAMS2, 0);
+ verifyRemoveUpstreamRule(inOrder, ruleB);
verifyNeverTetherOffloadSetInterfaceQuota(inOrder);
- // Removing the last rule on current upstream immediately sends the cleanup stuff to netd.
+ // Removing the last rule on current upstream immediately sends the cleanup stuff to BPF.
updateStatsEntryForTetherOffloadGetAndClearStats(
buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0));
- coordinator.removeIpv6DownstreamRule(mIpServer, ruleA);
- verifyRemoveDownstreamRule(inOrder, ruleA);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, 0);
+ verifyRemoveUpstreamRule(inOrder, ruleA);
verifyTetherOffloadGetAndClearStats(inOrder, mobileIfIndex);
inOrder.verifyNoMoreInteractions();
}
@@ -1118,8 +1141,8 @@
final String mobileIface = "rmnet_data0";
final Integer ethIfIndex = 100;
final Integer mobileIfIndex = 101;
- coordinator.addUpstreamNameToLookupTable(ethIfIndex, ethIface);
- coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+ coordinator.maybeAddUpstreamToLookupTable(ethIfIndex, ethIface);
+ coordinator.maybeAddUpstreamToLookupTable(mobileIfIndex, mobileIface);
final InOrder inOrder = inOrder(mNetd, mBpfDownstream6Map, mBpfUpstream6Map, mBpfLimitMap,
mBpfStatsMap);
@@ -1133,20 +1156,25 @@
// [1] Adding rules on the upstream Ethernet.
// Note that the default data limit is applied after the first rule is added.
+ final Ipv6UpstreamRule ethernetUpstreamRule = buildTestUpstreamRule(
+ ethIfIndex, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
final Ipv6DownstreamRule ethernetRuleA = buildTestDownstreamRule(
ethIfIndex, NEIGH_A, MAC_A);
final Ipv6DownstreamRule ethernetRuleB = buildTestDownstreamRule(
ethIfIndex, NEIGH_B, MAC_B);
- coordinator.addIpv6DownstreamRule(mIpServer, ethernetRuleA);
- verifyAddDownstreamRule(inOrder, ethernetRuleA);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, ethIfIndex);
verifyTetherOffloadSetInterfaceQuota(inOrder, ethIfIndex, QUOTA_UNLIMITED,
true /* isInit */);
- verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC, ethIfIndex);
+ verifyAddUpstreamRule(inOrder, ethernetUpstreamRule);
+ coordinator.addIpv6DownstreamRule(mIpServer, ethernetRuleA);
+ verifyAddDownstreamRule(inOrder, ethernetRuleA);
coordinator.addIpv6DownstreamRule(mIpServer, ethernetRuleB);
verifyAddDownstreamRule(inOrder, ethernetRuleB);
// [2] Update the existing rules from Ethernet to cellular.
+ final Ipv6UpstreamRule mobileUpstreamRule = buildTestUpstreamRule(
+ mobileIfIndex, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
final Ipv6DownstreamRule mobileRuleA = buildTestDownstreamRule(
mobileIfIndex, NEIGH_A, MAC_A);
final Ipv6DownstreamRule mobileRuleB = buildTestDownstreamRule(
@@ -1156,25 +1184,24 @@
// Update the existing rules for upstream changes. The rules are removed and re-added one
// by one for updating upstream interface index by #tetherOffloadRuleUpdate.
- coordinator.tetherOffloadRuleUpdate(mIpServer, mobileIfIndex);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, mobileIfIndex);
verifyRemoveDownstreamRule(inOrder, ethernetRuleA);
verifyRemoveDownstreamRule(inOrder, ethernetRuleB);
- verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
+ verifyRemoveUpstreamRule(inOrder, ethernetUpstreamRule);
verifyTetherOffloadGetAndClearStats(inOrder, ethIfIndex);
- verifyAddDownstreamRule(inOrder, mobileRuleA);
verifyTetherOffloadSetInterfaceQuota(inOrder, mobileIfIndex, QUOTA_UNLIMITED,
true /* isInit */);
- verifyStartUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC,
- mobileIfIndex);
+ verifyAddUpstreamRule(inOrder, mobileUpstreamRule);
+ verifyAddDownstreamRule(inOrder, mobileRuleA);
verifyAddDownstreamRule(inOrder, mobileRuleB);
// [3] Clear all rules for a given IpServer.
updateStatsEntryForTetherOffloadGetAndClearStats(
buildTestTetherStatsParcel(mobileIfIndex, 50, 60, 70, 80));
- coordinator.tetherOffloadRuleClear(mIpServer);
+ coordinator.clearAllIpv6Rules(mIpServer);
verifyRemoveDownstreamRule(inOrder, mobileRuleA);
verifyRemoveDownstreamRule(inOrder, mobileRuleB);
- verifyStopUpstreamIpv6Forwarding(inOrder, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
+ verifyRemoveUpstreamRule(inOrder, mobileUpstreamRule);
verifyTetherOffloadGetAndClearStats(inOrder, mobileIfIndex);
// [4] Force pushing stats update to verify that the last diff of stats is reported on all
@@ -1204,7 +1231,7 @@
// The interface name lookup table can't be added.
final String iface = "rmnet_data0";
final Integer ifIndex = 100;
- coordinator.addUpstreamNameToLookupTable(ifIndex, iface);
+ coordinator.maybeAddUpstreamToLookupTable(ifIndex, iface);
assertEquals(0, coordinator.getInterfaceNamesForTesting().size());
// The rule can't be added.
@@ -1230,14 +1257,15 @@
assertEquals(1, rules.size());
// The rule can't be cleared.
- coordinator.tetherOffloadRuleClear(mIpServer);
+ coordinator.clearAllIpv6Rules(mIpServer);
verifyNeverRemoveDownstreamRule();
rules = coordinator.getIpv6DownstreamRulesForTesting().get(mIpServer);
assertNotNull(rules);
assertEquals(1, rules.size());
// The rule can't be updated.
- coordinator.tetherOffloadRuleUpdate(mIpServer, rule.upstreamIfindex + 1 /* new */);
+ coordinator.updateAllIpv6Rules(
+ mIpServer, DOWNSTREAM_IFACE_PARAMS, rule.upstreamIfindex + 1 /* new */);
verifyNeverRemoveDownstreamRule();
verifyNeverAddDownstreamRule();
rules = coordinator.getIpv6DownstreamRulesForTesting().get(mIpServer);
@@ -1552,7 +1580,7 @@
// interface index.
doReturn(upstreamInfo.interfaceParams).when(mDeps).getInterfaceParams(
upstreamInfo.interfaceParams.name);
- coordinator.addUpstreamNameToLookupTable(upstreamInfo.interfaceParams.index,
+ coordinator.maybeAddUpstreamToLookupTable(upstreamInfo.interfaceParams.index,
upstreamInfo.interfaceParams.name);
final LinkProperties lp = new LinkProperties();
@@ -1677,19 +1705,21 @@
public void testAddDevMapRule6() throws Exception {
final BpfCoordinator coordinator = makeBpfCoordinator();
- coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
- final Ipv6DownstreamRule ruleA = buildTestDownstreamRule(UPSTREAM_IFINDEX, NEIGH_A, MAC_A);
- final Ipv6DownstreamRule ruleB = buildTestDownstreamRule(UPSTREAM_IFINDEX, NEIGH_B, MAC_B);
-
- coordinator.addIpv6DownstreamRule(mIpServer, ruleA);
+ coordinator.maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
+ coordinator.updateAllIpv6Rules(mIpServer, DOWNSTREAM_IFACE_PARAMS, UPSTREAM_IFINDEX);
verify(mBpfDevMap).updateEntry(eq(new TetherDevKey(UPSTREAM_IFINDEX)),
eq(new TetherDevValue(UPSTREAM_IFINDEX)));
verify(mBpfDevMap).updateEntry(eq(new TetherDevKey(DOWNSTREAM_IFINDEX)),
eq(new TetherDevValue(DOWNSTREAM_IFINDEX)));
clearInvocations(mBpfDevMap);
- coordinator.addIpv6DownstreamRule(mIpServer, ruleB);
- verify(mBpfDevMap, never()).updateEntry(any(), any());
+ // Adding the second downstream, only the second downstream ifindex is added to DevMap,
+ // the existing upstream ifindex won't be added again.
+ coordinator.updateAllIpv6Rules(mIpServer2, DOWNSTREAM_IFACE_PARAMS2, UPSTREAM_IFINDEX);
+ verify(mBpfDevMap).updateEntry(eq(new TetherDevKey(DOWNSTREAM_IFINDEX2)),
+ eq(new TetherDevValue(DOWNSTREAM_IFINDEX2)));
+ verify(mBpfDevMap, never()).updateEntry(eq(new TetherDevKey(UPSTREAM_IFINDEX)),
+ eq(new TetherDevValue(UPSTREAM_IFINDEX)));
}
@Test
@@ -2153,7 +2183,8 @@
assertEquals("upstreamIfindex: 1001, downstreamIfindex: 2001, address: 2001:db8::1, "
+ "srcMac: 12:34:56:78:90:ab, dstMac: 00:00:00:00:00:0a",
downstreamRule.toString());
- final Ipv6UpstreamRule upstreamRule = buildTestUpstreamRule(UPSTREAM_IFINDEX);
+ final Ipv6UpstreamRule upstreamRule = buildTestUpstreamRule(
+ UPSTREAM_IFINDEX, DOWNSTREAM_IFINDEX, DOWNSTREAM_MAC);
assertEquals("upstreamIfindex: 1001, downstreamIfindex: 2001, sourcePrefix: ::/64, "
+ "inDstMac: 12:34:56:78:90:ab, outSrcMac: 00:00:00:00:00:00, "
+ "outDstMac: 00:00:00:00:00:00", upstreamRule.toString());
@@ -2221,7 +2252,7 @@
0L /* txPackets */, 0L /* txBytes */, 0L /* txErrors */));
// dumpDevmap
- coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
+ coordinator.maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
mBpfDevMap.insertEntry(
new TetherDevKey(UPSTREAM_IFINDEX),
new TetherDevValue(UPSTREAM_IFINDEX));
@@ -2390,7 +2421,7 @@
// +-------+-------+-------+-------+-------+
// [1] Mobile IPv4 only
- coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
+ coordinator.maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
doReturn(UPSTREAM_IFACE_PARAMS).when(mDeps).getInterfaceParams(UPSTREAM_IFACE);
final UpstreamNetworkState mobileIPv4UpstreamState = new UpstreamNetworkState(
buildUpstreamLinkProperties(UPSTREAM_IFACE,
@@ -2442,7 +2473,7 @@
verifyIpv4Upstream(ipv4UpstreamIndices, interfaceNames);
// Mobile IPv6 and xlat
- // IpServer doesn't add xlat interface mapping via #addUpstreamNameToLookupTable on
+ // IpServer doesn't add xlat interface mapping via #maybeAddUpstreamToLookupTable on
// S and T devices.
coordinator.updateUpstreamNetworkState(mobile464xlatUpstreamState);
// Upstream IPv4 address mapping is removed because xlat interface is not supported.
@@ -2457,7 +2488,7 @@
// [6] Wifi IPv4 and IPv6
// Expect that upstream index map is cleared because ether ip is not supported.
- coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX2, UPSTREAM_IFACE2);
+ coordinator.maybeAddUpstreamToLookupTable(UPSTREAM_IFINDEX2, UPSTREAM_IFACE2);
doReturn(UPSTREAM_IFACE_PARAMS2).when(mDeps).getInterfaceParams(UPSTREAM_IFACE2);
final UpstreamNetworkState wifiDualStackUpstreamState = new UpstreamNetworkState(
buildUpstreamLinkProperties(UPSTREAM_IFACE2,
diff --git a/bpf_progs/block.c b/bpf_progs/block.c
index d734b74..0a2b0b8 100644
--- a/bpf_progs/block.c
+++ b/bpf_progs/block.c
@@ -24,8 +24,8 @@
#include "bpf_helpers.h"
-#define ALLOW 1
-#define DISALLOW 0
+static const int ALLOW = 1;
+static const int DISALLOW = 0;
DEFINE_BPF_MAP_GRW(blocked_ports_map, ARRAY, int, uint64_t,
1024 /* 64K ports -> 1024 u64s */, AID_SYSTEM)
@@ -57,14 +57,18 @@
return ALLOW;
}
-DEFINE_BPF_PROG_KVER("bind4/block_port", AID_ROOT, AID_SYSTEM,
- bind4_block_port, KVER(5, 4, 0))
+// the program need to be accessible/loadable by netd (from netd updatable plugin)
+#define DEFINE_NETD_RO_BPF_PROG(SECTION_NAME, the_prog, min_kver) \
+ DEFINE_BPF_PROG_EXT(SECTION_NAME, AID_ROOT, AID_ROOT, the_prog, min_kver, KVER_INF, \
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
+ "", "netd_readonly/", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
+
+DEFINE_NETD_RO_BPF_PROG("bind4/block_port", bind4_block_port, KVER_4_19)
(struct bpf_sock_addr *ctx) {
return block_port(ctx);
}
-DEFINE_BPF_PROG_KVER("bind6/block_port", AID_ROOT, AID_SYSTEM,
- bind6_block_port, KVER(5, 4, 0))
+DEFINE_NETD_RO_BPF_PROG("bind6/block_port", bind6_block_port, KVER_4_19)
(struct bpf_sock_addr *ctx) {
return block_port(ctx);
}
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index ed33cc9..f3c7de5 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -87,29 +87,18 @@
if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
}
-// constants for passing in to 'bool egress'
-static const bool INGRESS = false;
-static const bool EGRESS = true;
+struct egress_bool { bool egress; };
+#define INGRESS ((struct egress_bool){ .egress = false })
+#define EGRESS ((struct egress_bool){ .egress = true })
-// constants for passing in to 'bool downstream'
-static const bool UPSTREAM = false;
-static const bool DOWNSTREAM = true;
+struct stream_bool { bool down; };
+#define UPSTREAM ((struct stream_bool){ .down = false })
+#define DOWNSTREAM ((struct stream_bool){ .down = true })
-// constants for passing in to 'bool is_ethernet'
-static const bool RAWIP = false;
-static const bool ETHER = true;
+struct rawip_bool { bool rawip; };
+#define ETHER ((struct rawip_bool){ .rawip = false })
+#define RAWIP ((struct rawip_bool){ .rawip = true })
-// constants for passing in to 'bool updatetime'
-static const bool NO_UPDATETIME = false;
-static const bool UPDATETIME = true;
-
-// constants for passing in to ignore_on_eng / ignore_on_user / ignore_on_userdebug
-// define's instead of static const due to tm-mainline-prod compiler static_assert limitations
-#define LOAD_ON_ENG false
-#define LOAD_ON_USER false
-#define LOAD_ON_USERDEBUG false
-#define IGNORE_ON_ENG true
-#define IGNORE_ON_USER true
-#define IGNORE_ON_USERDEBUG true
-
-#define KVER_4_14 KVER(4, 14, 0)
+struct updatetime_bool { bool updatetime; };
+#define NO_UPDATETIME ((struct updatetime_bool){ .updatetime = false })
+#define UPDATETIME ((struct updatetime_bool){ .updatetime = true })
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 8f0ff84..addb02f 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -55,8 +55,10 @@
DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM)
static inline __always_inline int nat64(struct __sk_buff* skb,
- const bool is_ethernet,
- const unsigned kver) {
+ const struct rawip_bool rawip,
+ const struct kver_uint kver) {
+ const bool is_ethernet = !rawip.rawip;
+
// Require ethernet dst mac address to be our unicast address.
if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
@@ -115,7 +117,7 @@
if (proto == IPPROTO_FRAGMENT) {
// Fragment handling requires bpf_skb_adjust_room which is 4.14+
- if (kver < KVER_4_14) return TC_ACT_PIPE;
+ if (!KVER_IS_AT_LEAST(kver, 4, 14, 0)) return TC_ACT_PIPE;
// Must have (ethernet and) ipv6 header and ipv6 fragment extension header
if (data + l2_header_size + sizeof(*ip6) + sizeof(struct frag_hdr) > data_end)
@@ -233,7 +235,7 @@
//
// Note: we currently have no TreeHugger coverage for 4.9-T devices (there are no such
// Pixel or cuttlefish devices), so likely you won't notice for months if this breaks...
- if (kver >= KVER_4_14 && frag_off != htons(IP_DF)) {
+ if (KVER_IS_AT_LEAST(kver, 4, 14, 0) && frag_off != htons(IP_DF)) {
// If we're converting an IPv6 Fragment, we need to trim off 8 more bytes
// We're beyond recovery on error here... but hard to imagine how this could fail.
if (bpf_skb_adjust_room(skb, -(__s32)sizeof(struct frag_hdr), BPF_ADJ_ROOM_NET, /*flags*/0))
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index 88b50b5..e845a69 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -222,7 +222,7 @@
}
DEFINE_BPF_PROG_KVER("schedcls/set_dscp_ether", AID_ROOT, AID_SYSTEM, schedcls_set_dscp_ether,
- KVER(5, 15, 0))
+ KVER_5_15)
(struct __sk_buff* skb) {
if (skb->pkt_type != PACKET_HOST) return TC_ACT_PIPE;
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 0054d4a..9017976 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -59,18 +59,18 @@
#define TCP_FLAG8_OFF (TCP_FLAG32_OFF + 1)
// For maps netd does not need to access
-#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
- AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
- LOAD_ON_USER, LOAD_ON_USERDEBUG)
+#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
+ AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", \
+ PRIVATE, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \
+ LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd only needs read only access to
-#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
- AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
- LOAD_ON_USER, LOAD_ON_USERDEBUG)
+#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
+ AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", \
+ PRIVATE, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \
+ LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd needs to be able to read and write
#define DEFINE_BPF_MAP_RW_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
@@ -89,11 +89,11 @@
DEFINE_BPF_MAP_RW_NETD(cookie_tag_map, HASH, uint64_t, UidTagValue, COOKIE_UID_MAP_SIZE)
DEFINE_BPF_MAP_NO_NETD(uid_counterset_map, HASH, uint32_t, uint8_t, UID_COUNTERSET_MAP_SIZE)
DEFINE_BPF_MAP_NO_NETD(app_uid_stats_map, HASH, uint32_t, StatsValue, APP_STATS_MAP_SIZE)
-DEFINE_BPF_MAP_RW_NETD(stats_map_A, HASH, StatsKey, StatsValue, STATS_MAP_SIZE)
+DEFINE_BPF_MAP_RO_NETD(stats_map_A, HASH, StatsKey, StatsValue, STATS_MAP_SIZE)
DEFINE_BPF_MAP_RO_NETD(stats_map_B, HASH, StatsKey, StatsValue, STATS_MAP_SIZE)
DEFINE_BPF_MAP_NO_NETD(iface_stats_map, HASH, uint32_t, StatsValue, IFACE_STATS_MAP_SIZE)
DEFINE_BPF_MAP_NO_NETD(uid_owner_map, HASH, uint32_t, UidOwnerValue, UID_OWNER_MAP_SIZE)
-DEFINE_BPF_MAP_RW_NETD(uid_permission_map, HASH, uint32_t, uint8_t, UID_OWNER_MAP_SIZE)
+DEFINE_BPF_MAP_RO_NETD(uid_permission_map, HASH, uint32_t, uint8_t, UID_OWNER_MAP_SIZE)
DEFINE_BPF_MAP_NO_NETD(ingress_discard_map, HASH, IngressDiscardKey, IngressDiscardValue,
INGRESS_DISCARD_MAP_SIZE)
@@ -102,16 +102,15 @@
// A single-element configuration array, packet tracing is enabled when 'true'.
DEFINE_BPF_MAP_EXT(packet_trace_enabled_map, ARRAY, uint32_t, bool, 1,
- AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
+ AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
- IGNORE_ON_USER, LOAD_ON_USERDEBUG)
+ LOAD_ON_USER, LOAD_ON_USERDEBUG)
-// A ring buffer on which packet information is pushed. This map will only be loaded
-// on eng and userdebug devices. User devices won't load this to save memory.
+// A ring buffer on which packet information is pushed.
DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE,
- AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
+ AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
- IGNORE_ON_USER, LOAD_ON_USERDEBUG);
+ LOAD_ON_USER, LOAD_ON_USERDEBUG);
// iptables xt_bpf programs need to be usable by both netd and netutils_wrappers
// selinux contexts, because even non-xt_bpf iptables mutations are implemented as
@@ -128,8 +127,8 @@
// which is loaded into netd and thus runs as netd uid/gid/selinux context)
#define DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, maxKV) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
- minKV, maxKV, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, \
- "fs_bpf_netd_readonly", "", false, false, false)
+ minKV, maxKV, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
+ "fs_bpf_netd_readonly", "", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
#define DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF)
@@ -140,8 +139,8 @@
// programs that only need to be usable by the system server
#define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, "fs_bpf_net_shared", \
- "", false, false, false)
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
+ "fs_bpf_net_shared", "", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
static __always_inline int is_system_uid(uint32_t uid) {
// MIN_SYSTEM_UID is AID_ROOT == 0, so uint32_t is *always* >= 0
@@ -179,8 +178,8 @@
#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey) \
static __always_inline inline void update_##the_stats_map(const struct __sk_buff* const skb, \
const TypeOfKey* const key, \
- const bool egress, \
- const unsigned kver) { \
+ const struct egress_bool egress, \
+ const struct kver_uint kver) { \
StatsValue* value = bpf_##the_stats_map##_lookup_elem(key); \
if (!value) { \
StatsValue newValue = {}; \
@@ -200,7 +199,7 @@
packets = (payload + mss - 1) / mss; \
bytes = tcp_overhead * packets + payload; \
} \
- if (egress) { \
+ if (egress.egress) { \
__sync_fetch_and_add(&value->txPackets, packets); \
__sync_fetch_and_add(&value->txBytes, bytes); \
} else { \
@@ -220,7 +219,7 @@
const int L3_off,
void* const to,
const int len,
- const unsigned kver) {
+ const struct kver_uint kver) {
// 'kver' (here and throughout) is the compile time guaranteed minimum kernel version,
// ie. we're building (a version of) the bpf program for kver (or newer!) kernels.
//
@@ -237,16 +236,16 @@
//
// For similar reasons this will fail with non-offloaded VLAN tags on < 4.19 kernels,
// since those extend the ethernet header from 14 to 18 bytes.
- return kver >= KVER(4, 19, 0)
+ return KVER_IS_AT_LEAST(kver, 4, 19, 0)
? bpf_skb_load_bytes_relative(skb, L3_off, to, len, BPF_HDR_START_NET)
: bpf_skb_load_bytes(skb, L3_off, to, len);
}
static __always_inline inline void do_packet_tracing(
- const struct __sk_buff* const skb, const bool egress, const uint32_t uid,
- const uint32_t tag, const bool enable_tracing, const unsigned kver) {
+ const struct __sk_buff* const skb, const struct egress_bool egress, const uint32_t uid,
+ const uint32_t tag, const bool enable_tracing, const struct kver_uint kver) {
if (!enable_tracing) return;
- if (kver < KVER(5, 8, 0)) return;
+ if (!KVER_IS_AT_LEAST(kver, 5, 8, 0)) return;
uint32_t mapKey = 0;
bool* traceConfig = bpf_packet_trace_enabled_map_lookup_elem(&mapKey);
@@ -318,8 +317,8 @@
pkt->sport = sport;
pkt->dport = dport;
- pkt->egress = egress;
- pkt->wakeup = !egress && (skb->mark & 0x80000000); // Fwmark.ingress_cpu_wakeup
+ pkt->egress = egress.egress;
+ pkt->wakeup = !egress.egress && (skb->mark & 0x80000000); // Fwmark.ingress_cpu_wakeup
pkt->ipProto = proto;
pkt->tcpFlags = flags;
pkt->ipVersion = ipVersion;
@@ -327,8 +326,9 @@
bpf_packet_trace_ringbuf_submit(pkt);
}
-static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool egress,
- const unsigned kver) {
+static __always_inline inline bool skip_owner_match(struct __sk_buff* skb,
+ const struct egress_bool egress,
+ const struct kver_uint kver) {
uint32_t flag = 0;
if (skb->protocol == htons(ETH_P_IP)) {
uint8_t proto;
@@ -359,7 +359,7 @@
return false;
}
// Always allow RST's, and additionally allow ingress FINs
- return flag & (TCP_FLAG_RST | (egress ? 0 : TCP_FLAG_FIN)); // false on read failure
+ return flag & (TCP_FLAG_RST | (egress.egress ? 0 : TCP_FLAG_FIN)); // false on read failure
}
static __always_inline inline BpfConfig getConfig(uint32_t configKey) {
@@ -373,11 +373,11 @@
}
static __always_inline inline bool ingress_should_discard(struct __sk_buff* skb,
- const unsigned kver) {
+ const struct kver_uint kver) {
// Require 4.19, since earlier kernels don't have bpf_skb_load_bytes_relative() which
// provides relative to L3 header reads. Without that we could fetch the wrong bytes.
// Additionally earlier bpf verifiers are much harder to please.
- if (kver < KVER(4, 19, 0)) return false;
+ if (!KVER_IS_AT_LEAST(kver, 4, 19, 0)) return false;
IngressDiscardKey k = {};
if (skb->protocol == htons(ETH_P_IP)) {
@@ -402,7 +402,8 @@
}
static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
- bool egress, const unsigned kver) {
+ const struct egress_bool egress,
+ const struct kver_uint kver) {
if (is_system_uid(uid)) return PASS;
if (skip_owner_match(skb, egress, kver)) return PASS;
@@ -415,7 +416,7 @@
if (isBlockedByUidRules(enabledRules, uidRules)) return DROP;
- if (!egress && skb->ifindex != 1) {
+ if (!egress.egress && skb->ifindex != 1) {
if (ingress_should_discard(skb, kver)) return DROP;
if (uidRules & IIF_MATCH) {
if (allowed_iif && skb->ifindex != allowed_iif) {
@@ -435,8 +436,8 @@
static __always_inline inline void update_stats_with_config(const uint32_t selectedMap,
const struct __sk_buff* const skb,
const StatsKey* const key,
- const bool egress,
- const unsigned kver) {
+ const struct egress_bool egress,
+ const struct kver_uint kver) {
if (selectedMap == SELECT_MAP_A) {
update_stats_map_A(skb, key, egress, kver);
} else {
@@ -444,9 +445,10 @@
}
}
-static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, bool egress,
+static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb,
+ const struct egress_bool egress,
const bool enable_tracing,
- const unsigned kver) {
+ const struct kver_uint kver) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
uint64_t cookie = bpf_get_socket_cookie(skb);
UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
@@ -463,7 +465,7 @@
// interface is accounted for and subject to usage restrictions.
// CLAT IPv6 TX sockets are *always* tagged with CLAT uid, see tagSocketAsClat()
// CLAT daemon receives via an untagged AF_PACKET socket.
- if (egress && uid == AID_CLAT) return PASS;
+ if (egress.egress && uid == AID_CLAT) return PASS;
int match = bpf_owner_match(skb, sock_uid, egress, kver);
@@ -479,7 +481,7 @@
}
// If an outbound packet is going to be dropped, we do not count that traffic.
- if (egress && (match == DROP)) return DROP;
+ if (egress.egress && (match == DROP)) return DROP;
StatsKey key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex};
@@ -504,42 +506,66 @@
return match;
}
-DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_ingress_trace, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false,
- "fs_bpf_netd_readonly", "", false, true, false)
+// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
+DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace_user", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_ingress_trace_user, KVER_5_8, KVER_INF,
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ "fs_bpf_netd_readonly", "",
+ IGNORE_ON_ENG, LOAD_ON_USER, IGNORE_ON_USERDEBUG)
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER(5, 8, 0));
+ return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER_5_8);
+}
+
+// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
+DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_ingress_trace, KVER_5_8, KVER_INF,
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
+(struct __sk_buff* skb) {
+ return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER_5_8);
}
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_19", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_ingress_4_19, KVER(4, 19, 0), KVER_INF)
+ bpf_cgroup_ingress_4_19, KVER_4_19, KVER_INF)
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, INGRESS, TRACE_OFF, KVER(4, 19, 0));
+ return bpf_traffic_account(skb, INGRESS, TRACE_OFF, KVER_4_19);
}
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_14", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_ingress_4_14, KVER_NONE, KVER(4, 19, 0))
+ bpf_cgroup_ingress_4_14, KVER_NONE, KVER_4_19)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, INGRESS, TRACE_OFF, KVER_NONE);
}
-DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_egress_trace, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false,
- "fs_bpf_netd_readonly", "", false, true, false)
+// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
+DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace_user", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_egress_trace_user, KVER_5_8, KVER_INF,
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER(5, 8, 0));
+ return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER_5_8);
+}
+
+// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
+DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_egress_trace, KVER_5_8, KVER_INF,
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
+(struct __sk_buff* skb) {
+ return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER_5_8);
}
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_19", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_egress_4_19, KVER(4, 19, 0), KVER_INF)
+ bpf_cgroup_egress_4_19, KVER_4_19, KVER_INF)
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, EGRESS, TRACE_OFF, KVER(4, 19, 0));
+ return bpf_traffic_account(skb, EGRESS, TRACE_OFF, KVER_4_19);
}
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_14", AID_ROOT, AID_SYSTEM,
- bpf_cgroup_egress_4_14, KVER_NONE, KVER(4, 19, 0))
+ bpf_cgroup_egress_4_14, KVER_NONE, KVER_4_19)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, EGRESS, TRACE_OFF, KVER_NONE);
}
@@ -614,9 +640,7 @@
return BPF_NOMATCH;
}
-DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
- KVER(4, 14, 0))
-(struct bpf_sock* sk) {
+static __always_inline inline uint8_t get_app_permissions() {
uint64_t gid_uid = bpf_get_current_uid_gid();
/*
* A given app is guaranteed to have the same app ID in all the profiles in
@@ -626,13 +650,15 @@
*/
uint32_t appId = (gid_uid & 0xffffffff) % AID_USER_OFFSET; // == PER_USER_RANGE == 100000
uint8_t* permissions = bpf_uid_permission_map_lookup_elem(&appId);
- if (!permissions) {
- // UID not in map. Default to just INTERNET permission.
- return 1;
- }
+ // if UID not in map, then default to just INTERNET permission.
+ return permissions ? *permissions : BPF_PERMISSION_INTERNET;
+}
+DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
+ KVER_4_14)
+(struct bpf_sock* sk) {
// A return value of 1 means allow, everything else means deny.
- return (*permissions & BPF_PERMISSION_INTERNET) == BPF_PERMISSION_INTERNET;
+ return (get_app_permissions() & BPF_PERMISSION_INTERNET) ? 1 : 0;
}
LICENSE("Apache 2.0");
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index c752779..35b8eea 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -124,8 +124,12 @@
DEFINE_BPF_MAP_GRW(tether_upstream6_map, HASH, TetherUpstream6Key, Tether6Value, 64,
TETHERING_GID)
-static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet,
- const bool downstream, const unsigned kver) {
+static inline __always_inline int do_forward6(struct __sk_buff* skb,
+ const struct rawip_bool rawip,
+ const struct stream_bool stream,
+ const struct kver_uint kver) {
+ const bool is_ethernet = !rawip.rawip;
+
// Must be meta-ethernet IPv6 frame
if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_PIPE;
@@ -184,7 +188,7 @@
TC_PUNT(NON_GLOBAL_DST);
// In the upstream direction do not forward traffic within the same /64 subnet.
- if (!downstream && (src32 == dst32) && (ip6->saddr.s6_addr32[1] == ip6->daddr.s6_addr32[1]))
+ if (!stream.down && (src32 == dst32) && (ip6->saddr.s6_addr32[1] == ip6->daddr.s6_addr32[1]))
TC_PUNT(LOCAL_SRC_DST);
TetherDownstream6Key kd = {
@@ -196,15 +200,15 @@
.iif = skb->ifindex,
.src64 = 0,
};
- if (is_ethernet) __builtin_memcpy(downstream ? kd.dstMac : ku.dstMac, eth->h_dest, ETH_ALEN);
+ if (is_ethernet) __builtin_memcpy(stream.down ? kd.dstMac : ku.dstMac, eth->h_dest, ETH_ALEN);
- Tether6Value* v = downstream ? bpf_tether_downstream6_map_lookup_elem(&kd)
- : bpf_tether_upstream6_map_lookup_elem(&ku);
+ Tether6Value* v = stream.down ? bpf_tether_downstream6_map_lookup_elem(&kd)
+ : bpf_tether_upstream6_map_lookup_elem(&ku);
// If we don't find any offload information then simply let the core stack handle it...
if (!v) return TC_ACT_PIPE;
- uint32_t stat_and_limit_k = downstream ? skb->ifindex : v->oif;
+ uint32_t stat_and_limit_k = stream.down ? skb->ifindex : v->oif;
TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
@@ -249,7 +253,7 @@
// We do this even if TX interface is RAWIP and thus does not need an ethernet header,
// because this is easier and the kernel will strip extraneous ethernet header.
if (bpf_skb_change_head(skb, sizeof(struct ethhdr), /*flags*/ 0)) {
- __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxErrors : &stat_v->txErrors, 1);
TC_PUNT(CHANGE_HEAD_FAILED);
}
@@ -261,7 +265,7 @@
// I do not believe this can ever happen, but keep the verifier happy...
if (data + sizeof(struct ethhdr) + sizeof(*ip6) > data_end) {
- __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxErrors : &stat_v->txErrors, 1);
TC_DROP(TOO_SHORT);
}
};
@@ -281,8 +285,8 @@
// (-ENOTSUPP) if it isn't.
bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
- __sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets);
- __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxPackets : &stat_v->txPackets, packets);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
// Overwrite any mac header with the new one
// For a rawip tx interface it will simply be a bunch of zeroes and later stripped.
@@ -324,26 +328,26 @@
//
// Hence, these mandatory (must load successfully) implementations for 4.14+ kernels:
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream6_rawip_4_14, KVER(4, 14, 0))
+ sched_cls_tether_downstream6_rawip_4_14, KVER_4_14)
(struct __sk_buff* skb) {
- return do_forward6(skb, RAWIP, DOWNSTREAM, KVER(4, 14, 0));
+ return do_forward6(skb, RAWIP, DOWNSTREAM, KVER_4_14);
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream6_rawip_4_14, KVER(4, 14, 0))
+ sched_cls_tether_upstream6_rawip_4_14, KVER_4_14)
(struct __sk_buff* skb) {
- return do_forward6(skb, RAWIP, UPSTREAM, KVER(4, 14, 0));
+ return do_forward6(skb, RAWIP, UPSTREAM, KVER_4_14);
}
// and define no-op stubs for pre-4.14 kernels.
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream6_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream6_rawip_stub, KVER_NONE, KVER(4, 14, 0))
+ sched_cls_tether_downstream6_rawip_stub, KVER_NONE, KVER_4_14)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream6_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream6_rawip_stub, KVER_NONE, KVER(4, 14, 0))
+ sched_cls_tether_upstream6_rawip_stub, KVER_NONE, KVER_4_14)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
@@ -356,9 +360,10 @@
static inline __always_inline int do_forward4_bottom(struct __sk_buff* skb,
const int l2_header_size, void* data, const void* data_end,
- struct ethhdr* eth, struct iphdr* ip, const bool is_ethernet,
- const bool downstream, const bool updatetime, const bool is_tcp,
- const unsigned kver) {
+ struct ethhdr* eth, struct iphdr* ip, const struct rawip_bool rawip,
+ const struct stream_bool stream, const struct updatetime_bool updatetime,
+ const bool is_tcp, const struct kver_uint kver) {
+ const bool is_ethernet = !rawip.rawip;
struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL;
struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1);
@@ -416,13 +421,13 @@
};
if (is_ethernet) __builtin_memcpy(k.dstMac, eth->h_dest, ETH_ALEN);
- Tether4Value* v = downstream ? bpf_tether_downstream4_map_lookup_elem(&k)
- : bpf_tether_upstream4_map_lookup_elem(&k);
+ Tether4Value* v = stream.down ? bpf_tether_downstream4_map_lookup_elem(&k)
+ : bpf_tether_upstream4_map_lookup_elem(&k);
// If we don't find any offload information then simply let the core stack handle it...
if (!v) return TC_ACT_PIPE;
- uint32_t stat_and_limit_k = downstream ? skb->ifindex : v->oif;
+ uint32_t stat_and_limit_k = stream.down ? skb->ifindex : v->oif;
TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
@@ -467,7 +472,7 @@
// We do this even if TX interface is RAWIP and thus does not need an ethernet header,
// because this is easier and the kernel will strip extraneous ethernet header.
if (bpf_skb_change_head(skb, sizeof(struct ethhdr), /*flags*/ 0)) {
- __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxErrors : &stat_v->txErrors, 1);
TC_PUNT(CHANGE_HEAD_FAILED);
}
@@ -481,7 +486,7 @@
// I do not believe this can ever happen, but keep the verifier happy...
if (data + sizeof(struct ethhdr) + sizeof(*ip) + (is_tcp ? sizeof(*tcph) : sizeof(*udph)) > data_end) {
- __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxErrors : &stat_v->txErrors, 1);
TC_DROP(TOO_SHORT);
}
};
@@ -533,10 +538,10 @@
// This requires the bpf_ktime_get_boot_ns() helper which was added in 5.8,
// and backported to all Android Common Kernel 4.14+ trees.
- if (updatetime) v->last_used = bpf_ktime_get_boot_ns();
+ if (updatetime.updatetime) v->last_used = bpf_ktime_get_boot_ns();
- __sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets);
- __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxPackets : &stat_v->txPackets, packets);
+ __sync_fetch_and_add(stream.down ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
// Redirect to forwarded interface.
//
@@ -547,8 +552,13 @@
return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
}
-static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet,
- const bool downstream, const bool updatetime, const unsigned kver) {
+static inline __always_inline int do_forward4(struct __sk_buff* skb,
+ const struct rawip_bool rawip,
+ const struct stream_bool stream,
+ const struct updatetime_bool updatetime,
+ const struct kver_uint kver) {
+ const bool is_ethernet = !rawip.rawip;
+
// Require ethernet dst mac address to be our unicast address.
if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
@@ -606,16 +616,16 @@
// in such a situation we can only support TCP. This also has the added nice benefit of
// using a separate error counter, and thus making it obvious which version of the program
// is loaded.
- if (!updatetime && ip->protocol != IPPROTO_TCP) TC_PUNT(NON_TCP);
+ if (!updatetime.updatetime && ip->protocol != IPPROTO_TCP) TC_PUNT(NON_TCP);
// We do not support offloading anything besides IPv4 TCP and UDP, due to need for NAT,
// but no need to check this if !updatetime due to check immediately above.
- if (updatetime && (ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP))
+ if (updatetime.updatetime && (ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP))
TC_PUNT(NON_TCP_UDP);
// We want to make sure that the compiler will, in the !updatetime case, entirely optimize
// out all the non-tcp logic. Also note that at this point is_udp === !is_tcp.
- const bool is_tcp = !updatetime || (ip->protocol == IPPROTO_TCP);
+ const bool is_tcp = !updatetime.updatetime || (ip->protocol == IPPROTO_TCP);
// This is a bit of a hack to make things easier on the bpf verifier.
// (In particular I believe the Linux 4.14 kernel's verifier can get confused later on about
@@ -636,37 +646,37 @@
// if the underlying requisite kernel support (bpf_ktime_get_boot_ns) was backported.
if (is_tcp) {
return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
- is_ethernet, downstream, updatetime, /* is_tcp */ true, kver);
+ rawip, stream, updatetime, /* is_tcp */ true, kver);
} else {
return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
- is_ethernet, downstream, updatetime, /* is_tcp */ false, kver);
+ rawip, stream, updatetime, /* is_tcp */ false, kver);
}
}
// Full featured (required) implementations for 5.8+ kernels (these are S+ by definition)
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_rawip$5_8", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_rawip_5_8, KVER(5, 8, 0))
+ sched_cls_tether_downstream4_rawip_5_8, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0));
+ return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER_5_8);
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_rawip$5_8", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_rawip_5_8, KVER(5, 8, 0))
+ sched_cls_tether_upstream4_rawip_5_8, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(5, 8, 0));
+ return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER_5_8);
}
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_ether$5_8", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_ether_5_8, KVER(5, 8, 0))
+ sched_cls_tether_downstream4_ether_5_8, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0));
+ return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER_5_8);
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_ether$5_8", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_ether_5_8, KVER(5, 8, 0))
+ sched_cls_tether_upstream4_ether_5_8, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(5, 8, 0));
+ return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER_5_8);
}
// Full featured (optional) implementations for 4.14-S, 4.19-S & 5.4-S kernels
@@ -675,33 +685,33 @@
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$opt",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_rawip_opt,
- KVER(4, 14, 0), KVER(5, 8, 0))
+ KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER_4_14);
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$opt",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_rawip_opt,
- KVER(4, 14, 0), KVER(5, 8, 0))
+ KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER_4_14);
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$opt",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_ether_opt,
- KVER(4, 14, 0), KVER(5, 8, 0))
+ KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER_4_14);
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$opt",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_ether_opt,
- KVER(4, 14, 0), KVER(5, 8, 0))
+ KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER_4_14);
}
// Partial (TCP-only: will not update 'last_used' field) implementations for 4.14+ kernels.
@@ -719,15 +729,15 @@
// RAWIP: Required for 5.4-R kernels -- which always support bpf_skb_change_head().
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$5_4", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0))
+ sched_cls_tether_downstream4_rawip_5_4, KVER_5_4, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(5, 4, 0));
+ return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER_5_4);
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$5_4", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0))
+ sched_cls_tether_upstream4_rawip_5_4, KVER_5_4, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(5, 4, 0));
+ return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER_5_4);
}
// RAWIP: Optional for 4.14/4.19 (R) kernels -- which support bpf_skb_change_head().
@@ -736,31 +746,31 @@
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$4_14",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_rawip_4_14,
- KVER(4, 14, 0), KVER(5, 4, 0))
+ KVER_4_14, KVER_5_4)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER_4_14);
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$4_14",
TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_rawip_4_14,
- KVER(4, 14, 0), KVER(5, 4, 0))
+ KVER_4_14, KVER_5_4)
(struct __sk_buff* skb) {
- return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER_4_14);
}
// ETHER: Required for 4.14-Q/R, 4.19-Q/R & 5.4-R kernels.
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$4_14", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0))
+ sched_cls_tether_downstream4_ether_4_14, KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, ETHER, DOWNSTREAM, NO_UPDATETIME, KVER_4_14);
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$4_14", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0))
+ sched_cls_tether_upstream4_ether_4_14, KVER_4_14, KVER_5_8)
(struct __sk_buff* skb) {
- return do_forward4(skb, ETHER, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
+ return do_forward4(skb, ETHER, UPSTREAM, NO_UPDATETIME, KVER_4_14);
}
// Placeholder (no-op) implementations for older Q kernels
@@ -768,13 +778,13 @@
// RAWIP: 4.9-P/Q, 4.14-P/Q & 4.19-Q kernels -- without bpf_skb_change_head() for tc programs
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+ sched_cls_tether_downstream4_rawip_stub, KVER_NONE, KVER_5_4)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+ sched_cls_tether_upstream4_rawip_stub, KVER_NONE, KVER_5_4)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
@@ -782,13 +792,13 @@
// ETHER: 4.9-P/Q kernel
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream4_ether_stub, KVER_NONE, KVER(4, 14, 0))
+ sched_cls_tether_downstream4_ether_stub, KVER_NONE, KVER_4_14)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream4_ether_stub, KVER_NONE, KVER(4, 14, 0))
+ sched_cls_tether_upstream4_ether_stub, KVER_NONE, KVER_4_14)
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
@@ -797,17 +807,18 @@
DEFINE_BPF_MAP_GRW(tether_dev_map, DEVMAP_HASH, uint32_t, uint32_t, 64, TETHERING_GID)
-static inline __always_inline int do_xdp_forward6(struct xdp_md *ctx, const bool is_ethernet,
- const bool downstream) {
+static inline __always_inline int do_xdp_forward6(struct xdp_md *ctx, const struct rawip_bool rawip,
+ const struct stream_bool stream) {
return XDP_PASS;
}
-static inline __always_inline int do_xdp_forward4(struct xdp_md *ctx, const bool is_ethernet,
- const bool downstream) {
+static inline __always_inline int do_xdp_forward4(struct xdp_md *ctx, const struct rawip_bool rawip,
+ const struct stream_bool stream) {
return XDP_PASS;
}
-static inline __always_inline int do_xdp_forward_ether(struct xdp_md *ctx, const bool downstream) {
+static inline __always_inline int do_xdp_forward_ether(struct xdp_md *ctx,
+ const struct stream_bool stream) {
const void* data = (void*)(long)ctx->data;
const void* data_end = (void*)(long)ctx->data_end;
const struct ethhdr* eth = data;
@@ -816,15 +827,16 @@
if ((void*)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto == htons(ETH_P_IPV6))
- return do_xdp_forward6(ctx, ETHER, downstream);
+ return do_xdp_forward6(ctx, ETHER, stream);
if (eth->h_proto == htons(ETH_P_IP))
- return do_xdp_forward4(ctx, ETHER, downstream);
+ return do_xdp_forward4(ctx, ETHER, stream);
// Anything else we don't know how to handle...
return XDP_PASS;
}
-static inline __always_inline int do_xdp_forward_rawip(struct xdp_md *ctx, const bool downstream) {
+static inline __always_inline int do_xdp_forward_rawip(struct xdp_md *ctx,
+ const struct stream_bool stream) {
const void* data = (void*)(long)ctx->data;
const void* data_end = (void*)(long)ctx->data_end;
@@ -832,15 +844,15 @@
if (data_end - data < 1) return XDP_PASS;
const uint8_t v = (*(uint8_t*)data) >> 4;
- if (v == 6) return do_xdp_forward6(ctx, RAWIP, downstream);
- if (v == 4) return do_xdp_forward4(ctx, RAWIP, downstream);
+ if (v == 6) return do_xdp_forward6(ctx, RAWIP, stream);
+ if (v == 4) return do_xdp_forward4(ctx, RAWIP, stream);
// Anything else we don't know how to handle...
return XDP_PASS;
}
#define DEFINE_XDP_PROG(str, func) \
- DEFINE_BPF_PROG_KVER(str, TETHERING_UID, TETHERING_GID, func, KVER(5, 9, 0))(struct xdp_md *ctx)
+ DEFINE_BPF_PROG_KVER(str, TETHERING_UID, TETHERING_GID, func, KVER_5_9)(struct xdp_md *ctx)
DEFINE_XDP_PROG("xdp/tether_downstream_ether",
xdp_tether_downstream_ether) {
diff --git a/bpf_progs/test.c b/bpf_progs/test.c
index 68469c8..70b08b7 100644
--- a/bpf_progs/test.c
+++ b/bpf_progs/test.c
@@ -49,7 +49,7 @@
DEFINE_BPF_MAP_GRW(bitmap, ARRAY, int, uint64_t, 2, TETHERING_GID)
DEFINE_BPF_PROG_KVER("xdp/drop_ipv4_udp_ether", TETHERING_UID, TETHERING_GID,
- xdp_test, KVER(5, 9, 0))
+ xdp_test, KVER_5_9)
(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
diff --git a/common/Android.bp b/common/Android.bp
index ff4de11..e10ede8 100644
--- a/common/Android.bp
+++ b/common/Android.bp
@@ -19,6 +19,10 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+// This is a placeholder comment to avoid merge conflicts
+// as the above target may not exist
+// depending on the branch
+
java_library {
name: "connectivity-net-module-utils-bpf",
srcs: [
diff --git a/common/flags.aconfig b/common/flags.aconfig
new file mode 100644
index 0000000..4926503
--- /dev/null
+++ b/common/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.net.flags"
+
+flag {
+ name: "track_multiple_network_activities"
+ namespace: "android_core_networking"
+ description: "NetworkActivityTracker tracks multiple networks including non default networks"
+ bug: "267870186"
+}
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index b8a0e39..2f7db87 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -51,7 +51,7 @@
":framework-connectivity-tiramisu-updatable-sources",
":framework-nearby-java-sources",
":framework-thread-sources",
- ] + framework_remoteauth_srcs,
+ ],
libs: [
"unsupportedappusage",
"app-compat-annotations",
@@ -126,7 +126,6 @@
"enable-framework-connectivity-t-targets",
"FlaggedApiDefaults",
],
- api_srcs: framework_remoteauth_api_srcs,
// Do not add static_libs to this library: put them in framework-connectivity instead.
// The jarjar rules are only so that references to jarjared utils in
// framework-connectivity-pre-jarjar match at runtime.
@@ -143,10 +142,8 @@
"android.net",
"android.net.nsd",
"android.nearby",
- "android.remoteauth",
"com.android.connectivity",
"com.android.nearby",
- "com.android.remoteauth",
],
hidden_api: {
diff --git a/framework-t/api/OWNERS b/framework-t/api/OWNERS
index af583c3..607f85a 100644
--- a/framework-t/api/OWNERS
+++ b/framework-t/api/OWNERS
@@ -1,2 +1,2 @@
-file:platform/packages/modules/Connectivity:master:/nearby/OWNERS
-file:platform/packages/modules/Connectivity:master:/remoteauth/OWNERS
+file:platform/packages/modules/Connectivity:main:/nearby/OWNERS
+file:platform/packages/modules/Connectivity:main:/remoteauth/OWNERS
diff --git a/framework-t/udc-extended-api/OWNERS b/framework-t/udc-extended-api/OWNERS
index af583c3..607f85a 100644
--- a/framework-t/udc-extended-api/OWNERS
+++ b/framework-t/udc-extended-api/OWNERS
@@ -1,2 +1,2 @@
-file:platform/packages/modules/Connectivity:master:/nearby/OWNERS
-file:platform/packages/modules/Connectivity:master:/remoteauth/OWNERS
+file:platform/packages/modules/Connectivity:main:/nearby/OWNERS
+file:platform/packages/modules/Connectivity:main:/remoteauth/OWNERS
diff --git a/framework/cronet_disabled/api/current.txt b/framework/cronet_disabled/api/current.txt
deleted file mode 100644
index 672e3e2..0000000
--- a/framework/cronet_disabled/api/current.txt
+++ /dev/null
@@ -1,527 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class CaptivePortal implements android.os.Parcelable {
- method public int describeContents();
- method public void ignoreNetwork();
- method public void reportCaptivePortalDismissed();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
- }
-
- public class ConnectivityDiagnosticsManager {
- method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- }
-
- public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
- ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
- method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
- method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
- method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
- }
-
- public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method @NonNull public android.os.PersistableBundle getAdditionalInfo();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
- field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
- field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
- field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
- field public static final int NETWORK_PROBE_DNS = 4; // 0x4
- field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
- field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
- field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
- field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
- field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
- field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
- field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
- field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
- }
-
- public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method public int getDetectionMethod();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method @NonNull public android.os.PersistableBundle getStallDetails();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
- field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
- field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
- field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
- field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
- field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
- }
-
- public class ConnectivityManager {
- method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- 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 @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 @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
- method @Deprecated public boolean getBackgroundDataSetting();
- method @Nullable public android.net.Network getBoundNetworkForProcess();
- method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
- method @Nullable public android.net.ProxyInfo getDefaultProxy();
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
- method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
- method @Nullable public byte[] getNetworkWatchlistConfigHash();
- method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
- method public int getRestrictBackgroundStatus();
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
- method public boolean isDefaultNetworkActive();
- method @Deprecated public static boolean isNetworkTypeValid(int);
- method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
- method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
- method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
- method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
- method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method @Deprecated public void setNetworkPreference(int);
- method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
- method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
- field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
- field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
- field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
- field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
- field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
- field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
- field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
- field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
- field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
- field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
- field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
- field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
- field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
- field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
- field public static final String EXTRA_REASON = "reason";
- field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
- field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
- field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
- field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
- field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
- field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
- field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
- field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
- field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
- field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
- field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
- field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
- field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
- field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
- field @Deprecated public static final int TYPE_VPN = 17; // 0x11
- field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
- field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
- }
-
- public static class ConnectivityManager.NetworkCallback {
- ctor public ConnectivityManager.NetworkCallback();
- ctor public ConnectivityManager.NetworkCallback(int);
- method public void onAvailable(@NonNull android.net.Network);
- method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
- method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
- method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
- method public void onLosing(@NonNull android.net.Network, int);
- method public void onLost(@NonNull android.net.Network);
- method public void onUnavailable();
- field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
- }
-
- public static interface ConnectivityManager.OnNetworkActiveListener {
- method public void onNetworkActive();
- }
-
- public class DhcpInfo implements android.os.Parcelable {
- ctor public DhcpInfo();
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
- field public int dns1;
- field public int dns2;
- field public int gateway;
- field public int ipAddress;
- field public int leaseDuration;
- field public int netmask;
- field public int serverAddress;
- }
-
- public final class DnsResolver {
- method @NonNull public static android.net.DnsResolver getInstance();
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- field public static final int CLASS_IN = 1; // 0x1
- field public static final int ERROR_PARSE = 0; // 0x0
- field public static final int ERROR_SYSTEM = 1; // 0x1
- field public static final int FLAG_EMPTY = 0; // 0x0
- field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
- field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
- field public static final int FLAG_NO_RETRY = 1; // 0x1
- field public static final int TYPE_A = 1; // 0x1
- field public static final int TYPE_AAAA = 28; // 0x1c
- }
-
- public static interface DnsResolver.Callback<T> {
- method public void onAnswer(@NonNull T, int);
- method public void onError(@NonNull android.net.DnsResolver.DnsException);
- }
-
- public static class DnsResolver.DnsException extends java.lang.Exception {
- ctor public DnsResolver.DnsException(int, @Nullable Throwable);
- field public final int code;
- }
-
- public class InetAddresses {
- method public static boolean isNumericAddress(@NonNull String);
- method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
- }
-
- public final class IpConfiguration implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
- }
-
- public static final class IpConfiguration.Builder {
- ctor public IpConfiguration.Builder();
- method @NonNull public android.net.IpConfiguration build();
- method @NonNull public android.net.IpConfiguration.Builder setHttpProxy(@Nullable android.net.ProxyInfo);
- method @NonNull public android.net.IpConfiguration.Builder setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- method public boolean contains(@NonNull java.net.InetAddress);
- method public int describeContents();
- method @NonNull public java.net.InetAddress getAddress();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method @NonNull public byte[] getRawAddress();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
- }
-
- public class LinkAddress implements android.os.Parcelable {
- method public int describeContents();
- method public java.net.InetAddress getAddress();
- method public int getFlags();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method public int getScope();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties();
- method public boolean addRoute(@NonNull android.net.RouteInfo);
- method public void clear();
- method public int describeContents();
- method @Nullable public java.net.Inet4Address getDhcpServerAddress();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @Nullable public String getInterfaceName();
- method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
- method public int getMtu();
- method @Nullable public android.net.IpPrefix getNat64Prefix();
- method @Nullable public String getPrivateDnsServerName();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
- method public boolean isPrivateDnsActive();
- method public boolean isWakeOnLanSupported();
- method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
- method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setDomains(@Nullable String);
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setInterfaceName(@Nullable String);
- method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
- method public void setMtu(int);
- method public void setNat64Prefix(@Nullable android.net.IpPrefix);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
- }
-
- public final class MacAddress implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
- method @NonNull public static android.net.MacAddress fromString(@NonNull String);
- method public int getAddressType();
- method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
- method public boolean isLocallyAssigned();
- method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
- method @NonNull public byte[] toByteArray();
- method @NonNull public String toOuiString();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.net.MacAddress BROADCAST_ADDRESS;
- field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
- field public static final int TYPE_BROADCAST = 3; // 0x3
- field public static final int TYPE_MULTICAST = 2; // 0x2
- field public static final int TYPE_UNICAST = 1; // 0x1
- }
-
- public class Network implements android.os.Parcelable {
- method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
- method public void bindSocket(java.net.Socket) throws java.io.IOException;
- method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
- method public int describeContents();
- method public static android.net.Network fromNetworkHandle(long);
- method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
- method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
- method public long getNetworkHandle();
- method public javax.net.SocketFactory getSocketFactory();
- method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
- method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities();
- ctor public NetworkCapabilities(android.net.NetworkCapabilities);
- method public int describeContents();
- method @NonNull public int[] getCapabilities();
- method @NonNull public int[] getEnterpriseIds();
- method public int getLinkDownstreamBandwidthKbps();
- method public int getLinkUpstreamBandwidthKbps();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method public int getOwnerUid();
- method public int getSignalStrength();
- method @Nullable public android.net.TransportInfo getTransportInfo();
- method public boolean hasCapability(int);
- method public boolean hasEnterpriseId(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
- field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
- field public static final int NET_CAPABILITY_CBS = 5; // 0x5
- field public static final int NET_CAPABILITY_DUN = 2; // 0x2
- field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
- field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
- field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
- field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
- field public static final int NET_CAPABILITY_HEAD_UNIT = 32; // 0x20
- field public static final int NET_CAPABILITY_IA = 7; // 0x7
- field public static final int NET_CAPABILITY_IMS = 4; // 0x4
- field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
- field public static final int NET_CAPABILITY_MCX = 23; // 0x17
- field public static final int NET_CAPABILITY_MMS = 0; // 0x0
- field public static final int NET_CAPABILITY_MMTEL = 33; // 0x21
- field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
- field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
- field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
- field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
- field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
- field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
- field public static final int NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 35; // 0x23
- field public static final int NET_CAPABILITY_PRIORITIZE_LATENCY = 34; // 0x22
- field public static final int NET_CAPABILITY_RCS = 8; // 0x8
- field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
- field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
- field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
- field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
- field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
- field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
- field public static final int NET_ENTERPRISE_ID_1 = 1; // 0x1
- field public static final int NET_ENTERPRISE_ID_2 = 2; // 0x2
- field public static final int NET_ENTERPRISE_ID_3 = 3; // 0x3
- field public static final int NET_ENTERPRISE_ID_4 = 4; // 0x4
- field public static final int NET_ENTERPRISE_ID_5 = 5; // 0x5
- field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
- field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
- field public static final int TRANSPORT_CELLULAR = 0; // 0x0
- field public static final int TRANSPORT_ETHERNET = 3; // 0x3
- field public static final int TRANSPORT_LOWPAN = 6; // 0x6
- field public static final int TRANSPORT_THREAD = 9; // 0x9
- field public static final int TRANSPORT_USB = 8; // 0x8
- field public static final int TRANSPORT_VPN = 4; // 0x4
- field public static final int TRANSPORT_WIFI = 1; // 0x1
- field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
- }
-
- @Deprecated public class NetworkInfo implements android.os.Parcelable {
- ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
- method @Deprecated public String getExtraInfo();
- method @Deprecated public String getReason();
- method @Deprecated public android.net.NetworkInfo.State getState();
- method @Deprecated public int getSubtype();
- method @Deprecated public String getSubtypeName();
- method @Deprecated public int getType();
- method @Deprecated public String getTypeName();
- method @Deprecated public boolean isAvailable();
- method @Deprecated public boolean isConnected();
- method @Deprecated public boolean isConnectedOrConnecting();
- method @Deprecated public boolean isFailover();
- method @Deprecated public boolean isRoaming();
- method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
- }
-
- @Deprecated public enum NetworkInfo.DetailedState {
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
- }
-
- @Deprecated public enum NetworkInfo.State {
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
- method public int describeContents();
- method @NonNull public int[] getCapabilities();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method @NonNull public int[] getTransportTypes();
- method public boolean hasCapability(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
- }
-
- public static class NetworkRequest.Builder {
- ctor public NetworkRequest.Builder();
- ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
- method public android.net.NetworkRequest.Builder addCapability(int);
- method public android.net.NetworkRequest.Builder addTransportType(int);
- method public android.net.NetworkRequest build();
- method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
- method public android.net.NetworkRequest.Builder removeCapability(int);
- method public android.net.NetworkRequest.Builder removeTransportType(int);
- method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean);
- method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
- method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- }
-
- public class ParseException extends java.lang.RuntimeException {
- ctor public ParseException(@NonNull String);
- ctor public ParseException(@NonNull String, @NonNull Throwable);
- field public String response;
- }
-
- public class ProxyInfo implements android.os.Parcelable {
- ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
- method public static android.net.ProxyInfo buildDirectProxy(String, int);
- method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
- method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
- method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
- method public int describeContents();
- method public String[] getExclusionList();
- method public String getHost();
- method public android.net.Uri getPacFileUrl();
- method public int getPort();
- method public boolean isValid();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.IpPrefix getDestination();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public String getInterface();
- method public int getType();
- method public boolean hasGateway();
- method public boolean isDefaultRoute();
- method public boolean matches(java.net.InetAddress);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
- field public static final int RTN_THROW = 9; // 0x9
- field public static final int RTN_UNICAST = 1; // 0x1
- field public static final int RTN_UNREACHABLE = 7; // 0x7
- }
-
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void close();
- method public final void start(@IntRange(from=0xa, to=0xe10) int);
- method public final void stop();
- field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
- field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
- field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
- field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
- field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
- }
-
- public static class SocketKeepalive.Callback {
- ctor public SocketKeepalive.Callback();
- method public void onDataReceived();
- method public void onError(int);
- method public void onStarted();
- method public void onStopped();
- }
-
- public final class StaticIpConfiguration implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public java.net.InetAddress getGateway();
- method @NonNull public android.net.LinkAddress getIpAddress();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
- }
-
- public static final class StaticIpConfiguration.Builder {
- ctor public StaticIpConfiguration.Builder();
- method @NonNull public android.net.StaticIpConfiguration build();
- method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
- method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
- method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
- method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@NonNull android.net.LinkAddress);
- }
-
- public interface TransportInfo {
- }
-
-}
-
diff --git a/framework/cronet_disabled/api/lint-baseline.txt b/framework/cronet_disabled/api/lint-baseline.txt
deleted file mode 100644
index 2f4004a..0000000
--- a/framework/cronet_disabled/api/lint-baseline.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-// Baseline format: 1.0
-VisiblySynchronized: android.net.NetworkInfo#toString():
- Internal locks must not be exposed (synchronizing on this or class is still
- externally observable): method android.net.NetworkInfo.toString()
diff --git a/framework/cronet_disabled/api/module-lib-current.txt b/framework/cronet_disabled/api/module-lib-current.txt
deleted file mode 100644
index 193bd92..0000000
--- a/framework/cronet_disabled/api/module-lib-current.txt
+++ /dev/null
@@ -1,239 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class ConnectivityFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
- public class ConnectivityManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkAllowList(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkDenyList(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
- method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
- method @Nullable public android.net.ProxyInfo getGlobalProxy();
- method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
- method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
- method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setFirewallChainEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreferences(@NonNull android.os.UserHandle, @NonNull java.util.List<android.net.ProfileNetworkPreference>, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setUidFirewallRule(int, int, int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setVpnDefaultForUids(@NonNull String, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
- method public void systemReady();
- field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
- field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
- field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
- field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
- field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
- field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
- field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
- field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
- field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
- field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
- field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
- field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
- field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
- field public static final int BLOCKED_REASON_NONE = 0; // 0x0
- field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
- field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
- field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
- field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7
- field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8
- field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9
- field public static final int FIREWALL_CHAIN_POWERSAVE = 3; // 0x3
- field public static final int FIREWALL_CHAIN_RESTRICTED = 4; // 0x4
- field public static final int FIREWALL_CHAIN_STANDBY = 2; // 0x2
- field public static final int FIREWALL_RULE_ALLOW = 1; // 0x1
- field public static final int FIREWALL_RULE_DEFAULT = 0; // 0x0
- field public static final int FIREWALL_RULE_DENY = 2; // 0x2
- field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
- field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
- field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; // 0x3
- field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2
- }
-
- public static class ConnectivityManager.NetworkCallback {
- method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
- }
-
- public class ConnectivitySettingsManager {
- method public static void clearGlobalProxy(@NonNull android.content.Context);
- method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
- method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
- method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
- method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
- method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
- method public static long getIngressRateLimitInBytesPerSecond(@NonNull android.content.Context);
- method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
- method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
- method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
- method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
- method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
- method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
- method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
- method public static int getPrivateDnsMode(@NonNull android.content.Context);
- method @NonNull public static java.util.Set<java.lang.Integer> getUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
- method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
- method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
- method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
- method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
- method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
- method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
- method public static void setIngressRateLimitInBytesPerSecond(@NonNull android.content.Context, @IntRange(from=-1L, to=4294967295L) long);
- method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
- method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
- method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
- method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
- method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
- method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
- method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
- method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
- method public static void setUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
- method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
- method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
- field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
- field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
- field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
- field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
- field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
- field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
- field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
- field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
- }
-
- public final class DhcpOption implements android.os.Parcelable {
- ctor public DhcpOption(byte, @Nullable byte[]);
- method public int describeContents();
- method public byte getType();
- method @Nullable public byte[] getValue();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpOption> CREATOR;
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method @Nullable public String getSubscriberId();
- method public boolean isBypassableVpn();
- method public boolean isVpnValidationRequired();
- }
-
- public static final class NetworkAgentConfig.Builder {
- method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLocalRoutesExcludedForVpn(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setVpnRequiresValidation(boolean);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAllowedUids();
- method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
- method public boolean hasForbiddenCapability(int);
- field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
- field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
- field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
- field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
- field public static final long REDACT_NONE = 0L; // 0x0L
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
- public static final class NetworkCapabilities.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAllowedUids(@NonNull java.util.Set<java.lang.Integer>);
- method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method @NonNull public int[] getEnterpriseIds();
- method @NonNull public int[] getForbiddenCapabilities();
- method public boolean hasEnterpriseId(int);
- method public boolean hasForbiddenCapability(int);
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull public android.net.NetworkRequest.Builder addForbiddenCapability(int);
- method @NonNull public android.net.NetworkRequest.Builder removeForbiddenCapability(int);
- method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
- }
-
- public final class ProfileNetworkPreference implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public int[] getExcludedUids();
- method @NonNull public int[] getIncludedUids();
- method public int getPreference();
- method public int getPreferenceEnterpriseId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ProfileNetworkPreference> CREATOR;
- }
-
- public static final class ProfileNetworkPreference.Builder {
- ctor public ProfileNetworkPreference.Builder();
- method @NonNull public android.net.ProfileNetworkPreference build();
- method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@NonNull int[]);
- method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@NonNull int[]);
- method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int);
- method @NonNull public android.net.ProfileNetworkPreference.Builder setPreferenceEnterpriseId(int);
- }
-
- public final class TestNetworkInterface implements android.os.Parcelable {
- ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
- method public int describeContents();
- method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
- method @NonNull public String getInterfaceName();
- method @Nullable public android.net.MacAddress getMacAddress();
- method public int getMtu();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
- }
-
- public class TestNetworkManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTapInterface();
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
- method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
- method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void teardownTestNetwork(@NonNull android.net.Network);
- field public static final String TEST_TAP_PREFIX = "testtap";
- }
-
- public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public TestNetworkSpecifier(@NonNull String);
- method public int describeContents();
- method @Nullable public String getInterfaceName();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR;
- }
-
- public interface TransportInfo {
- method public default long getApplicableRedactions();
- method @NonNull public default android.net.TransportInfo makeCopy(long);
- }
-
- public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor @Deprecated public VpnTransportInfo(int, @Nullable String);
- method @Nullable public String getSessionId();
- method @NonNull public android.net.VpnTransportInfo makeCopy(long);
- }
-
-}
-
diff --git a/framework/cronet_disabled/api/module-lib-removed.txt b/framework/cronet_disabled/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/framework/cronet_disabled/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/framework/cronet_disabled/api/removed.txt b/framework/cronet_disabled/api/removed.txt
deleted file mode 100644
index 303a1e6..0000000
--- a/framework/cronet_disabled/api/removed.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class ConnectivityManager {
- method @Deprecated public boolean requestRouteToHost(int, int);
- method @Deprecated public int startUsingNetworkFeature(int, String);
- method @Deprecated public int stopUsingNetworkFeature(int, String);
- }
-
-}
-
diff --git a/framework/cronet_disabled/api/system-current.txt b/framework/cronet_disabled/api/system-current.txt
deleted file mode 100644
index 4a2ed8a..0000000
--- a/framework/cronet_disabled/api/system-current.txt
+++ /dev/null
@@ -1,544 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class CaptivePortal implements android.os.Parcelable {
- method @Deprecated public void logEvent(int, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
- method public void useNetwork();
- field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
- field public static final int APP_RETURN_DISMISSED = 0; // 0x0
- field public static final int APP_RETURN_UNWANTED = 1; // 0x1
- field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
- }
-
- public final class CaptivePortalData implements android.os.Parcelable {
- method public int describeContents();
- method public long getByteLimit();
- method public long getExpiryTimeMillis();
- method public long getRefreshTimeMillis();
- method @Nullable public android.net.Uri getUserPortalUrl();
- method public int getUserPortalUrlSource();
- method @Nullable public CharSequence getVenueFriendlyName();
- method @Nullable public android.net.Uri getVenueInfoUrl();
- method public int getVenueInfoUrlSource();
- method public boolean isCaptive();
- method public boolean isSessionExtendable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
- }
-
- public static class CaptivePortalData.Builder {
- ctor public CaptivePortalData.Builder();
- ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
- method @NonNull public android.net.CaptivePortalData build();
- method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
- method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
- }
-
- public class ConnectivityManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void unregisterQosCallback(@NonNull android.net.QosCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
- field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
- field public static final int TYPE_NONE = -1; // 0xffffffff
- field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
- field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
- method @Deprecated public void onTetheringFailed();
- method @Deprecated public void onTetheringStarted();
- }
-
- @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method @Deprecated public void onTetheringEntitlementResult(int);
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
- method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public final class DscpPolicy implements android.os.Parcelable {
- method @Nullable public java.net.InetAddress getDestinationAddress();
- method @Nullable public android.util.Range<java.lang.Integer> getDestinationPortRange();
- method public int getDscpValue();
- method public int getPolicyId();
- method public int getProtocol();
- method @Nullable public java.net.InetAddress getSourceAddress();
- method public int getSourcePort();
- field @NonNull public static final android.os.Parcelable.Creator<android.net.DscpPolicy> CREATOR;
- field public static final int PROTOCOL_ANY = -1; // 0xffffffff
- field public static final int SOURCE_PORT_ANY = -1; // 0xffffffff
- }
-
- public static final class DscpPolicy.Builder {
- ctor public DscpPolicy.Builder(int, int);
- method @NonNull public android.net.DscpPolicy build();
- method @NonNull public android.net.DscpPolicy.Builder setDestinationAddress(@NonNull java.net.InetAddress);
- method @NonNull public android.net.DscpPolicy.Builder setDestinationPortRange(@NonNull android.util.Range<java.lang.Integer>);
- method @NonNull public android.net.DscpPolicy.Builder setProtocol(int);
- method @NonNull public android.net.DscpPolicy.Builder setSourceAddress(@NonNull java.net.InetAddress);
- method @NonNull public android.net.DscpPolicy.Builder setSourcePort(int);
- }
-
- public final class InvalidPacketException extends java.lang.Exception {
- ctor public InvalidPacketException(int);
- method public int getError();
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- }
-
- public final class IpConfiguration implements android.os.Parcelable {
- ctor public IpConfiguration();
- ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
- method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
- method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
- method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
- method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- }
-
- public enum IpConfiguration.IpAssignment {
- enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
- enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
- enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
- }
-
- public enum IpConfiguration.ProxySettings {
- enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
- enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull String);
- }
-
- public class KeepalivePacketData {
- ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method @NonNull public java.net.InetAddress getDstAddress();
- method public int getDstPort();
- method @NonNull public byte[] getPacket();
- method @NonNull public java.net.InetAddress getSrcAddress();
- method public int getSrcPort();
- }
-
- public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public LinkAddress(@NonNull String);
- ctor public LinkAddress(@NonNull String, int, int);
- method public long getDeprecationTime();
- method public long getExpirationTime();
- method public boolean isGlobalPreferred();
- method public boolean isIpv4();
- method public boolean isIpv6();
- method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
- field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
- field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties(@Nullable android.net.LinkProperties);
- ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
- method public boolean addDnsServer(@NonNull java.net.InetAddress);
- method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean addPcscfServer(@NonNull java.net.InetAddress);
- method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
- method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
- method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
- method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
- method @Nullable public android.net.Uri getCaptivePortalApiUrl();
- method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @Nullable public String getTcpBufferSizes();
- method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
- method public boolean hasGlobalIpv6Address();
- method public boolean hasIpv4Address();
- method public boolean hasIpv4DefaultRoute();
- method public boolean hasIpv4DnsServer();
- method public boolean hasIpv6DefaultRoute();
- method public boolean hasIpv6DnsServer();
- method public boolean isIpv4Provisioned();
- method public boolean isIpv6Provisioned();
- method public boolean isProvisioned();
- method public boolean isReachable(@NonNull java.net.InetAddress);
- method public boolean removeDnsServer(@NonNull java.net.InetAddress);
- method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
- method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
- method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setPrivateDnsServerName(@Nullable String);
- method public void setTcpBufferSizes(@Nullable String);
- method public void setUsePrivateDns(boolean);
- method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- }
-
- public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
- }
-
- public class Network implements android.os.Parcelable {
- ctor public Network(@NonNull android.net.Network);
- method public int getNetId();
- method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
- }
-
- public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- method @Nullable public android.net.Network getNetwork();
- method public void markConnected();
- method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
- method public void onAutomaticReconnectDisabled();
- method public void onBandwidthUpdateRequested();
- method public void onDscpPolicyStatusUpdated(int, int);
- method public void onNetworkCreated();
- method public void onNetworkDestroyed();
- method public void onNetworkUnwanted();
- method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
- method public void onQosCallbackUnregistered(int);
- method public void onRemoveKeepalivePacketFilter(int);
- method public void onSaveAcceptUnvalidated(boolean);
- method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
- method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
- method public void onStopSocketKeepalive(int);
- method public void onValidationStatus(int, @Nullable android.net.Uri);
- method @NonNull public android.net.Network register();
- method public void sendAddDscpPolicy(@NonNull android.net.DscpPolicy);
- method public void sendLinkProperties(@NonNull android.net.LinkProperties);
- method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public void sendNetworkScore(@NonNull android.net.NetworkScore);
- method public void sendNetworkScore(@IntRange(from=0, to=99) int);
- method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
- method public final void sendQosSessionLost(int, int, int);
- method public void sendRemoveAllDscpPolicies();
- method public void sendRemoveDscpPolicy(int);
- method public final void sendSocketKeepaliveEvent(int, int);
- method @Deprecated public void setLegacySubtype(int, @NonNull String);
- method public void setLingerDuration(@NonNull java.time.Duration);
- method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int);
- method public void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
- method public void unregister();
- method public void unregisterAfterReplacement(@IntRange(from=0, to=0x1388) int);
- field public static final int DSCP_POLICY_STATUS_DELETED = 4; // 0x4
- field public static final int DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES = 3; // 0x3
- field public static final int DSCP_POLICY_STATUS_POLICY_NOT_FOUND = 5; // 0x5
- field public static final int DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED = 2; // 0x2
- field public static final int DSCP_POLICY_STATUS_REQUEST_DECLINED = 1; // 0x1
- field public static final int DSCP_POLICY_STATUS_SUCCESS = 0; // 0x0
- field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
- field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getLegacyType();
- method @NonNull public String getLegacyTypeName();
- method public boolean isExplicitlySelected();
- method public boolean isPartialConnectivityAcceptable();
- method public boolean isUnvalidatedConnectivityAcceptable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
- }
-
- public static final class NetworkAgentConfig.Builder {
- ctor public NetworkAgentConfig.Builder();
- method @NonNull public android.net.NetworkAgentConfig build();
- method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setNat64DetectionEnabled(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setProvisioningNotificationEnabled(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- method @NonNull public int[] getAdministratorUids();
- method @Nullable public static String getCapabilityCarrierName(int);
- method @Nullable public String getSsid();
- method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds();
- method @NonNull public int[] getTransportTypes();
- method @Nullable public java.util.List<android.net.Network> getUnderlyingNetworks();
- method public boolean isPrivateDnsBroken();
- method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
- field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
- field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
- field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
- field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
- field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
- field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
- field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
- }
-
- public static final class NetworkCapabilities.Builder {
- ctor public NetworkCapabilities.Builder();
- ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
- method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder addEnterpriseId(int);
- method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
- method @NonNull public android.net.NetworkCapabilities build();
- method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder removeEnterpriseId(int);
- method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
- method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
- method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
- method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
- }
-
- public class NetworkProvider {
- ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
- method public int getProviderId();
- method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
- method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void registerNetworkOffer(@NonNull android.net.NetworkScore, @NonNull android.net.NetworkCapabilities, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkProvider.NetworkOfferCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkOffer(@NonNull android.net.NetworkProvider.NetworkOfferCallback);
- field public static final int ID_NONE = -1; // 0xffffffff
- }
-
- public static interface NetworkProvider.NetworkOfferCallback {
- method public void onNetworkNeeded(@NonNull android.net.NetworkRequest);
- method public void onNetworkUnneeded(@NonNull android.net.NetworkRequest);
- }
-
- public class NetworkReleasedException extends java.lang.Exception {
- ctor public NetworkReleasedException();
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method @Nullable public String getRequestorPackageName();
- method public int getRequestorUid();
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
- method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
- }
-
- public final class NetworkScore implements android.os.Parcelable {
- method public int describeContents();
- method public int getKeepConnectedReason();
- method public int getLegacyInt();
- method public boolean isExiting();
- method public boolean isTransportPrimary();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
- field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1
- field public static final int KEEP_CONNECTED_NONE = 0; // 0x0
- }
-
- public static final class NetworkScore.Builder {
- ctor public NetworkScore.Builder();
- method @NonNull public android.net.NetworkScore build();
- method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
- method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int);
- method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
- method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean);
- }
-
- public final class OemNetworkPreferences implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR;
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4
- field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0
- }
-
- public static final class OemNetworkPreferences.Builder {
- ctor public OemNetworkPreferences.Builder();
- ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences);
- method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int);
- method @NonNull public android.net.OemNetworkPreferences build();
- method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
- }
-
- public abstract class QosCallback {
- ctor public QosCallback();
- method public void onError(@NonNull android.net.QosCallbackException);
- method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
- method public void onQosSessionLost(@NonNull android.net.QosSession);
- }
-
- public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
- }
-
- public final class QosCallbackException extends java.lang.Exception {
- ctor public QosCallbackException(@NonNull String);
- ctor public QosCallbackException(@NonNull Throwable);
- }
-
- public abstract class QosFilter {
- method @NonNull public abstract android.net.Network getNetwork();
- method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
- method public boolean matchesProtocol(int);
- method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int);
- }
-
- public final class QosSession implements android.os.Parcelable {
- ctor public QosSession(int, int);
- method public int describeContents();
- method public int getSessionId();
- method public int getSessionType();
- method public long getUniqueId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
- field public static final int TYPE_EPS_BEARER = 1; // 0x1
- field public static final int TYPE_NR_BEARER = 2; // 0x2
- }
-
- public interface QosSessionAttributes {
- }
-
- public final class QosSocketInfo implements android.os.Parcelable {
- ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
- ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.DatagramSocket) throws java.io.IOException;
- method public int describeContents();
- method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
- method @NonNull public android.net.Network getNetwork();
- method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
- method public int getMtu();
- }
-
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @Nullable android.net.Network);
- field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
- field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
- field public static final int SUCCESS = 0; // 0x0
- }
-
- public class SocketLocalAddressChangedException extends java.lang.Exception {
- ctor public SocketLocalAddressChangedException();
- }
-
- public class SocketNotBoundException extends java.lang.Exception {
- ctor public SocketNotBoundException();
- }
-
- public class SocketNotConnectedException extends java.lang.Exception {
- ctor public SocketNotConnectedException();
- }
-
- public class SocketRemoteAddressChangedException extends java.lang.Exception {
- ctor public SocketRemoteAddressChangedException();
- }
-
- public final class StaticIpConfiguration implements android.os.Parcelable {
- ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void addDnsServer(@NonNull java.net.InetAddress);
- method public void clear();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- }
-
- public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public int getIpTos();
- method public int getIpTtl();
- method public int getTcpAck();
- method public int getTcpSeq();
- method public int getTcpWindow();
- method public int getTcpWindowScale();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
- }
-
- public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor public VpnTransportInfo(int, @Nullable String, boolean, boolean);
- method public boolean areLongLivedTcpConnectionsExpensive();
- method public int describeContents();
- method public int getType();
- method public boolean isBypassable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
- }
-
-}
-
-package android.net.apf {
-
- public final class ApfCapabilities implements android.os.Parcelable {
- ctor public ApfCapabilities(int, int, int);
- method public int describeContents();
- method public static boolean getApfDrop8023Frames();
- method @NonNull public static int[] getApfEtherTypeBlackList();
- method public boolean hasDataAccess();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
- field public final int apfPacketFormat;
- field public final int apfVersionSupported;
- field public final int maximumApfProgramSize;
- }
-
-}
-
diff --git a/framework/cronet_disabled/api/system-lint-baseline.txt b/framework/cronet_disabled/api/system-lint-baseline.txt
deleted file mode 100644
index 9a97707..0000000
--- a/framework/cronet_disabled/api/system-lint-baseline.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Baseline format: 1.0
diff --git a/framework/cronet_disabled/api/system-removed.txt b/framework/cronet_disabled/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/framework/cronet_disabled/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 67dacb8..ba7df7f 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -176,7 +176,9 @@
/**
* When detecting a captive portal, immediately disconnect from the
- * network and do not reconnect to that network in the future.
+ * network and do not reconnect to that network in the future; except
+ * on Wear platform companion proxy networks (transport BLUETOOTH)
+ * will stay behind captive portal.
*/
public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
diff --git a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
index 9dd07a4..e4651b7 100644
--- a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
@@ -68,15 +68,6 @@
@GuardedBy("mLock")
@Nullable
private List<android.nearby.ScanFilter> mScanFilters;
- private android.bluetooth.le.ScanCallback mScanCallbackLegacy =
- new android.bluetooth.le.ScanCallback() {
- @Override
- public void onScanResult(int callbackType, ScanResult scanResult) {
- }
- @Override
- public void onScanFailed(int errorCode) {
- }
- };
private android.bluetooth.le.ScanCallback mScanCallback =
new android.bluetooth.le.ScanCallback() {
@Override
@@ -170,7 +161,6 @@
if (isBleAvailable()) {
Log.d(TAG, "BleDiscoveryProvider started");
startScan(getScanFilters(), getScanSettings(/* legacy= */ false), mScanCallback);
- startScan(getScanFilters(), getScanSettings(/* legacy= */ true), mScanCallbackLegacy);
return;
}
Log.w(TAG, "Cannot start BleDiscoveryProvider because Ble is not available.");
@@ -187,7 +177,6 @@
}
Log.v(TAG, "Ble scan stopped.");
bluetoothLeScanner.stopScan(mScanCallback);
- bluetoothLeScanner.stopScan(mScanCallbackLegacy);
synchronized (mLock) {
if (mScanFilters != null) {
mScanFilters = null;
diff --git a/nearby/tests/cts/fastpair/Android.bp b/nearby/tests/cts/fastpair/Android.bp
index a61d180..66a1ffe 100644
--- a/nearby/tests/cts/fastpair/Android.bp
+++ b/nearby/tests/cts/fastpair/Android.bp
@@ -26,7 +26,7 @@
"bluetooth-test-util-lib",
"compatibility-device-util-axt",
"ctstestrunner-axt",
- "truth-prebuilt",
+ "truth",
],
libs: [
"android.test.base",
diff --git a/nearby/tests/integration/privileged/Android.bp b/nearby/tests/integration/privileged/Android.bp
index e3250f6..9b6e488 100644
--- a/nearby/tests/integration/privileged/Android.bp
+++ b/nearby/tests/integration/privileged/Android.bp
@@ -27,7 +27,7 @@
"androidx.test.ext.junit",
"androidx.test.rules",
"junit",
- "truth-prebuilt",
+ "truth",
],
test_suites: ["device-tests"],
}
diff --git a/nearby/tests/integration/untrusted/Android.bp b/nearby/tests/integration/untrusted/Android.bp
index 57499e4..75f765b 100644
--- a/nearby/tests/integration/untrusted/Android.bp
+++ b/nearby/tests/integration/untrusted/Android.bp
@@ -31,7 +31,7 @@
"androidx.test.uiautomator_uiautomator",
"junit",
"kotlin-test",
- "truth-prebuilt",
+ "truth",
],
test_suites: ["device-tests"],
}
diff --git a/nearby/tests/unit/Android.bp b/nearby/tests/unit/Android.bp
index 9b35452..112c751 100644
--- a/nearby/tests/unit/Android.bp
+++ b/nearby/tests/unit/Android.bp
@@ -42,7 +42,7 @@
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"service-nearby-pre-jarjar",
- "truth-prebuilt",
+ "truth",
// "Robolectric_all-target",
],
// these are needed for Extended Mockito
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
index 05b556b..c064844 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java
@@ -16,6 +16,7 @@
package com.android.server.nearby.provider;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
@@ -69,7 +70,7 @@
AdvertiseSettings settings = new AdvertiseSettings.Builder().build();
mBleBroadcastProvider.onStartSuccess(settings);
- verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
+ verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
}
@Test
@@ -81,7 +82,7 @@
// advertising set can not be mocked, so we will allow nulls
mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30,
AdvertisingSetCallback.ADVERTISE_SUCCESS);
- verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
+ verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
}
@Test
diff --git a/netbpfload/Android.bp b/netbpfload/Android.bp
new file mode 100644
index 0000000..5480ef7
--- /dev/null
+++ b/netbpfload/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "netbpfload",
+
+ defaults: ["bpf_defaults"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+ sanitize: {
+ integer_overflow: true,
+ },
+
+ header_libs: ["bpf_headers"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ srcs: [
+ "loader.cpp",
+ "NetBpfLoad.cpp",
+ ],
+ apex_available: [
+ "com.android.tethering",
+ "//apex_available:platform",
+ ],
+ // really should be Android 14/U (34), but we cannot include binaries built
+ // against newer sdk in the apex, which still targets 30(R):
+ // module "netbpfload" variant "android_x86_apex30": should support
+ // min_sdk_version(30) for "com.android.tethering": newer SDK(34).
+ min_sdk_version: "30",
+}
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
new file mode 100644
index 0000000..b44a0bc
--- /dev/null
+++ b/netbpfload/NetBpfLoad.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2017-2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_TAG
+#define LOG_TAG "NetBpfLoad"
+#endif
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <elf.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/bpf.h>
+#include <linux/unistd.h>
+#include <net/if.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <log/log.h>
+
+#include "BpfSyscallWrappers.h"
+#include "bpf/BpfUtils.h"
+#include "loader.h"
+
+using android::base::EndsWith;
+using android::bpf::domain;
+using std::string;
+
+bool exists(const char* const path) {
+ int v = access(path, F_OK);
+ if (!v) {
+ ALOGI("%s exists.", path);
+ return true;
+ }
+ if (errno == ENOENT) return false;
+ ALOGE("FATAL: access(%s, F_OK) -> %d [%d:%s]", path, v, errno, strerror(errno));
+ abort(); // can only hit this if permissions (likely selinux) are screwed up
+}
+
+
+const android::bpf::Location locations[] = {
+ // S+ Tethering mainline module (network_stack): tether offload
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/",
+ .prefix = "tethering/",
+ },
+ // T+ Tethering mainline module (shared with netd & system server)
+ // netutils_wrapper (for iptables xt_bpf) has access to programs
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/netd_shared/",
+ .prefix = "netd_shared/",
+ },
+ // T+ Tethering mainline module (shared with netd & system server)
+ // netutils_wrapper has no access, netd has read only access
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/netd_readonly/",
+ .prefix = "netd_readonly/",
+ },
+ // T+ Tethering mainline module (shared with system server)
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/net_shared/",
+ .prefix = "net_shared/",
+ },
+ // T+ Tethering mainline module (not shared, just network_stack)
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/net_private/",
+ .prefix = "net_private/",
+ },
+};
+
+int loadAllElfObjects(const android::bpf::Location& location) {
+ int retVal = 0;
+ DIR* dir;
+ struct dirent* ent;
+
+ if ((dir = opendir(location.dir)) != NULL) {
+ while ((ent = readdir(dir)) != NULL) {
+ string s = ent->d_name;
+ if (!EndsWith(s, ".o")) continue;
+
+ string progPath(location.dir);
+ progPath += s;
+
+ bool critical;
+ int ret = android::bpf::loadProg(progPath.c_str(), &critical, location);
+ if (ret) {
+ if (critical) retVal = ret;
+ ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
+ } else {
+ ALOGI("Loaded object: %s", progPath.c_str());
+ }
+ }
+ closedir(dir);
+ }
+ return retVal;
+}
+
+int createSysFsBpfSubDir(const char* const prefix) {
+ if (*prefix) {
+ mode_t prevUmask = umask(0);
+
+ string s = "/sys/fs/bpf/";
+ s += prefix;
+
+ errno = 0;
+ int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
+ if (ret && errno != EEXIST) {
+ const int err = errno;
+ ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(err));
+ return -err;
+ }
+
+ umask(prevUmask);
+ }
+ return 0;
+}
+
+// Technically 'value' doesn't need to be newline terminated, but it's best
+// to include a newline to match 'echo "value" > /proc/sys/...foo' behaviour,
+// which is usually how kernel devs test the actual sysctl interfaces.
+int writeProcSysFile(const char *filename, const char *value) {
+ android::base::unique_fd fd(open(filename, O_WRONLY | O_CLOEXEC));
+ if (fd < 0) {
+ const int err = errno;
+ ALOGE("open('%s', O_WRONLY | O_CLOEXEC) -> %s", filename, strerror(err));
+ return -err;
+ }
+ int len = strlen(value);
+ int v = write(fd, value, len);
+ if (v < 0) {
+ const int err = errno;
+ ALOGE("write('%s', '%s', %d) -> %s", filename, value, len, strerror(err));
+ return -err;
+ }
+ if (v != len) {
+ // In practice, due to us only using this for /proc/sys/... files, this can't happen.
+ ALOGE("write('%s', '%s', %d) -> short write [%d]", filename, value, len, v);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ (void)argc;
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ if (!android::bpf::isAtLeastKernelVersion(4, 19, 0)) {
+ ALOGE("Android U QPR2 requires kernel 4.19.");
+ return 1;
+ }
+
+ if (android::bpf::isUserspace32bit() && android::bpf::isAtLeastKernelVersion(6, 2, 0)) {
+ /* Android 14/U should only launch on 64-bit kernels
+ * T launches on 5.10/5.15
+ * U launches on 5.15/6.1
+ * So >=5.16 implies isKernel64Bit()
+ *
+ * We thus added a test to V VTS which requires 5.16+ devices to use 64-bit kernels.
+ *
+ * Starting with Android V, which is the first to support a post 6.1 Linux Kernel,
+ * we also require 64-bit userspace.
+ *
+ * There are various known issues with 32-bit userspace talking to various
+ * kernel interfaces (especially CAP_NET_ADMIN ones) on a 64-bit kernel.
+ * Some of these have userspace or kernel workarounds/hacks.
+ * Some of them don't...
+ * We're going to be removing the hacks.
+ *
+ * Additionally the 32-bit kernel jit support is poor,
+ * and 32-bit userspace on 64-bit kernel bpf ringbuffer compatibility is broken.
+ */
+ ALOGE("64-bit userspace required on 6.2+ kernels.");
+ return 1;
+ }
+
+ // Ensure we can determine the Android build type.
+ if (!android::bpf::isEng() && !android::bpf::isUser() && !android::bpf::isUserdebug()) {
+ ALOGE("Failed to determine the build type: got %s, want 'eng', 'user', or 'userdebug'",
+ android::bpf::getBuildType().c_str());
+ return 1;
+ }
+
+ // Linux 5.16-rc1 changed the default to 2 (disabled but changeable), but we need 0 (enabled)
+ // (this writeFile is known to fail on at least 4.19, but always defaults to 0 on pre-5.13,
+ // on 5.13+ it depends on CONFIG_BPF_UNPRIV_DEFAULT_OFF)
+ if (writeProcSysFile("/proc/sys/kernel/unprivileged_bpf_disabled", "0\n") &&
+ android::bpf::isAtLeastKernelVersion(5, 13, 0)) return 1;
+
+ // Enable the eBPF JIT -- but do note that on 64-bit kernels it is likely
+ // already force enabled by the kernel config option BPF_JIT_ALWAYS_ON.
+ // (Note: this (open) will fail with ENOENT 'No such file or directory' if
+ // kernel does not have CONFIG_BPF_JIT=y)
+ // BPF_JIT is required by R VINTF (which means 4.14/4.19/5.4 kernels),
+ // but 4.14/4.19 were released with P & Q, and only 5.4 is new in R+.
+ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_enable", "1\n")) return 1;
+
+ // Enable JIT kallsyms export for privileged users only
+ // (Note: this (open) will fail with ENOENT 'No such file or directory' if
+ // kernel does not have CONFIG_HAVE_EBPF_JIT=y)
+ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_kallsyms", "1\n")) return 1;
+
+ // Create all the pin subdirectories
+ // (this must be done first to allow selinux_context and pin_subdir functionality,
+ // which could otherwise fail with ENOENT during object pinning or renaming,
+ // due to ordering issues)
+ for (const auto& location : locations) {
+ if (createSysFsBpfSubDir(location.prefix)) return 1;
+ }
+
+ // Load all ELF objects, create programs and maps, and pin them
+ for (const auto& location : locations) {
+ if (loadAllElfObjects(location) != 0) {
+ ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
+ ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
+ ALOGE("If this triggers randomly, you might be hitting some memory allocation "
+ "problems or startup script race.");
+ ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
+ sleep(20);
+ return 2;
+ }
+ }
+
+ int key = 1;
+ int value = 123;
+ android::base::unique_fd map(
+ android::bpf::createMap(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2, 0));
+ if (android::bpf::writeToMapEntry(map, &key, &value, BPF_ANY)) {
+ ALOGE("Critical kernel bug - failure to write into index 1 of 2 element bpf map array.");
+ return 1;
+ }
+
+ if (android::base::SetProperty("bpf.progs_loaded", "1") == false) {
+ ALOGE("Failed to set bpf.progs_loaded property");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
new file mode 100644
index 0000000..c534b2c
--- /dev/null
+++ b/netbpfload/loader.cpp
@@ -0,0 +1,1185 @@
+/*
+ * Copyright (C) 2018-2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NetBpfLoader"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/bpf.h>
+#include <linux/elf.h>
+#include <log/log.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// This is BpfLoader v0.41
+// WARNING: If you ever hit cherrypick conflicts here you're doing it wrong:
+// You are NOT allowed to cherrypick bpfloader related patches out of order.
+// (indeed: cherrypicking is probably a bad idea and you should merge instead)
+// Mainline supports ONLY the published versions of the bpfloader for each Android release.
+#define BPFLOADER_VERSION_MAJOR 0u
+#define BPFLOADER_VERSION_MINOR 41u
+#define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
+
+#include "BpfSyscallWrappers.h"
+#include "bpf/BpfUtils.h"
+#include "bpf/bpf_map_def.h"
+#include "loader.h"
+
+#if BPFLOADER_VERSION < COMPILE_FOR_BPFLOADER_VERSION
+#error "BPFLOADER_VERSION is less than COMPILE_FOR_BPFLOADER_VERSION"
+#endif
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/cmsg.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+// Size of the BPF log buffer for verifier logging
+#define BPF_LOAD_LOG_SZ 0xfffff
+
+// Unspecified attach type is 0 which is BPF_CGROUP_INET_INGRESS.
+#define BPF_ATTACH_TYPE_UNSPEC BPF_CGROUP_INET_INGRESS
+
+using android::base::StartsWith;
+using android::base::unique_fd;
+using std::ifstream;
+using std::ios;
+using std::optional;
+using std::string;
+using std::vector;
+
+namespace android {
+namespace bpf {
+
+const std::string& getBuildType() {
+ static std::string t = android::base::GetProperty("ro.build.type", "unknown");
+ return t;
+}
+
+static unsigned int page_size = static_cast<unsigned int>(getpagesize());
+
+constexpr const char* lookupSelinuxContext(const domain d, const char* const unspecified = "") {
+ switch (d) {
+ case domain::unspecified: return unspecified;
+ case domain::tethering: return "fs_bpf_tethering";
+ case domain::net_private: return "fs_bpf_net_private";
+ case domain::net_shared: return "fs_bpf_net_shared";
+ case domain::netd_readonly: return "fs_bpf_netd_readonly";
+ case domain::netd_shared: return "fs_bpf_netd_shared";
+ default: return "(unrecognized)";
+ }
+}
+
+domain getDomainFromSelinuxContext(const char s[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]) {
+ for (domain d : AllDomains) {
+ // Not sure how to enforce this at compile time, so abort() bpfloader at boot instead
+ if (strlen(lookupSelinuxContext(d)) >= BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE) abort();
+ if (!strncmp(s, lookupSelinuxContext(d), BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE)) return d;
+ }
+ ALOGW("ignoring unrecognized selinux_context '%-32s'", s);
+ // We should return 'unrecognized' here, however: returning unspecified will
+ // result in the system simply using the default context, which in turn
+ // will allow future expansion by adding more restrictive selinux types.
+ // Older bpfloader will simply ignore that, and use the less restrictive default.
+ // This does mean you CANNOT later add a *less* restrictive type than the default.
+ //
+ // Note: we cannot just abort() here as this might be a mainline module shipped optional update
+ return domain::unspecified;
+}
+
+constexpr const char* lookupPinSubdir(const domain d, const char* const unspecified = "") {
+ switch (d) {
+ case domain::unspecified: return unspecified;
+ case domain::tethering: return "tethering/";
+ case domain::net_private: return "net_private/";
+ case domain::net_shared: return "net_shared/";
+ case domain::netd_readonly: return "netd_readonly/";
+ case domain::netd_shared: return "netd_shared/";
+ default: return "(unrecognized)";
+ }
+};
+
+domain getDomainFromPinSubdir(const char s[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]) {
+ for (domain d : AllDomains) {
+ // Not sure how to enforce this at compile time, so abort() bpfloader at boot instead
+ if (strlen(lookupPinSubdir(d)) >= BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE) abort();
+ if (!strncmp(s, lookupPinSubdir(d), BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE)) return d;
+ }
+ ALOGE("unrecognized pin_subdir '%-32s'", s);
+ // pin_subdir affects the object's full pathname,
+ // and thus using the default would change the location and thus our code's ability to find it,
+ // hence this seems worth treating as a true error condition.
+ //
+ // Note: we cannot just abort() here as this might be a mainline module shipped optional update
+ // However, our callers will treat this as an error, and stop loading the specific .o,
+ // which will fail bpfloader if the .o is marked critical.
+ return domain::unrecognized;
+}
+
+static string pathToObjName(const string& path) {
+ // extract everything after the final slash, ie. this is the filename 'foo@1.o' or 'bar.o'
+ string filename = android::base::Split(path, "/").back();
+ // strip off everything from the final period onwards (strip '.o' suffix), ie. 'foo@1' or 'bar'
+ string name = filename.substr(0, filename.find_last_of('.'));
+ // strip any potential @1 suffix, this will leave us with just 'foo' or 'bar'
+ // this can be used to provide duplicate programs (mux based on the bpfloader version)
+ return name.substr(0, name.find_last_of('@'));
+}
+
+typedef struct {
+ const char* name;
+ enum bpf_prog_type type;
+ enum bpf_attach_type expected_attach_type;
+} sectionType;
+
+/*
+ * Map section name prefixes to program types, the section name will be:
+ * SECTION(<prefix>/<name-of-program>)
+ * For example:
+ * SECTION("tracepoint/sched_switch_func") where sched_switch_funcs
+ * is the name of the program, and tracepoint is the type.
+ *
+ * However, be aware that you should not be directly using the SECTION() macro.
+ * Instead use the DEFINE_(BPF|XDP)_(PROG|MAP)... & LICENSE/CRITICAL macros.
+ *
+ * Programs shipped inside the tethering apex should be limited to networking stuff,
+ * as KPROBE, PERF_EVENT, TRACEPOINT are dangerous to use from mainline updatable code,
+ * since they are less stable abi/api and may conflict with platform uses of bpf.
+ */
+sectionType sectionNameTypes[] = {
+ {"bind4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND},
+ {"bind6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
+ {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB, BPF_ATTACH_TYPE_UNSPEC},
+ {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_ATTACH_TYPE_UNSPEC},
+ {"connect4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT},
+ {"connect6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT},
+ {"egress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_EGRESS},
+ {"getsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_GETSOCKOPT},
+ {"ingress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_INGRESS},
+ {"lwt_in/", BPF_PROG_TYPE_LWT_IN, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_out/", BPF_PROG_TYPE_LWT_OUT, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_seg6local/", BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_xmit/", BPF_PROG_TYPE_LWT_XMIT, BPF_ATTACH_TYPE_UNSPEC},
+ {"postbind4/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND},
+ {"postbind6/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND},
+ {"recvmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG},
+ {"recvmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG},
+ {"schedact/", BPF_PROG_TYPE_SCHED_ACT, BPF_ATTACH_TYPE_UNSPEC},
+ {"schedcls/", BPF_PROG_TYPE_SCHED_CLS, BPF_ATTACH_TYPE_UNSPEC},
+ {"sendmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG},
+ {"sendmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG},
+ {"setsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT},
+ {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER, BPF_ATTACH_TYPE_UNSPEC},
+ {"sockops/", BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS},
+ {"sysctl", BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL},
+ {"xdp/", BPF_PROG_TYPE_XDP, BPF_ATTACH_TYPE_UNSPEC},
+};
+
+typedef struct {
+ enum bpf_prog_type type;
+ enum bpf_attach_type expected_attach_type;
+ string name;
+ vector<char> data;
+ vector<char> rel_data;
+ optional<struct bpf_prog_def> prog_def;
+
+ unique_fd prog_fd; /* fd after loading */
+} codeSection;
+
+static int readElfHeader(ifstream& elfFile, Elf64_Ehdr* eh) {
+ elfFile.seekg(0);
+ if (elfFile.fail()) return -1;
+
+ if (!elfFile.read((char*)eh, sizeof(*eh))) return -1;
+
+ return 0;
+}
+
+/* Reads all section header tables into an Shdr array */
+static int readSectionHeadersAll(ifstream& elfFile, vector<Elf64_Shdr>& shTable) {
+ Elf64_Ehdr eh;
+ int ret = 0;
+
+ ret = readElfHeader(elfFile, &eh);
+ if (ret) return ret;
+
+ elfFile.seekg(eh.e_shoff);
+ if (elfFile.fail()) return -1;
+
+ /* Read shdr table entries */
+ shTable.resize(eh.e_shnum);
+
+ if (!elfFile.read((char*)shTable.data(), (eh.e_shnum * eh.e_shentsize))) return -ENOMEM;
+
+ return 0;
+}
+
+/* Read a section by its index - for ex to get sec hdr strtab blob */
+static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
+ vector<Elf64_Shdr> shTable;
+ int ret = readSectionHeadersAll(elfFile, shTable);
+ if (ret) return ret;
+
+ elfFile.seekg(shTable[id].sh_offset);
+ if (elfFile.fail()) return -1;
+
+ sec.resize(shTable[id].sh_size);
+ if (!elfFile.read(sec.data(), shTable[id].sh_size)) return -1;
+
+ return 0;
+}
+
+/* Read whole section header string table */
+static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
+ Elf64_Ehdr eh;
+ int ret = readElfHeader(elfFile, &eh);
+ if (ret) return ret;
+
+ ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
+ if (ret) return ret;
+
+ return 0;
+}
+
+/* Get name from offset in strtab */
+static int getSymName(ifstream& elfFile, int nameOff, string& name) {
+ int ret;
+ vector<char> secStrTab;
+
+ ret = readSectionHeaderStrtab(elfFile, secStrTab);
+ if (ret) return ret;
+
+ if (nameOff >= (int)secStrTab.size()) return -1;
+
+ name = string((char*)secStrTab.data() + nameOff);
+ return 0;
+}
+
+/* Reads a full section by name - example to get the GPL license */
+static int readSectionByName(const char* name, ifstream& elfFile, vector<char>& data) {
+ vector<char> secStrTab;
+ vector<Elf64_Shdr> shTable;
+ int ret;
+
+ ret = readSectionHeadersAll(elfFile, shTable);
+ if (ret) return ret;
+
+ ret = readSectionHeaderStrtab(elfFile, secStrTab);
+ if (ret) return ret;
+
+ for (int i = 0; i < (int)shTable.size(); i++) {
+ char* secname = secStrTab.data() + shTable[i].sh_name;
+ if (!secname) continue;
+
+ if (!strcmp(secname, name)) {
+ vector<char> dataTmp;
+ dataTmp.resize(shTable[i].sh_size);
+
+ elfFile.seekg(shTable[i].sh_offset);
+ if (elfFile.fail()) return -1;
+
+ if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
+
+ data = dataTmp;
+ return 0;
+ }
+ }
+ return -2;
+}
+
+unsigned int readSectionUint(const char* name, ifstream& elfFile, unsigned int defVal) {
+ vector<char> theBytes;
+ int ret = readSectionByName(name, elfFile, theBytes);
+ if (ret) {
+ ALOGD("Couldn't find section %s (defaulting to %u [0x%x]).", name, defVal, defVal);
+ return defVal;
+ } else if (theBytes.size() < sizeof(unsigned int)) {
+ ALOGE("Section %s too short (defaulting to %u [0x%x]).", name, defVal, defVal);
+ return defVal;
+ } else {
+ // decode first 4 bytes as LE32 uint, there will likely be more bytes due to alignment.
+ unsigned int value = static_cast<unsigned char>(theBytes[3]);
+ value <<= 8;
+ value += static_cast<unsigned char>(theBytes[2]);
+ value <<= 8;
+ value += static_cast<unsigned char>(theBytes[1]);
+ value <<= 8;
+ value += static_cast<unsigned char>(theBytes[0]);
+ ALOGI("Section %s value is %u [0x%x]", name, value, value);
+ return value;
+ }
+}
+
+static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) {
+ int ret;
+ vector<Elf64_Shdr> shTable;
+
+ ret = readSectionHeadersAll(elfFile, shTable);
+ if (ret) return ret;
+
+ for (int i = 0; i < (int)shTable.size(); i++) {
+ if ((int)shTable[i].sh_type != type) continue;
+
+ vector<char> dataTmp;
+ dataTmp.resize(shTable[i].sh_size);
+
+ elfFile.seekg(shTable[i].sh_offset);
+ if (elfFile.fail()) return -1;
+
+ if (!elfFile.read((char*)dataTmp.data(), shTable[i].sh_size)) return -1;
+
+ data = dataTmp;
+ return 0;
+ }
+ return -2;
+}
+
+static bool symCompare(Elf64_Sym a, Elf64_Sym b) {
+ return (a.st_value < b.st_value);
+}
+
+static int readSymTab(ifstream& elfFile, int sort, vector<Elf64_Sym>& data) {
+ int ret, numElems;
+ Elf64_Sym* buf;
+ vector<char> secData;
+
+ ret = readSectionByType(elfFile, SHT_SYMTAB, secData);
+ if (ret) return ret;
+
+ buf = (Elf64_Sym*)secData.data();
+ numElems = (secData.size() / sizeof(Elf64_Sym));
+ data.assign(buf, buf + numElems);
+
+ if (sort) std::sort(data.begin(), data.end(), symCompare);
+ return 0;
+}
+
+static enum bpf_prog_type getSectionType(string& name) {
+ for (auto& snt : sectionNameTypes)
+ if (StartsWith(name, snt.name)) return snt.type;
+
+ return BPF_PROG_TYPE_UNSPEC;
+}
+
+static enum bpf_attach_type getExpectedAttachType(string& name) {
+ for (auto& snt : sectionNameTypes)
+ if (StartsWith(name, snt.name)) return snt.expected_attach_type;
+ return BPF_ATTACH_TYPE_UNSPEC;
+}
+
+/*
+static string getSectionName(enum bpf_prog_type type)
+{
+ for (auto& snt : sectionNameTypes)
+ if (snt.type == type)
+ return string(snt.name);
+
+ return "UNKNOWN SECTION NAME " + std::to_string(type);
+}
+*/
+
+static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd,
+ size_t sizeOfBpfProgDef) {
+ vector<char> pdData;
+ int ret = readSectionByName("progs", elfFile, pdData);
+ // Older file formats do not require a 'progs' section at all.
+ // (We should probably figure out whether this is behaviour which is safe to remove now.)
+ if (ret == -2) return 0;
+ if (ret) return ret;
+
+ if (pdData.size() % sizeOfBpfProgDef) {
+ ALOGE("readProgDefs failed due to improper sized progs section, %zu %% %zu != 0",
+ pdData.size(), sizeOfBpfProgDef);
+ return -1;
+ };
+
+ int progCount = pdData.size() / sizeOfBpfProgDef;
+ pd.resize(progCount);
+ size_t trimmedSize = std::min(sizeOfBpfProgDef, sizeof(struct bpf_prog_def));
+
+ const char* dataPtr = pdData.data();
+ for (auto& p : pd) {
+ // First we zero initialize
+ memset(&p, 0, sizeof(p));
+ // Then we set non-zero defaults
+ p.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0
+ // Then we copy over the structure prefix from the ELF file.
+ memcpy(&p, dataPtr, trimmedSize);
+ // Move to next struct in the ELF file
+ dataPtr += sizeOfBpfProgDef;
+ }
+ return 0;
+}
+
+static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names,
+ optional<unsigned> symbolType = std::nullopt) {
+ int ret;
+ string name;
+ vector<Elf64_Sym> symtab;
+ vector<Elf64_Shdr> shTable;
+
+ ret = readSymTab(elfFile, 1 /* sort */, symtab);
+ if (ret) return ret;
+
+ /* Get index of section */
+ ret = readSectionHeadersAll(elfFile, shTable);
+ if (ret) return ret;
+
+ int sec_idx = -1;
+ for (int i = 0; i < (int)shTable.size(); i++) {
+ ret = getSymName(elfFile, shTable[i].sh_name, name);
+ if (ret) return ret;
+
+ if (!name.compare(sectionName)) {
+ sec_idx = i;
+ break;
+ }
+ }
+
+ /* No section found with matching name*/
+ if (sec_idx == -1) {
+ ALOGW("No %s section could be found in elf object", sectionName.c_str());
+ return -1;
+ }
+
+ for (int i = 0; i < (int)symtab.size(); i++) {
+ if (symbolType.has_value() && ELF_ST_TYPE(symtab[i].st_info) != symbolType) continue;
+
+ if (symtab[i].st_shndx == sec_idx) {
+ string s;
+ ret = getSymName(elfFile, symtab[i].st_name, s);
+ if (ret) return ret;
+ names.push_back(s);
+ }
+ }
+
+ return 0;
+}
+
+/* Read a section by its index - for ex to get sec hdr strtab blob */
+static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef) {
+ vector<Elf64_Shdr> shTable;
+ int entries, ret = 0;
+
+ ret = readSectionHeadersAll(elfFile, shTable);
+ if (ret) return ret;
+ entries = shTable.size();
+
+ vector<struct bpf_prog_def> pd;
+ ret = readProgDefs(elfFile, pd, sizeOfBpfProgDef);
+ if (ret) return ret;
+ vector<string> progDefNames;
+ ret = getSectionSymNames(elfFile, "progs", progDefNames);
+ if (!pd.empty() && ret) return ret;
+
+ for (int i = 0; i < entries; i++) {
+ string name;
+ codeSection cs_temp;
+ cs_temp.type = BPF_PROG_TYPE_UNSPEC;
+
+ ret = getSymName(elfFile, shTable[i].sh_name, name);
+ if (ret) return ret;
+
+ enum bpf_prog_type ptype = getSectionType(name);
+
+ if (ptype == BPF_PROG_TYPE_UNSPEC) continue;
+
+ // This must be done before '/' is replaced with '_'.
+ cs_temp.expected_attach_type = getExpectedAttachType(name);
+
+ string oldName = name;
+
+ // convert all slashes to underscores
+ std::replace(name.begin(), name.end(), '/', '_');
+
+ cs_temp.type = ptype;
+ cs_temp.name = name;
+
+ ret = readSectionByIdx(elfFile, i, cs_temp.data);
+ if (ret) return ret;
+ ALOGD("Loaded code section %d (%s)", i, name.c_str());
+
+ vector<string> csSymNames;
+ ret = getSectionSymNames(elfFile, oldName, csSymNames, STT_FUNC);
+ if (ret || !csSymNames.size()) return ret;
+ for (size_t i = 0; i < progDefNames.size(); ++i) {
+ if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
+ cs_temp.prog_def = pd[i];
+ break;
+ }
+ }
+
+ /* Check for rel section */
+ if (cs_temp.data.size() > 0 && i < entries) {
+ ret = getSymName(elfFile, shTable[i + 1].sh_name, name);
+ if (ret) return ret;
+
+ if (name == (".rel" + oldName)) {
+ ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
+ if (ret) return ret;
+ ALOGD("Loaded relo section %d (%s)", i, name.c_str());
+ }
+ }
+
+ if (cs_temp.data.size() > 0) {
+ cs.push_back(std::move(cs_temp));
+ ALOGD("Adding section %d to cs list", i);
+ }
+ }
+ return 0;
+}
+
+static int getSymNameByIdx(ifstream& elfFile, int index, string& name) {
+ vector<Elf64_Sym> symtab;
+ int ret = 0;
+
+ ret = readSymTab(elfFile, 0 /* !sort */, symtab);
+ if (ret) return ret;
+
+ if (index >= (int)symtab.size()) return -1;
+
+ return getSymName(elfFile, symtab[index].st_name, name);
+}
+
+static bool mapMatchesExpectations(const unique_fd& fd, const string& mapName,
+ const struct bpf_map_def& mapDef, const enum bpf_map_type type) {
+ // Assuming fd is a valid Bpf Map file descriptor then
+ // all the following should always succeed on a 4.14+ kernel.
+ // If they somehow do fail, they'll return -1 (and set errno),
+ // which should then cause (among others) a key_size mismatch.
+ int fd_type = bpfGetFdMapType(fd);
+ int fd_key_size = bpfGetFdKeySize(fd);
+ int fd_value_size = bpfGetFdValueSize(fd);
+ int fd_max_entries = bpfGetFdMaxEntries(fd);
+ int fd_map_flags = bpfGetFdMapFlags(fd);
+
+ // DEVMAPs are readonly from the bpf program side's point of view, as such
+ // the kernel in kernel/bpf/devmap.c dev_map_init_map() will set the flag
+ int desired_map_flags = (int)mapDef.map_flags;
+ if (type == BPF_MAP_TYPE_DEVMAP || type == BPF_MAP_TYPE_DEVMAP_HASH)
+ desired_map_flags |= BPF_F_RDONLY_PROG;
+
+ // The .h file enforces that this is a power of two, and page size will
+ // also always be a power of two, so this logic is actually enough to
+ // force it to be a multiple of the page size, as required by the kernel.
+ unsigned int desired_max_entries = mapDef.max_entries;
+ if (type == BPF_MAP_TYPE_RINGBUF) {
+ if (desired_max_entries < page_size) desired_max_entries = page_size;
+ }
+
+ // The following checks should *never* trigger, if one of them somehow does,
+ // it probably means a bpf .o file has been changed/replaced at runtime
+ // and bpfloader was manually rerun (normally it should only run *once*
+ // early during the boot process).
+ // Another possibility is that something is misconfigured in the code:
+ // most likely a shared map is declared twice differently.
+ // But such a change should never be checked into the source tree...
+ if ((fd_type == type) &&
+ (fd_key_size == (int)mapDef.key_size) &&
+ (fd_value_size == (int)mapDef.value_size) &&
+ (fd_max_entries == (int)desired_max_entries) &&
+ (fd_map_flags == desired_map_flags)) {
+ return true;
+ }
+
+ ALOGE("bpf map name %s mismatch: desired/found: "
+ "type:%d/%d key:%u/%d value:%u/%d entries:%u/%d flags:%u/%d",
+ mapName.c_str(), type, fd_type, mapDef.key_size, fd_key_size, mapDef.value_size,
+ fd_value_size, mapDef.max_entries, fd_max_entries, desired_map_flags, fd_map_flags);
+ return false;
+}
+
+static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
+ const char* prefix, const size_t sizeOfBpfMapDef) {
+ int ret;
+ vector<char> mdData;
+ vector<struct bpf_map_def> md;
+ vector<string> mapNames;
+ string objName = pathToObjName(string(elfPath));
+
+ ret = readSectionByName("maps", elfFile, mdData);
+ if (ret == -2) return 0; // no maps to read
+ if (ret) return ret;
+
+ if (mdData.size() % sizeOfBpfMapDef) {
+ ALOGE("createMaps failed due to improper sized maps section, %zu %% %zu != 0",
+ mdData.size(), sizeOfBpfMapDef);
+ return -1;
+ };
+
+ int mapCount = mdData.size() / sizeOfBpfMapDef;
+ md.resize(mapCount);
+ size_t trimmedSize = std::min(sizeOfBpfMapDef, sizeof(struct bpf_map_def));
+
+ const char* dataPtr = mdData.data();
+ for (auto& m : md) {
+ // First we zero initialize
+ memset(&m, 0, sizeof(m));
+ // Then we set non-zero defaults
+ m.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER; // v1.0
+ m.max_kver = 0xFFFFFFFFu; // matches KVER_INF from bpf_helpers.h
+ // Then we copy over the structure prefix from the ELF file.
+ memcpy(&m, dataPtr, trimmedSize);
+ // Move to next struct in the ELF file
+ dataPtr += sizeOfBpfMapDef;
+ }
+
+ ret = getSectionSymNames(elfFile, "maps", mapNames);
+ if (ret) return ret;
+
+ unsigned kvers = kernelVersion();
+
+ for (int i = 0; i < (int)mapNames.size(); i++) {
+ if (md[i].zero != 0) abort();
+
+ if (BPFLOADER_VERSION < md[i].bpfloader_min_ver) {
+ ALOGI("skipping map %s which requires bpfloader min ver 0x%05x", mapNames[i].c_str(),
+ md[i].bpfloader_min_ver);
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ if (BPFLOADER_VERSION >= md[i].bpfloader_max_ver) {
+ ALOGI("skipping map %s which requires bpfloader max ver 0x%05x", mapNames[i].c_str(),
+ md[i].bpfloader_max_ver);
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ if (kvers < md[i].min_kver) {
+ ALOGI("skipping map %s which requires kernel version 0x%x >= 0x%x",
+ mapNames[i].c_str(), kvers, md[i].min_kver);
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ if (kvers >= md[i].max_kver) {
+ ALOGI("skipping map %s which requires kernel version 0x%x < 0x%x",
+ mapNames[i].c_str(), kvers, md[i].max_kver);
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ if ((md[i].ignore_on_eng && isEng()) || (md[i].ignore_on_user && isUser()) ||
+ (md[i].ignore_on_userdebug && isUserdebug())) {
+ ALOGI("skipping map %s which is ignored on %s builds", mapNames[i].c_str(),
+ getBuildType().c_str());
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ if ((isArm() && isKernel32Bit() && md[i].ignore_on_arm32) ||
+ (isArm() && isKernel64Bit() && md[i].ignore_on_aarch64) ||
+ (isX86() && isKernel32Bit() && md[i].ignore_on_x86_32) ||
+ (isX86() && isKernel64Bit() && md[i].ignore_on_x86_64) ||
+ (isRiscV() && md[i].ignore_on_riscv64)) {
+ ALOGI("skipping map %s which is ignored on %s", mapNames[i].c_str(),
+ describeArch());
+ mapFds.push_back(unique_fd());
+ continue;
+ }
+
+ enum bpf_map_type type = md[i].type;
+ if (type == BPF_MAP_TYPE_DEVMAP_HASH && !isAtLeastKernelVersion(5, 4, 0)) {
+ // On Linux Kernels older than 5.4 this map type doesn't exist, but it can kind
+ // of be approximated: HASH has the same userspace visible api.
+ // However it cannot be used by ebpf programs in the same way.
+ // Since bpf_redirect_map() only requires 4.14, a program using a DEVMAP_HASH map
+ // would fail to load (due to trying to redirect to a HASH instead of DEVMAP_HASH).
+ // One must thus tag any BPF_MAP_TYPE_DEVMAP_HASH + bpf_redirect_map() using
+ // programs as being 5.4+...
+ type = BPF_MAP_TYPE_HASH;
+ }
+
+ // The .h file enforces that this is a power of two, and page size will
+ // also always be a power of two, so this logic is actually enough to
+ // force it to be a multiple of the page size, as required by the kernel.
+ unsigned int max_entries = md[i].max_entries;
+ if (type == BPF_MAP_TYPE_RINGBUF) {
+ if (max_entries < page_size) max_entries = page_size;
+ }
+
+ domain selinux_context = getDomainFromSelinuxContext(md[i].selinux_context);
+ if (specified(selinux_context)) {
+ ALOGI("map %s selinux_context [%-32s] -> %d -> '%s' (%s)", mapNames[i].c_str(),
+ md[i].selinux_context, selinux_context, lookupSelinuxContext(selinux_context),
+ lookupPinSubdir(selinux_context));
+ }
+
+ domain pin_subdir = getDomainFromPinSubdir(md[i].pin_subdir);
+ if (unrecognized(pin_subdir)) return -ENOTDIR;
+ if (specified(pin_subdir)) {
+ ALOGI("map %s pin_subdir [%-32s] -> %d -> '%s'", mapNames[i].c_str(), md[i].pin_subdir,
+ pin_subdir, lookupPinSubdir(pin_subdir));
+ }
+
+ // Format of pin location is /sys/fs/bpf/<pin_subdir|prefix>map_<objName>_<mapName>
+ // except that maps shared across .o's have empty <objName>
+ // Note: <objName> refers to the extension-less basename of the .o file (without @ suffix).
+ string mapPinLoc = string(BPF_FS_PATH) + lookupPinSubdir(pin_subdir, prefix) + "map_" +
+ (md[i].shared ? "" : objName) + "_" + mapNames[i];
+ bool reuse = false;
+ unique_fd fd;
+ int saved_errno;
+
+ if (access(mapPinLoc.c_str(), F_OK) == 0) {
+ fd.reset(mapRetrieveRO(mapPinLoc.c_str()));
+ saved_errno = errno;
+ ALOGD("bpf_create_map reusing map %s, ret: %d", mapNames[i].c_str(), fd.get());
+ reuse = true;
+ } else {
+ union bpf_attr req = {
+ .map_type = type,
+ .key_size = md[i].key_size,
+ .value_size = md[i].value_size,
+ .max_entries = max_entries,
+ .map_flags = md[i].map_flags,
+ };
+ strlcpy(req.map_name, mapNames[i].c_str(), sizeof(req.map_name));
+ fd.reset(bpf(BPF_MAP_CREATE, req));
+ saved_errno = errno;
+ ALOGD("bpf_create_map name %s, ret: %d", mapNames[i].c_str(), fd.get());
+ }
+
+ if (!fd.ok()) return -saved_errno;
+
+ // When reusing a pinned map, we need to check the map type/sizes/etc match, but for
+ // safety (since reuse code path is rare) run these checks even if we just created it.
+ // We assume failure is due to pinned map mismatch, hence the 'NOT UNIQUE' return code.
+ if (!mapMatchesExpectations(fd, mapNames[i], md[i], type)) return -ENOTUNIQ;
+
+ if (!reuse) {
+ if (specified(selinux_context)) {
+ string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) +
+ "tmp_map_" + objName + "_" + mapNames[i];
+ ret = bpfFdPin(fd, createLoc.c_str());
+ if (ret) {
+ int err = errno;
+ ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err));
+ return -err;
+ }
+ ret = renameat2(AT_FDCWD, createLoc.c_str(),
+ AT_FDCWD, mapPinLoc.c_str(), RENAME_NOREPLACE);
+ if (ret) {
+ int err = errno;
+ ALOGE("rename %s %s -> %d [%d:%s]", createLoc.c_str(), mapPinLoc.c_str(), ret,
+ err, strerror(err));
+ return -err;
+ }
+ } else {
+ ret = bpfFdPin(fd, mapPinLoc.c_str());
+ if (ret) {
+ int err = errno;
+ ALOGE("pin %s -> %d [%d:%s]", mapPinLoc.c_str(), ret, err, strerror(err));
+ return -err;
+ }
+ }
+ ret = chmod(mapPinLoc.c_str(), md[i].mode);
+ if (ret) {
+ int err = errno;
+ ALOGE("chmod(%s, 0%o) = %d [%d:%s]", mapPinLoc.c_str(), md[i].mode, ret, err,
+ strerror(err));
+ return -err;
+ }
+ ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid);
+ if (ret) {
+ int err = errno;
+ ALOGE("chown(%s, %u, %u) = %d [%d:%s]", mapPinLoc.c_str(), md[i].uid, md[i].gid,
+ ret, err, strerror(err));
+ return -err;
+ }
+ }
+
+ int mapId = bpfGetFdMapId(fd);
+ if (mapId == -1) {
+ ALOGE("bpfGetFdMapId failed, ret: %d [%d]", mapId, errno);
+ } else {
+ ALOGI("map %s id %d", mapPinLoc.c_str(), mapId);
+ }
+
+ mapFds.push_back(std::move(fd));
+ }
+
+ return ret;
+}
+
+/* For debugging, dump all instructions */
+static void dumpIns(char* ins, int size) {
+ for (int row = 0; row < size / 8; row++) {
+ ALOGE("%d: ", row);
+ for (int j = 0; j < 8; j++) {
+ ALOGE("%3x ", ins[(row * 8) + j]);
+ }
+ ALOGE("\n");
+ }
+}
+
+/* For debugging, dump all code sections from cs list */
+static void dumpAllCs(vector<codeSection>& cs) {
+ for (int i = 0; i < (int)cs.size(); i++) {
+ ALOGE("Dumping cs %d, name %s", int(i), cs[i].name.c_str());
+ dumpIns((char*)cs[i].data.data(), cs[i].data.size());
+ ALOGE("-----------");
+ }
+}
+
+static void applyRelo(void* insnsPtr, Elf64_Addr offset, int fd) {
+ int insnIndex;
+ struct bpf_insn *insn, *insns;
+
+ insns = (struct bpf_insn*)(insnsPtr);
+
+ insnIndex = offset / sizeof(struct bpf_insn);
+ insn = &insns[insnIndex];
+
+ // Occasionally might be useful for relocation debugging, but pretty spammy
+ if (0) {
+ ALOGD("applying relo to instruction at byte offset: %llu, "
+ "insn offset %d, insn %llx",
+ (unsigned long long)offset, insnIndex, *(unsigned long long*)insn);
+ }
+
+ if (insn->code != (BPF_LD | BPF_IMM | BPF_DW)) {
+ ALOGE("Dumping all instructions till ins %d", insnIndex);
+ ALOGE("invalid relo for insn %d: code 0x%x", insnIndex, insn->code);
+ dumpIns((char*)insnsPtr, (insnIndex + 3) * 8);
+ return;
+ }
+
+ insn->imm = fd;
+ insn->src_reg = BPF_PSEUDO_MAP_FD;
+}
+
+static void applyMapRelo(ifstream& elfFile, vector<unique_fd> &mapFds, vector<codeSection>& cs) {
+ vector<string> mapNames;
+
+ int ret = getSectionSymNames(elfFile, "maps", mapNames);
+ if (ret) return;
+
+ for (int k = 0; k != (int)cs.size(); k++) {
+ Elf64_Rel* rel = (Elf64_Rel*)(cs[k].rel_data.data());
+ int n_rel = cs[k].rel_data.size() / sizeof(*rel);
+
+ for (int i = 0; i < n_rel; i++) {
+ int symIndex = ELF64_R_SYM(rel[i].r_info);
+ string symName;
+
+ ret = getSymNameByIdx(elfFile, symIndex, symName);
+ if (ret) return;
+
+ /* Find the map fd and apply relo */
+ for (int j = 0; j < (int)mapNames.size(); j++) {
+ if (!mapNames[j].compare(symName)) {
+ applyRelo(cs[k].data.data(), rel[i].r_offset, mapFds[j]);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
+ const char* prefix) {
+ unsigned kvers = kernelVersion();
+
+ if (!kvers) {
+ ALOGE("unable to get kernel version");
+ return -EINVAL;
+ }
+
+ string objName = pathToObjName(string(elfPath));
+
+ for (int i = 0; i < (int)cs.size(); i++) {
+ unique_fd& fd = cs[i].prog_fd;
+ int ret;
+ string name = cs[i].name;
+
+ if (!cs[i].prog_def.has_value()) {
+ ALOGE("[%d] '%s' missing program definition! bad bpf.o build?", i, name.c_str());
+ return -EINVAL;
+ }
+
+ unsigned min_kver = cs[i].prog_def->min_kver;
+ unsigned max_kver = cs[i].prog_def->max_kver;
+ ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)", i, name.c_str(), min_kver,
+ max_kver, kvers);
+ if (kvers < min_kver) continue;
+ if (kvers >= max_kver) continue;
+
+ unsigned bpfMinVer = cs[i].prog_def->bpfloader_min_ver;
+ unsigned bpfMaxVer = cs[i].prog_def->bpfloader_max_ver;
+ domain selinux_context = getDomainFromSelinuxContext(cs[i].prog_def->selinux_context);
+ domain pin_subdir = getDomainFromPinSubdir(cs[i].prog_def->pin_subdir);
+ // Note: make sure to only check for unrecognized *after* verifying bpfloader
+ // version limits include this bpfloader's version.
+
+ ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)", i, name.c_str(),
+ bpfMinVer, bpfMaxVer);
+ if (BPFLOADER_VERSION < bpfMinVer) continue;
+ if (BPFLOADER_VERSION >= bpfMaxVer) continue;
+
+ if ((cs[i].prog_def->ignore_on_eng && isEng()) ||
+ (cs[i].prog_def->ignore_on_user && isUser()) ||
+ (cs[i].prog_def->ignore_on_userdebug && isUserdebug())) {
+ ALOGD("cs[%d].name:%s is ignored on %s builds", i, name.c_str(),
+ getBuildType().c_str());
+ continue;
+ }
+
+ if ((isArm() && isKernel32Bit() && cs[i].prog_def->ignore_on_arm32) ||
+ (isArm() && isKernel64Bit() && cs[i].prog_def->ignore_on_aarch64) ||
+ (isX86() && isKernel32Bit() && cs[i].prog_def->ignore_on_x86_32) ||
+ (isX86() && isKernel64Bit() && cs[i].prog_def->ignore_on_x86_64) ||
+ (isRiscV() && cs[i].prog_def->ignore_on_riscv64)) {
+ ALOGD("cs[%d].name:%s is ignored on %s", i, name.c_str(), describeArch());
+ continue;
+ }
+
+ if (unrecognized(pin_subdir)) return -ENOTDIR;
+
+ if (specified(selinux_context)) {
+ ALOGI("prog %s selinux_context [%-32s] -> %d -> '%s' (%s)", name.c_str(),
+ cs[i].prog_def->selinux_context, selinux_context,
+ lookupSelinuxContext(selinux_context), lookupPinSubdir(selinux_context));
+ }
+
+ if (specified(pin_subdir)) {
+ ALOGI("prog %s pin_subdir [%-32s] -> %d -> '%s'", name.c_str(),
+ cs[i].prog_def->pin_subdir, pin_subdir, lookupPinSubdir(pin_subdir));
+ }
+
+ // strip any potential $foo suffix
+ // this can be used to provide duplicate programs
+ // conditionally loaded based on running kernel version
+ name = name.substr(0, name.find_last_of('$'));
+
+ bool reuse = false;
+ // Format of pin location is
+ // /sys/fs/bpf/<prefix>prog_<objName>_<progName>
+ string progPinLoc = string(BPF_FS_PATH) + lookupPinSubdir(pin_subdir, prefix) + "prog_" +
+ objName + '_' + string(name);
+ if (access(progPinLoc.c_str(), F_OK) == 0) {
+ fd.reset(retrieveProgram(progPinLoc.c_str()));
+ ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd.get(),
+ (!fd.ok() ? std::strerror(errno) : "no error"));
+ reuse = true;
+ } else {
+ vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
+
+ union bpf_attr req = {
+ .prog_type = cs[i].type,
+ .kern_version = kvers,
+ .license = ptr_to_u64(license.c_str()),
+ .insns = ptr_to_u64(cs[i].data.data()),
+ .insn_cnt = static_cast<__u32>(cs[i].data.size() / sizeof(struct bpf_insn)),
+ .log_level = 1,
+ .log_buf = ptr_to_u64(log_buf.data()),
+ .log_size = static_cast<__u32>(log_buf.size()),
+ .expected_attach_type = cs[i].expected_attach_type,
+ };
+ strlcpy(req.prog_name, cs[i].name.c_str(), sizeof(req.prog_name));
+ fd.reset(bpf(BPF_PROG_LOAD, req));
+
+ ALOGD("BPF_PROG_LOAD call for %s (%s) returned fd: %d (%s)", elfPath,
+ cs[i].name.c_str(), fd.get(), (!fd.ok() ? std::strerror(errno) : "no error"));
+
+ if (!fd.ok()) {
+ vector<string> lines = android::base::Split(log_buf.data(), "\n");
+
+ ALOGW("BPF_PROG_LOAD - BEGIN log_buf contents:");
+ for (const auto& line : lines) ALOGW("%s", line.c_str());
+ ALOGW("BPF_PROG_LOAD - END log_buf contents.");
+
+ if (cs[i].prog_def->optional) {
+ ALOGW("failed program is marked optional - continuing...");
+ continue;
+ }
+ ALOGE("non-optional program failed to load.");
+ }
+ }
+
+ if (!fd.ok()) return fd.get();
+
+ if (!reuse) {
+ if (specified(selinux_context)) {
+ string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) +
+ "tmp_prog_" + objName + '_' + string(name);
+ ret = bpfFdPin(fd, createLoc.c_str());
+ if (ret) {
+ int err = errno;
+ ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err));
+ return -err;
+ }
+ ret = renameat2(AT_FDCWD, createLoc.c_str(),
+ AT_FDCWD, progPinLoc.c_str(), RENAME_NOREPLACE);
+ if (ret) {
+ int err = errno;
+ ALOGE("rename %s %s -> %d [%d:%s]", createLoc.c_str(), progPinLoc.c_str(), ret,
+ err, strerror(err));
+ return -err;
+ }
+ } else {
+ ret = bpfFdPin(fd, progPinLoc.c_str());
+ if (ret) {
+ int err = errno;
+ ALOGE("create %s -> %d [%d:%s]", progPinLoc.c_str(), ret, err, strerror(err));
+ return -err;
+ }
+ }
+ if (chmod(progPinLoc.c_str(), 0440)) {
+ int err = errno;
+ ALOGE("chmod %s 0440 -> [%d:%s]", progPinLoc.c_str(), err, strerror(err));
+ return -err;
+ }
+ if (chown(progPinLoc.c_str(), (uid_t)cs[i].prog_def->uid,
+ (gid_t)cs[i].prog_def->gid)) {
+ int err = errno;
+ ALOGE("chown %s %d %d -> [%d:%s]", progPinLoc.c_str(), cs[i].prog_def->uid,
+ cs[i].prog_def->gid, err, strerror(err));
+ return -err;
+ }
+ }
+
+ int progId = bpfGetFdProgId(fd);
+ if (progId == -1) {
+ ALOGE("bpfGetFdProgId failed, ret: %d [%d]", progId, errno);
+ } else {
+ ALOGI("prog %s id %d", progPinLoc.c_str(), progId);
+ }
+ }
+
+ return 0;
+}
+
+int loadProg(const char* elfPath, bool* isCritical, const Location& location) {
+ vector<char> license;
+ vector<char> critical;
+ vector<codeSection> cs;
+ vector<unique_fd> mapFds;
+ int ret;
+
+ if (!isCritical) return -1;
+ *isCritical = false;
+
+ ifstream elfFile(elfPath, ios::in | ios::binary);
+ if (!elfFile.is_open()) return -1;
+
+ ret = readSectionByName("critical", elfFile, critical);
+ *isCritical = !ret;
+
+ ret = readSectionByName("license", elfFile, license);
+ if (ret) {
+ ALOGE("Couldn't find license in %s", elfPath);
+ return ret;
+ } else {
+ ALOGD("Loading %s%s ELF object %s with license %s",
+ *isCritical ? "critical for " : "optional", *isCritical ? (char*)critical.data() : "",
+ elfPath, (char*)license.data());
+ }
+
+ // the following default values are for bpfloader V0.0 format which does not include them
+ unsigned int bpfLoaderMinVer =
+ readSectionUint("bpfloader_min_ver", elfFile, DEFAULT_BPFLOADER_MIN_VER);
+ unsigned int bpfLoaderMaxVer =
+ readSectionUint("bpfloader_max_ver", elfFile, DEFAULT_BPFLOADER_MAX_VER);
+ unsigned int bpfLoaderMinRequiredVer =
+ readSectionUint("bpfloader_min_required_ver", elfFile, 0);
+ size_t sizeOfBpfMapDef =
+ readSectionUint("size_of_bpf_map_def", elfFile, DEFAULT_SIZEOF_BPF_MAP_DEF);
+ size_t sizeOfBpfProgDef =
+ readSectionUint("size_of_bpf_prog_def", elfFile, DEFAULT_SIZEOF_BPF_PROG_DEF);
+
+ // inclusive lower bound check
+ if (BPFLOADER_VERSION < bpfLoaderMinVer) {
+ ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with min ver 0x%05x",
+ BPFLOADER_VERSION, elfPath, bpfLoaderMinVer);
+ return 0;
+ }
+
+ // exclusive upper bound check
+ if (BPFLOADER_VERSION >= bpfLoaderMaxVer) {
+ ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with max ver 0x%05x",
+ BPFLOADER_VERSION, elfPath, bpfLoaderMaxVer);
+ return 0;
+ }
+
+ if (BPFLOADER_VERSION < bpfLoaderMinRequiredVer) {
+ ALOGI("BpfLoader version 0x%05x failing due to ELF object %s with required min ver 0x%05x",
+ BPFLOADER_VERSION, elfPath, bpfLoaderMinRequiredVer);
+ return -1;
+ }
+
+ ALOGI("BpfLoader version 0x%05x processing ELF object %s with ver [0x%05x,0x%05x)",
+ BPFLOADER_VERSION, elfPath, bpfLoaderMinVer, bpfLoaderMaxVer);
+
+ if (sizeOfBpfMapDef < DEFAULT_SIZEOF_BPF_MAP_DEF) {
+ ALOGE("sizeof(bpf_map_def) of %zu is too small (< %d)", sizeOfBpfMapDef,
+ DEFAULT_SIZEOF_BPF_MAP_DEF);
+ return -1;
+ }
+
+ if (sizeOfBpfProgDef < DEFAULT_SIZEOF_BPF_PROG_DEF) {
+ ALOGE("sizeof(bpf_prog_def) of %zu is too small (< %d)", sizeOfBpfProgDef,
+ DEFAULT_SIZEOF_BPF_PROG_DEF);
+ return -1;
+ }
+
+ ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef);
+ if (ret) {
+ ALOGE("Couldn't read all code sections in %s", elfPath);
+ return ret;
+ }
+
+ /* Just for future debugging */
+ if (0) dumpAllCs(cs);
+
+ ret = createMaps(elfPath, elfFile, mapFds, location.prefix, sizeOfBpfMapDef);
+ if (ret) {
+ ALOGE("Failed to create maps: (ret=%d) in %s", ret, elfPath);
+ return ret;
+ }
+
+ for (int i = 0; i < (int)mapFds.size(); i++)
+ ALOGD("map_fd found at %d is %d in %s", i, mapFds[i].get(), elfPath);
+
+ applyMapRelo(elfFile, mapFds, cs);
+
+ ret = loadCodeSections(elfPath, cs, string(license.data()), location.prefix);
+ if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d", ret);
+
+ return ret;
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/netbpfload/loader.h b/netbpfload/loader.h
new file mode 100644
index 0000000..b884637
--- /dev/null
+++ b/netbpfload/loader.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018-2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/bpf.h>
+
+#include <fstream>
+
+namespace android {
+namespace bpf {
+
+// Bpf programs may specify per-program & per-map selinux_context and pin_subdir.
+//
+// The BpfLoader needs to convert these bpf.o specified strings into an enum
+// for internal use (to check that valid values were specified for the specific
+// location of the bpf.o file).
+//
+// It also needs to map selinux_context's into pin_subdir's.
+// This is because of how selinux_context is actually implemented via pin+rename.
+//
+// Thus 'domain' enumerates all selinux_context's/pin_subdir's that the BpfLoader
+// is aware of. Thus there currently needs to be a 1:1 mapping between the two.
+//
+enum class domain : int {
+ unrecognized = -1, // invalid for this version of the bpfloader
+ unspecified = 0, // means just use the default for that specific pin location
+ tethering, // (S+) fs_bpf_tethering /sys/fs/bpf/tethering
+ net_private, // (T+) fs_bpf_net_private /sys/fs/bpf/net_private
+ net_shared, // (T+) fs_bpf_net_shared /sys/fs/bpf/net_shared
+ netd_readonly, // (T+) fs_bpf_netd_readonly /sys/fs/bpf/netd_readonly
+ netd_shared, // (T+) fs_bpf_netd_shared /sys/fs/bpf/netd_shared
+};
+
+// Note: this does not include domain::unrecognized, but does include domain::unspecified
+static constexpr domain AllDomains[] = {
+ domain::unspecified,
+ domain::tethering,
+ domain::net_private,
+ domain::net_shared,
+ domain::netd_readonly,
+ domain::netd_shared,
+};
+
+static constexpr bool unrecognized(domain d) {
+ return d == domain::unrecognized;
+}
+
+// Note: this doesn't handle unrecognized, handle it first.
+static constexpr bool specified(domain d) {
+ return d != domain::unspecified;
+}
+
+struct Location {
+ const char* const dir = "";
+ const char* const prefix = "";
+};
+
+// BPF loader implementation. Loads an eBPF ELF object
+int loadProg(const char* elfPath, bool* isCritical, const Location &location = {});
+
+// Exposed for testing
+unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal);
+
+// Returns the build type string (from ro.build.type).
+const std::string& getBuildType();
+
+// The following functions classify the 3 Android build types.
+inline bool isEng() {
+ return getBuildType() == "eng";
+}
+inline bool isUser() {
+ return getBuildType() == "user";
+}
+inline bool isUserdebug() {
+ return getBuildType() == "userdebug";
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index fc680d9..a7a4059 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -85,8 +85,24 @@
// U bumps the kernel requirement up to 4.14
if (modules::sdklevel::IsAtLeastU() && !bpf::isAtLeastKernelVersion(4, 14, 0)) abort();
- // V bumps the kernel requirement up to 4.19
- if (modules::sdklevel::IsAtLeastV() && !bpf::isAtLeastKernelVersion(4, 19, 0)) abort();
+ if (modules::sdklevel::IsAtLeastV()) {
+ // V bumps the kernel requirement up to 4.19
+ // see also: //system/netd/tests/kernel_test.cpp TestKernel419
+ if (!bpf::isAtLeastKernelVersion(4, 19, 0)) abort();
+
+ // Technically already required by U, but only enforce on V+
+ // see also: //system/netd/tests/kernel_test.cpp TestKernel64Bit
+ if (bpf::isKernel32Bit() && bpf::isAtLeastKernelVersion(5, 16, 0)) abort();
+ }
+
+ // Linux 6.1 is highest version supported by U, starting with V new kernels,
+ // ie. 6.2+ we are dropping various kernel/system userspace 32-on-64 hacks
+ // (for example "ANDROID: xfrm: remove in_compat_syscall() checks").
+ // Note: this check/enforcement only applies to *system* userspace code,
+ // it does not affect unprivileged apps, the 32-on-64 compatibility
+ // problems are AFAIK limited to various CAP_NET_ADMIN protected interfaces.
+ // see also: //system/bpf/bpfloader/BpfLoader.cpp main()
+ if (bpf::isUserspace32bit() && bpf::isAtLeastKernelVersion(6, 2, 0)) abort();
// U mandates this mount point (though it should also be the case on T)
if (modules::sdklevel::IsAtLeastU() && !!strcmp(cg2_path, "/sys/fs/cgroup")) abort();
@@ -113,6 +129,24 @@
RETURN_IF_NOT_OK(
attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
}
+
+ if (bpf::isAtLeastKernelVersion(4, 19, 0)) {
+ RETURN_IF_NOT_OK(attachProgramToCgroup(
+ "/sys/fs/bpf/netd_readonly/prog_block_bind4_block_port",
+ cg_fd, BPF_CGROUP_INET4_BIND));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(
+ "/sys/fs/bpf/netd_readonly/prog_block_bind6_block_port",
+ cg_fd, BPF_CGROUP_INET6_BIND));
+
+ // This should trivially pass, since we just attached up above,
+ // but BPF_PROG_QUERY is only implemented on 4.19+ kernels.
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_EGRESS) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_INGRESS) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_CREATE) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET4_BIND) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET6_BIND) <= 0) abort();
+ }
+
return netdutils::status::ok;
}
@@ -214,7 +248,7 @@
// which might toggle the live stats map and clean it.
const auto countUidStatsEntries = [chargeUid, &totalEntryCount, &perUidEntryCount](
const StatsKey& key,
- const BpfMap<StatsKey, StatsValue>&) {
+ const BpfMapRO<StatsKey, StatsValue>&) {
if (key.uid == chargeUid) {
perUidEntryCount++;
}
@@ -232,9 +266,8 @@
return -EINVAL;
}
- BpfMap<StatsKey, StatsValue>& currentMap =
+ BpfMapRO<StatsKey, StatsValue>& currentMap =
(configuration.value() == SELECT_MAP_A) ? mStatsMapA : mStatsMapB;
- // HACK: mStatsMapB becomes RW BpfMap here, but countUidStatsEntries doesn't modify so it works
base::Result<void> res = currentMap.iterate(countUidStatsEntries);
if (!res.ok()) {
ALOGE("Failed to count the stats entry in map: %s",
diff --git a/netd/BpfHandler.h b/netd/BpfHandler.h
index a6da4eb..9e69efc 100644
--- a/netd/BpfHandler.h
+++ b/netd/BpfHandler.h
@@ -59,10 +59,10 @@
bool hasUpdateDeviceStatsPermission(uid_t uid);
BpfMap<uint64_t, UidTagValue> mCookieTagMap;
- BpfMap<StatsKey, StatsValue> mStatsMapA;
+ BpfMapRO<StatsKey, StatsValue> mStatsMapA;
BpfMapRO<StatsKey, StatsValue> mStatsMapB;
BpfMapRO<uint32_t, uint32_t> mConfigurationMap;
- BpfMap<uint32_t, uint8_t> mUidPermissionMap;
+ BpfMapRO<uint32_t, uint8_t> mUidPermissionMap;
// The limit on the number of stats entries a uid can have in the per uid stats map. BpfHandler
// will block that specific uid from tagging new sockets after the limit is reached.
diff --git a/netd/BpfHandlerTest.cpp b/netd/BpfHandlerTest.cpp
index f5c9a68..b38fa16 100644
--- a/netd/BpfHandlerTest.cpp
+++ b/netd/BpfHandlerTest.cpp
@@ -49,7 +49,7 @@
BpfHandler mBh;
BpfMap<uint64_t, UidTagValue> mFakeCookieTagMap;
BpfMap<StatsKey, StatsValue> mFakeStatsMapA;
- BpfMapRO<uint32_t, uint32_t> mFakeConfigurationMap;
+ BpfMap<uint32_t, uint32_t> mFakeConfigurationMap;
BpfMap<uint32_t, uint8_t> mFakeUidPermissionMap;
void SetUp() {
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index ae5fe5c..98ed2b2 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -18,7 +18,7 @@
filegroup {
name: "remoteauth-service-srcs",
- srcs: ["java/**/*.java"],
+ srcs: [],
}
// Main lib for remoteauth services.
diff --git a/remoteauth/tests/unit/Android.bp b/remoteauth/tests/unit/Android.bp
index 37c78c7..a21c033 100644
--- a/remoteauth/tests/unit/Android.bp
+++ b/remoteauth/tests/unit/Android.bp
@@ -20,13 +20,13 @@
name: "RemoteAuthUnitTests",
defaults: [
"enable-remoteauth-targets",
- "mts-target-sdk-version-current"
+ "mts-target-sdk-version-current",
],
sdk_version: "test_current",
min_sdk_version: "31",
// Include all test java files.
- srcs: ["src/**/*.java"],
+ srcs: [],
libs: [
"android.test.base",
@@ -45,7 +45,7 @@
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"service-remoteauth-pre-jarjar",
- "truth-prebuilt",
+ "truth",
],
// these are needed for Extended Mockito
jni_libs: [
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 55a0712..7e588cd 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -102,7 +102,12 @@
],
exclude_srcs: [
"src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java",
- "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java"
+ "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java",
+ "src/com/android/server/connectivity/mdns/MdnsAdvertiser.java",
+ "src/com/android/server/connectivity/mdns/MdnsAnnouncer.java",
+ "src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java",
+ "src/com/android/server/connectivity/mdns/MdnsProber.java",
+ "src/com/android/server/connectivity/mdns/MdnsRecordRepository.java",
],
static_libs: [
"net-utils-device-common-mdns-standalone-build-test",
diff --git a/service-t/Sources.bp b/service-t/Sources.bp
index 187eadf..fbe02a5 100644
--- a/service-t/Sources.bp
+++ b/service-t/Sources.bp
@@ -20,7 +20,6 @@
srcs: [
"jni/com_android_server_net_NetworkStatsFactory.cpp",
],
- path: "jni",
visibility: [
"//packages/modules/Connectivity:__subpackages__",
],
@@ -32,7 +31,6 @@
"jni/com_android_server_net_NetworkStatsFactory.cpp",
"jni/com_android_server_net_NetworkStatsService.cpp",
],
- path: "jni",
visibility: [
"//packages/modules/Connectivity:__subpackages__",
],
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
index fed2979..3101397 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -41,7 +41,7 @@
using base::Result;
int bpfGetUidStatsInternal(uid_t uid, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& appUidStatsMap) {
+ const BpfMapRO<uint32_t, StatsValue>& appUidStatsMap) {
auto statsEntry = appUidStatsMap.readValue(uid);
if (!statsEntry.ok()) {
*stats = {};
@@ -57,14 +57,14 @@
}
int bpfGetIfaceStatsInternal(const char* iface, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceNameMap) {
+ const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceNameMap) {
*stats = {};
int64_t unknownIfaceBytesTotal = 0;
const auto processIfaceStats =
[iface, stats, &ifaceNameMap, &unknownIfaceBytesTotal](
const uint32_t& key,
- const BpfMap<uint32_t, StatsValue>& ifaceStatsMap) -> Result<void> {
+ const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap) -> Result<void> {
char ifname[IFNAMSIZ];
if (getIfaceNameFromMap(ifaceNameMap, ifaceStatsMap, key, ifname, key,
&unknownIfaceBytesTotal)) {
@@ -90,7 +90,7 @@
}
int bpfGetIfIndexStatsInternal(uint32_t ifindex, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& ifaceStatsMap) {
+ const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap) {
auto statsEntry = ifaceStatsMap.readValue(ifindex);
if (!statsEntry.ok()) {
*stats = {};
@@ -120,13 +120,13 @@
}
int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
- const BpfMap<StatsKey, StatsValue>& statsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
+ const BpfMapRO<StatsKey, StatsValue>& statsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceMap) {
int64_t unknownIfaceBytesTotal = 0;
const auto processDetailUidStats =
[&lines, &unknownIfaceBytesTotal, &ifaceMap](
const StatsKey& key,
- const BpfMap<StatsKey, StatsValue>& statsMap) -> Result<void> {
+ const BpfMapRO<StatsKey, StatsValue>& statsMap) -> Result<void> {
char ifname[IFNAMSIZ];
if (getIfaceNameFromMap(ifaceMap, statsMap, key.ifaceIndex, ifname, key,
&unknownIfaceBytesTotal)) {
@@ -212,12 +212,12 @@
}
int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
- const BpfMap<uint32_t, StatsValue>& statsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
+ const BpfMapRO<uint32_t, StatsValue>& statsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceMap) {
int64_t unknownIfaceBytesTotal = 0;
const auto processDetailIfaceStats = [&lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
const uint32_t& key, const StatsValue& value,
- const BpfMap<uint32_t, StatsValue>&) {
+ const BpfMapRO<uint32_t, StatsValue>&) {
char ifname[IFNAMSIZ];
if (getIfaceNameFromMap(ifaceMap, statsMap, key, ifname, key, &unknownIfaceBytesTotal)) {
return Result<void>();
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
index 76c56eb..bcc4550 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
@@ -80,19 +80,19 @@
void SetUp() {
ASSERT_EQ(0, setrlimitForTest());
- mFakeCookieTagMap = BpfMap<uint64_t, UidTagValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
+ mFakeCookieTagMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE);
ASSERT_TRUE(mFakeCookieTagMap.isValid());
- mFakeAppUidStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
+ mFakeAppUidStatsMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE);
ASSERT_TRUE(mFakeAppUidStatsMap.isValid());
- mFakeStatsMap = BpfMap<StatsKey, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
+ mFakeStatsMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE);
ASSERT_TRUE(mFakeStatsMap.isValid());
- mFakeIfaceIndexNameMap = BpfMap<uint32_t, IfaceValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
+ mFakeIfaceIndexNameMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE);
ASSERT_TRUE(mFakeIfaceIndexNameMap.isValid());
- mFakeIfaceStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
+ mFakeIfaceStatsMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE);
ASSERT_TRUE(mFakeIfaceStatsMap.isValid());
}
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
index ec63e41..9b1b72d 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -18,6 +18,7 @@
#include "netdbpf/NetworkTraceHandler.h"
+#include <android-base/macros.h>
#include <arpa/inet.h>
#include <bpf/BpfUtils.h>
#include <log/log.h>
@@ -75,9 +76,35 @@
uint32_t bytes = 0;
};
-#define AGG_FIELDS(x) \
- (x).ifindex, (x).uid, (x).tag, (x).sport, (x).dport, (x).egress, \
- (x).ipProto, (x).tcpFlags
+BundleKey::BundleKey(const PacketTrace& pkt)
+ : ifindex(pkt.ifindex),
+ uid(pkt.uid),
+ tag(pkt.tag),
+ egress(pkt.egress),
+ ipProto(pkt.ipProto),
+ ipVersion(pkt.ipVersion) {
+ switch (ipProto) {
+ case IPPROTO_TCP:
+ tcpFlags = pkt.tcpFlags;
+ FALLTHROUGH_INTENDED;
+ case IPPROTO_DCCP:
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ case IPPROTO_SCTP:
+ localPort = ntohs(pkt.egress ? pkt.sport : pkt.dport);
+ remotePort = ntohs(pkt.egress ? pkt.dport : pkt.sport);
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ icmpType = ntohs(pkt.sport);
+ icmpCode = ntohs(pkt.dport);
+ break;
+ }
+}
+
+#define AGG_FIELDS(x) \
+ (x).ifindex, (x).uid, (x).tag, (x).egress, (x).ipProto, (x).ipVersion, \
+ (x).tcpFlags, (x).localPort, (x).remotePort, (x).icmpType, (x).icmpCode
std::size_t BundleHash::operator()(const BundleKey& a) const {
std::size_t seed = 0;
@@ -179,7 +206,7 @@
dst->set_timestamp(pkt.timestampNs);
auto* event = dst->set_network_packet();
event->set_length(pkt.length);
- Fill(pkt, event);
+ Fill(BundleKey(pkt), event);
}
return;
}
@@ -187,14 +214,13 @@
uint64_t minTs = std::numeric_limits<uint64_t>::max();
std::unordered_map<BundleKey, BundleDetails, BundleHash, BundleEq> bundles;
for (const PacketTrace& pkt : packets) {
- BundleKey key = pkt;
+ BundleKey key(pkt);
// Dropping fields should remove them from the output and remove them from
- // the aggregation key. In order to do the latter without changing the hash
- // function, set the dropped fields to zero.
- if (mDropTcpFlags) key.tcpFlags = 0;
- if (mDropLocalPort) (key.egress ? key.sport : key.dport) = 0;
- if (mDropRemotePort) (key.egress ? key.dport : key.sport) = 0;
+ // the aggregation key. Reset the optionals to indicate omission.
+ if (mDropTcpFlags) key.tcpFlags.reset();
+ if (mDropLocalPort) key.localPort.reset();
+ if (mDropRemotePort) key.remotePort.reset();
minTs = std::min(minTs, pkt.timestampNs);
@@ -245,22 +271,18 @@
}
}
-void NetworkTraceHandler::Fill(const PacketTrace& src,
+void NetworkTraceHandler::Fill(const BundleKey& src,
NetworkPacketEvent* event) {
event->set_direction(src.egress ? TrafficDirection::DIR_EGRESS
: TrafficDirection::DIR_INGRESS);
event->set_uid(src.uid);
event->set_tag(src.tag);
- if (!mDropLocalPort) {
- event->set_local_port(ntohs(src.egress ? src.sport : src.dport));
- }
- if (!mDropRemotePort) {
- event->set_remote_port(ntohs(src.egress ? src.dport : src.sport));
- }
- if (!mDropTcpFlags) {
- event->set_tcp_flags(src.tcpFlags);
- }
+ if (src.tcpFlags.has_value()) event->set_tcp_flags(*src.tcpFlags);
+ if (src.localPort.has_value()) event->set_local_port(*src.localPort);
+ if (src.remotePort.has_value()) event->set_remote_port(*src.remotePort);
+ if (src.icmpType.has_value()) event->set_icmp_type(*src.icmpType);
+ if (src.icmpCode.has_value()) event->set_icmp_code(*src.icmpCode);
event->set_ip_proto(src.ipProto);
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
index f2c1a86..0c4f049 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandlerTest.cpp
@@ -113,7 +113,7 @@
.length = 100,
.uid = 10,
.tag = 123,
- .ipProto = 6,
+ .ipProto = IPPROTO_TCP,
.tcpFlags = 1,
},
};
@@ -138,12 +138,14 @@
.sport = htons(8080),
.dport = htons(443),
.egress = true,
+ .ipProto = IPPROTO_TCP,
},
PacketTrace{
.timestampNs = 2,
.sport = htons(443),
.dport = htons(8080),
.egress = false,
+ .ipProto = IPPROTO_TCP,
},
};
@@ -161,6 +163,42 @@
TrafficDirection::DIR_INGRESS);
}
+TEST_F(NetworkTraceHandlerTest, WriteIcmpTypeAndCode) {
+ std::vector<PacketTrace> input = {
+ PacketTrace{
+ .timestampNs = 1,
+ .sport = htons(11), // type
+ .dport = htons(22), // code
+ .egress = true,
+ .ipProto = IPPROTO_ICMP,
+ },
+ PacketTrace{
+ .timestampNs = 2,
+ .sport = htons(33), // type
+ .dport = htons(44), // code
+ .egress = false,
+ .ipProto = IPPROTO_ICMPV6,
+ },
+ };
+
+ std::vector<TracePacket> events;
+ ASSERT_TRUE(TraceAndSortPackets(input, &events));
+
+ ASSERT_EQ(events.size(), 2);
+ EXPECT_FALSE(events[0].network_packet().has_local_port());
+ EXPECT_FALSE(events[0].network_packet().has_remote_port());
+ EXPECT_THAT(events[0].network_packet().icmp_type(), 11);
+ EXPECT_THAT(events[0].network_packet().icmp_code(), 22);
+ EXPECT_THAT(events[0].network_packet().direction(),
+ TrafficDirection::DIR_EGRESS);
+ EXPECT_FALSE(events[1].network_packet().local_port());
+ EXPECT_FALSE(events[1].network_packet().remote_port());
+ EXPECT_THAT(events[1].network_packet().icmp_type(), 33);
+ EXPECT_THAT(events[1].network_packet().icmp_code(), 44);
+ EXPECT_THAT(events[1].network_packet().direction(),
+ TrafficDirection::DIR_INGRESS);
+}
+
TEST_F(NetworkTraceHandlerTest, BasicBundling) {
// TODO: remove this once bundling becomes default. Until then, set arbitrary
// aggregation threshold to enable bundling.
@@ -168,12 +206,12 @@
config.set_aggregation_threshold(10);
std::vector<PacketTrace> input = {
- PacketTrace{.uid = 123, .timestampNs = 2, .length = 200},
- PacketTrace{.uid = 123, .timestampNs = 1, .length = 100},
- PacketTrace{.uid = 123, .timestampNs = 4, .length = 300},
+ PacketTrace{.timestampNs = 2, .length = 200, .uid = 123},
+ PacketTrace{.timestampNs = 1, .length = 100, .uid = 123},
+ PacketTrace{.timestampNs = 4, .length = 300, .uid = 123},
- PacketTrace{.uid = 456, .timestampNs = 2, .length = 400},
- PacketTrace{.uid = 456, .timestampNs = 4, .length = 100},
+ PacketTrace{.timestampNs = 2, .length = 400, .uid = 456},
+ PacketTrace{.timestampNs = 4, .length = 100, .uid = 456},
};
std::vector<TracePacket> events;
@@ -203,12 +241,12 @@
config.set_aggregation_threshold(3);
std::vector<PacketTrace> input = {
- PacketTrace{.uid = 123, .timestampNs = 2, .length = 200},
- PacketTrace{.uid = 123, .timestampNs = 1, .length = 100},
- PacketTrace{.uid = 123, .timestampNs = 4, .length = 300},
+ PacketTrace{.timestampNs = 2, .length = 200, .uid = 123},
+ PacketTrace{.timestampNs = 1, .length = 100, .uid = 123},
+ PacketTrace{.timestampNs = 4, .length = 300, .uid = 123},
- PacketTrace{.uid = 456, .timestampNs = 2, .length = 400},
- PacketTrace{.uid = 456, .timestampNs = 4, .length = 100},
+ PacketTrace{.timestampNs = 2, .length = 400, .uid = 456},
+ PacketTrace{.timestampNs = 4, .length = 100, .uid = 456},
};
std::vector<TracePacket> events;
@@ -239,12 +277,17 @@
__be16 b = htons(10001);
std::vector<PacketTrace> input = {
// Recall that local is `src` for egress and `dst` for ingress.
- PacketTrace{.timestampNs = 1, .length = 2, .egress = true, .sport = a},
- PacketTrace{.timestampNs = 2, .length = 4, .egress = false, .dport = a},
- PacketTrace{.timestampNs = 3, .length = 6, .egress = true, .sport = b},
- PacketTrace{.timestampNs = 4, .length = 8, .egress = false, .dport = b},
+ PacketTrace{.timestampNs = 1, .length = 2, .sport = a, .egress = true},
+ PacketTrace{.timestampNs = 2, .length = 4, .dport = a, .egress = false},
+ PacketTrace{.timestampNs = 3, .length = 6, .sport = b, .egress = true},
+ PacketTrace{.timestampNs = 4, .length = 8, .dport = b, .egress = false},
};
+ // Set common fields.
+ for (PacketTrace& pkt : input) {
+ pkt.ipProto = IPPROTO_TCP;
+ }
+
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
ASSERT_EQ(events.size(), 2);
@@ -274,12 +317,17 @@
__be16 b = htons(80);
std::vector<PacketTrace> input = {
// Recall that remote is `dst` for egress and `src` for ingress.
- PacketTrace{.timestampNs = 1, .length = 2, .egress = true, .dport = a},
- PacketTrace{.timestampNs = 2, .length = 4, .egress = false, .sport = a},
- PacketTrace{.timestampNs = 3, .length = 6, .egress = true, .dport = b},
- PacketTrace{.timestampNs = 4, .length = 8, .egress = false, .sport = b},
+ PacketTrace{.timestampNs = 1, .length = 2, .dport = a, .egress = true},
+ PacketTrace{.timestampNs = 2, .length = 4, .sport = a, .egress = false},
+ PacketTrace{.timestampNs = 3, .length = 6, .dport = b, .egress = true},
+ PacketTrace{.timestampNs = 4, .length = 8, .sport = b, .egress = false},
};
+ // Set common fields.
+ for (PacketTrace& pkt : input) {
+ pkt.ipProto = IPPROTO_TCP;
+ }
+
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
ASSERT_EQ(events.size(), 2);
@@ -306,12 +354,17 @@
config.set_aggregation_threshold(10);
std::vector<PacketTrace> input = {
- PacketTrace{.timestampNs = 1, .uid = 123, .length = 1, .tcpFlags = 1},
- PacketTrace{.timestampNs = 2, .uid = 123, .length = 2, .tcpFlags = 2},
- PacketTrace{.timestampNs = 3, .uid = 456, .length = 3, .tcpFlags = 1},
- PacketTrace{.timestampNs = 4, .uid = 456, .length = 4, .tcpFlags = 2},
+ PacketTrace{.timestampNs = 1, .length = 1, .uid = 123, .tcpFlags = 1},
+ PacketTrace{.timestampNs = 2, .length = 2, .uid = 123, .tcpFlags = 2},
+ PacketTrace{.timestampNs = 3, .length = 3, .uid = 456, .tcpFlags = 1},
+ PacketTrace{.timestampNs = 4, .length = 4, .uid = 456, .tcpFlags = 2},
};
+ // Set common fields.
+ for (PacketTrace& pkt : input) {
+ pkt.ipProto = IPPROTO_TCP;
+ }
+
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
index ea068fc..8058d05 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
@@ -57,24 +57,25 @@
// For test only
int bpfGetUidStatsInternal(uid_t uid, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& appUidStatsMap);
+ const BpfMapRO<uint32_t, StatsValue>& appUidStatsMap);
// For test only
int bpfGetIfaceStatsInternal(const char* iface, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceNameMap);
+ const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceNameMap);
// For test only
int bpfGetIfIndexStatsInternal(uint32_t ifindex, StatsValue* stats,
- const BpfMap<uint32_t, StatsValue>& ifaceStatsMap);
+ const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap);
// For test only
int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
- const BpfMap<StatsKey, StatsValue>& statsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceMap);
+ const BpfMapRO<StatsKey, StatsValue>& statsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceMap);
// For test only
int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap);
// For test only
template <class Key>
-int getIfaceNameFromMap(const BpfMap<uint32_t, IfaceValue>& ifaceMap,
- const BpfMap<Key, StatsValue>& statsMap, uint32_t ifaceIndex, char* ifname,
+int getIfaceNameFromMap(const BpfMapRO<uint32_t, IfaceValue>& ifaceMap,
+ const BpfMapRO<Key, StatsValue>& statsMap,
+ uint32_t ifaceIndex, char* ifname,
const Key& curKey, int64_t* unknownIfaceBytesTotal) {
auto iface = ifaceMap.readValue(ifaceIndex);
if (!iface.ok()) {
@@ -86,7 +87,7 @@
}
template <class Key>
-void maybeLogUnknownIface(int ifaceIndex, const BpfMap<Key, StatsValue>& statsMap,
+void maybeLogUnknownIface(int ifaceIndex, const BpfMapRO<Key, StatsValue>& statsMap,
const Key& curKey, int64_t* unknownIfaceBytesTotal) {
// Have we already logged an error?
if (*unknownIfaceBytesTotal == -1) {
@@ -110,8 +111,8 @@
// For test only
int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
- const BpfMap<uint32_t, StatsValue>& statsMap,
- const BpfMap<uint32_t, IfaceValue>& ifaceMap);
+ const BpfMapRO<uint32_t, StatsValue>& statsMap,
+ const BpfMapRO<uint32_t, IfaceValue>& ifaceMap);
int bpfGetUidStats(uid_t uid, StatsValue* stats);
int bpfGetIfaceStats(const char* iface, StatsValue* stats);
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
index bc10e68..6bf186a 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/NetworkTraceHandler.h
@@ -30,15 +30,33 @@
namespace android {
namespace bpf {
-// BundleKeys are PacketTraces where timestamp and length are ignored.
-using BundleKey = PacketTrace;
+// BundleKey encodes a PacketTrace minus timestamp and length. The key should
+// match many packets over time for interning. For convenience, sport/dport
+// are parsed here as either local/remote port or icmp type/code.
+struct BundleKey {
+ explicit BundleKey(const PacketTrace& pkt);
-// BundleKeys are hashed using all fields except timestamp/length.
+ uint32_t ifindex;
+ uint32_t uid;
+ uint32_t tag;
+
+ bool egress;
+ uint8_t ipProto;
+ uint8_t ipVersion;
+
+ std::optional<uint8_t> tcpFlags;
+ std::optional<uint16_t> localPort;
+ std::optional<uint16_t> remotePort;
+ std::optional<uint8_t> icmpType;
+ std::optional<uint8_t> icmpCode;
+};
+
+// BundleKeys are hashed using a simple hash combine.
struct BundleHash {
std::size_t operator()(const BundleKey& a) const;
};
-// BundleKeys are equal if all fields except timestamp/length are equal.
+// BundleKeys are equal if all fields are equal.
struct BundleEq {
bool operator()(const BundleKey& a, const BundleKey& b) const;
};
@@ -84,13 +102,13 @@
NetworkTraceHandler::TraceContext& ctx);
private:
- // Convert a PacketTrace into a Perfetto trace packet.
- void Fill(const PacketTrace& src,
+ // Fills in contextual information from a bundle without interning.
+ void Fill(const BundleKey& src,
::perfetto::protos::pbzero::NetworkPacketEvent* event);
// Fills in contextual information either inline or via interning.
::perfetto::protos::pbzero::NetworkPacketBundle* FillWithInterning(
- NetworkTraceState* state, const BundleKey& key,
+ NetworkTraceState* state, const BundleKey& src,
::perfetto::protos::pbzero::TracePacket* dst);
static internal::NetworkTracePoller sPoller;
diff --git a/service-t/src/com/android/server/ConnectivityServiceInitializer.java b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
index 003ec8c..1ac2f6e 100644
--- a/service-t/src/com/android/server/ConnectivityServiceInitializer.java
+++ b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
@@ -28,7 +28,6 @@
import com.android.server.ethernet.EthernetService;
import com.android.server.ethernet.EthernetServiceImpl;
import com.android.server.nearby.NearbyService;
-import com.android.server.remoteauth.RemoteAuthService;
import com.android.server.thread.ThreadNetworkService;
/**
@@ -43,7 +42,6 @@
private final NsdService mNsdService;
private final NearbyService mNearbyService;
private final EthernetServiceImpl mEthernetServiceImpl;
- private final RemoteAuthService mRemoteAuthService;
private final ThreadNetworkService mThreadNetworkService;
public ConnectivityServiceInitializer(Context context) {
@@ -56,7 +54,6 @@
mConnectivityNative = createConnectivityNativeService(context);
mNsdService = createNsdService(context);
mNearbyService = createNearbyService(context);
- mRemoteAuthService = createRemoteAuthService(context);
mThreadNetworkService = createThreadNetworkService(context);
}
@@ -94,12 +91,6 @@
/* allowIsolated= */ false);
}
- if (mRemoteAuthService != null) {
- Log.i(TAG, "Registering " + RemoteAuthService.SERVICE_NAME);
- publishBinderService(RemoteAuthService.SERVICE_NAME, mRemoteAuthService,
- /* allowIsolated= */ false);
- }
-
if (mThreadNetworkService != null) {
Log.i(TAG, "Registering " + ThreadNetworkManager.SERVICE_NAME);
publishBinderService(ThreadNetworkManager.SERVICE_NAME, mThreadNetworkService,
@@ -164,19 +155,6 @@
}
}
- /** Return RemoteAuth service instance */
- private RemoteAuthService createRemoteAuthService(final Context context) {
- if (!SdkLevel.isAtLeastV()) return null;
- try {
- return new RemoteAuthService(context);
- } catch (UnsupportedOperationException e) {
- // RemoteAuth is not yet supported in all branches
- // TODO: remove catch clause when it is available.
- Log.i(TAG, "Skipping unsupported service " + RemoteAuthService.SERVICE_NAME);
- return null;
- }
- }
-
/**
* Return EthernetServiceImpl instance or null if current SDK is lower than T or Ethernet
* service isn't necessary.
diff --git a/service-t/src/com/android/server/NetworkStatsServiceInitializer.java b/service-t/src/com/android/server/NetworkStatsServiceInitializer.java
index 82a4fbd..675e5a1 100644
--- a/service-t/src/com/android/server/NetworkStatsServiceInitializer.java
+++ b/service-t/src/com/android/server/NetworkStatsServiceInitializer.java
@@ -22,6 +22,7 @@
import android.util.Log;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.DeviceConfigUtils;
import com.android.server.net.NetworkStatsService;
/**
@@ -30,6 +31,8 @@
*/
public final class NetworkStatsServiceInitializer extends SystemService {
private static final String TAG = NetworkStatsServiceInitializer.class.getSimpleName();
+ private static final String ENABLE_NETWORK_TRACING = "enable_network_tracing";
+ private final boolean mNetworkTracingFlagEnabled;
private final NetworkStatsService mStatsService;
public NetworkStatsServiceInitializer(Context context) {
@@ -37,6 +40,8 @@
// Load JNI libraries used by NetworkStatsService and its dependencies
System.loadLibrary("service-connectivity");
mStatsService = maybeCreateNetworkStatsService(context);
+ mNetworkTracingFlagEnabled = DeviceConfigUtils.isTetheringFeatureEnabled(
+ context, ENABLE_NETWORK_TRACING);
}
@Override
@@ -48,11 +53,10 @@
TrafficStats.init(getContext());
}
- // The following code registers the Perfetto Network Trace Handler on non-user builds.
- // The enhanced tracing is intended to be used for debugging and diagnosing issues. This
- // is conditional on the build type rather than `isDebuggable` to match the system_server
- // selinux rules which only allow the Perfetto connection under the same circumstances.
- if (SdkLevel.isAtLeastU() && !Build.TYPE.equals("user")) {
+ // The following code registers the Perfetto Network Trace Handler. The enhanced tracing
+ // is intended to be used for debugging and diagnosing issues. This is enabled by default
+ // on userdebug/eng builds and flag protected in user builds.
+ if (SdkLevel.isAtLeastU() && (mNetworkTracingFlagEnabled || !Build.TYPE.equals("user"))) {
Log.i(TAG, "Initializing network tracing hooks");
NetworkStatsService.nativeInitNetworkTracing();
}
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 468d7bd..93ccb85 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -26,6 +26,7 @@
import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
import static android.net.nsd.NsdManager.RESOLVE_SERVICE_SUCCEEDED;
import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
+
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
import static com.android.server.connectivity.mdns.MdnsAdvertiser.AdvertiserMetrics;
@@ -1709,7 +1710,7 @@
mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"));
handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
MdnsFeatureFlags flags = new MdnsFeatureFlags.Builder().setIsMdnsOffloadFeatureEnabled(
- mDeps.isTetheringFeatureNotChickenedOut(
+ mDeps.isTetheringFeatureNotChickenedOut(mContext,
MdnsFeatureFlags.NSD_FORCE_DISABLE_MDNS_OFFLOAD)).build();
mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"), flags);
@@ -1763,8 +1764,8 @@
/**
* @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
*/
- public boolean isTetheringFeatureNotChickenedOut(String feature) {
- return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(feature);
+ public boolean isTetheringFeatureNotChickenedOut(Context context, String feature) {
+ return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, feature);
}
/**
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
index d9bc643..5812797 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
@@ -110,7 +110,7 @@
@NonNull MdnsReplySender replySender,
@Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb,
@NonNull SharedLog sharedLog) {
- super(looper, replySender, cb, sharedLog);
+ super(looper, replySender, cb, sharedLog, MdnsAdvertiser.DBG);
}
// TODO: Notify MdnsRecordRepository that the records were announced for that service ID,
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java b/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java
index 1251170..b83a6a0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsConstants.java
@@ -19,6 +19,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
@@ -42,6 +43,10 @@
public static final String SUBTYPE_PREFIX = "_";
private static final String MDNS_IPV4_HOST_ADDRESS = "224.0.0.251";
private static final String MDNS_IPV6_HOST_ADDRESS = "FF02::FB";
+ public static final InetSocketAddress IPV6_SOCKET_ADDR = new InetSocketAddress(
+ getMdnsIPv6Address(), MDNS_PORT);
+ public static final InetSocketAddress IPV4_SOCKET_ADDR = new InetSocketAddress(
+ getMdnsIPv4Address(), MDNS_PORT);
private static InetAddress mdnsAddress;
private MdnsConstants() {
}
@@ -75,4 +80,4 @@
public static Charset getUtf8Charset() {
return UTF_8;
}
-}
\ No newline at end of file
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
index 40dfd57..37e9743 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
@@ -161,7 +161,7 @@
@NonNull SharedLog sharedLog) {
return new MdnsReplySender(looper, socket, packetCreationBuffer,
sharedLog.forSubComponent(
- MdnsReplySender.class.getSimpleName() + "/" + interfaceTag));
+ MdnsReplySender.class.getSimpleName() + "/" + interfaceTag), DBG);
}
/** @see MdnsAnnouncer */
@@ -370,7 +370,7 @@
// happen when the incoming packet has answer records (not a question), so there will be no
// answer. One exception is simultaneous probe tiebreaking (rfc6762 8.2), in which case the
// conflicting service is still probing and won't reply either.
- final MdnsRecordRepository.ReplyInfo answers = mRecordRepository.getReply(packet, src);
+ final MdnsReplyInfo answers = mRecordRepository.getReply(packet, src);
if (answers == null) return;
mReplySender.queueReply(answers);
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java
index 7fa3f84..1fabd49 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacket.java
@@ -31,6 +31,7 @@
public class MdnsPacket {
private static final String TAG = MdnsPacket.class.getSimpleName();
+ public final int transactionId;
public final int flags;
@NonNull
public final List<MdnsRecord> questions;
@@ -46,6 +47,15 @@
@NonNull List<MdnsRecord> answers,
@NonNull List<MdnsRecord> authorityRecords,
@NonNull List<MdnsRecord> additionalRecords) {
+ this(0, flags, questions, answers, authorityRecords, additionalRecords);
+ }
+
+ MdnsPacket(int transactionId, int flags,
+ @NonNull List<MdnsRecord> questions,
+ @NonNull List<MdnsRecord> answers,
+ @NonNull List<MdnsRecord> authorityRecords,
+ @NonNull List<MdnsRecord> additionalRecords) {
+ this.transactionId = transactionId;
this.flags = flags;
this.questions = Collections.unmodifiableList(questions);
this.answers = Collections.unmodifiableList(answers);
@@ -70,15 +80,16 @@
*/
@NonNull
public static MdnsPacket parse(@NonNull MdnsPacketReader reader) throws ParseException {
+ final int transactionId;
final int flags;
try {
- reader.readUInt16(); // transaction ID (not used)
+ transactionId = reader.readUInt16();
flags = reader.readUInt16();
} catch (EOFException e) {
throw new ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE,
"Reached the end of the mDNS response unexpectedly.", e);
}
- return parseRecordsSection(reader, flags);
+ return parseRecordsSection(reader, flags, transactionId);
}
/**
@@ -86,8 +97,8 @@
*
* The records section starts with the questions count, just after the packet flags.
*/
- public static MdnsPacket parseRecordsSection(@NonNull MdnsPacketReader reader, int flags)
- throws ParseException {
+ public static MdnsPacket parseRecordsSection(@NonNull MdnsPacketReader reader, int flags,
+ int transactionId) throws ParseException {
try {
final int numQuestions = reader.readUInt16();
final int numAnswers = reader.readUInt16();
@@ -99,7 +110,7 @@
final ArrayList<MdnsRecord> authority = parseRecords(reader, numAuthority, false);
final ArrayList<MdnsRecord> additional = parseRecords(reader, numAdditional, false);
- return new MdnsPacket(flags, questions, answers, authority, additional);
+ return new MdnsPacket(transactionId, flags, questions, answers, authority, additional);
} catch (EOFException e) {
throw new ParseException(MdnsResponseErrorCode.ERROR_END_OF_FILE,
"Reached the end of the mDNS response unexpectedly.", e);
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
index fd0f5c9..e84cead 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
@@ -16,8 +16,8 @@
package com.android.server.connectivity.mdns;
-import static com.android.server.connectivity.mdns.MdnsRecordRepository.IPV4_ADDR;
-import static com.android.server.connectivity.mdns.MdnsRecordRepository.IPV6_ADDR;
+import static com.android.server.connectivity.mdns.MdnsConstants.IPV4_SOCKET_ADDR;
+import static com.android.server.connectivity.mdns.MdnsConstants.IPV6_SOCKET_ADDR;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,9 +38,8 @@
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public abstract class MdnsPacketRepeater<T extends MdnsPacketRepeater.Request> {
- private static final boolean DBG = MdnsAdvertiser.DBG;
private static final InetSocketAddress[] ALL_ADDRS = new InetSocketAddress[] {
- IPV4_ADDR, IPV6_ADDR
+ IPV4_SOCKET_ADDR, IPV6_SOCKET_ADDR
};
@NonNull
@@ -51,6 +50,7 @@
private final PacketRepeaterCallback<T> mCb;
@NonNull
private final SharedLog mSharedLog;
+ private final boolean mEnableDebugLog;
/**
* Status callback from {@link MdnsPacketRepeater}.
@@ -111,7 +111,7 @@
}
final MdnsPacket packet = request.getPacket(index);
- if (DBG) {
+ if (mEnableDebugLog) {
mSharedLog.v("Sending packets for iteration " + index + " out of "
+ request.getNumSends() + " for ID " + msg.what);
}
@@ -134,7 +134,7 @@
// likely not to be available since the device is in deep sleep anyway.
final long delay = request.getDelayMs(nextIndex);
sendMessageDelayed(obtainMessage(msg.what, nextIndex, 0, request), delay);
- if (DBG) mSharedLog.v("Scheduled next packet in " + delay + "ms");
+ if (mEnableDebugLog) mSharedLog.v("Scheduled next packet in " + delay + "ms");
}
// Call onSent after scheduling the next run, to allow the callback to cancel it
@@ -145,15 +145,17 @@
}
protected MdnsPacketRepeater(@NonNull Looper looper, @NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<T> cb, @NonNull SharedLog sharedLog) {
+ @Nullable PacketRepeaterCallback<T> cb, @NonNull SharedLog sharedLog,
+ boolean enableDebugLog) {
mHandler = new ProbeHandler(looper);
mReplySender = replySender;
mCb = cb;
mSharedLog = sharedLog;
+ mEnableDebugLog = enableDebugLog;
}
protected void startSending(int id, @NonNull T request, long initialDelayMs) {
- if (DBG) {
+ if (mEnableDebugLog) {
mSharedLog.v("Starting send with id " + id + ", request "
+ request.getClass().getSimpleName() + ", delay " + initialDelayMs);
}
@@ -172,7 +174,7 @@
// all in the handler queue; unless this method is called from a message, but the current
// message cannot be cancelled.
if (mHandler.hasMessages(id)) {
- if (DBG) {
+ if (mEnableDebugLog) {
mSharedLog.v("Stopping send on id " + id);
}
mHandler.removeMessages(id);
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
index f2b562a..e88947a 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
@@ -40,9 +40,8 @@
private static final long CONFLICT_RETRY_DELAY_MS = 5_000L;
public MdnsProber(@NonNull Looper looper, @NonNull MdnsReplySender replySender,
- @NonNull PacketRepeaterCallback<ProbingInfo> cb,
- @NonNull SharedLog sharedLog) {
- super(looper, replySender, cb, sharedLog);
+ @NonNull PacketRepeaterCallback<ProbingInfo> cb, @NonNull SharedLog sharedLog) {
+ super(looper, replySender, cb, sharedLog, MdnsAdvertiser.DBG);
}
/** Probing request to send with {@link MdnsProber}. */
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
index f532372..130ff48 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.mdns;
+import static com.android.server.connectivity.mdns.MdnsConstants.IPV4_SOCKET_ADDR;
+import static com.android.server.connectivity.mdns.MdnsConstants.IPV6_SOCKET_ADDR;
import static com.android.server.connectivity.mdns.MdnsConstants.NO_PACKET;
import android.annotation.NonNull;
@@ -79,11 +81,6 @@
private static final String[] DNS_SD_SERVICE_TYPE =
new String[] { "_services", "_dns-sd", "_udp", LOCAL_TLD };
- public static final InetSocketAddress IPV6_ADDR = new InetSocketAddress(
- MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT);
- public static final InetSocketAddress IPV4_ADDR = new InetSocketAddress(
- MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
-
@NonNull
private final Random mDelayGenerator = new Random();
// Map of service unique ID -> records for service
@@ -455,44 +452,13 @@
}
/**
- * Info about a reply to be sent.
- */
- public static class ReplyInfo {
- @NonNull
- public final List<MdnsRecord> answers;
- @NonNull
- public final List<MdnsRecord> additionalAnswers;
- public final long sendDelayMs;
- @NonNull
- public final InetSocketAddress destination;
-
- public ReplyInfo(
- @NonNull List<MdnsRecord> answers,
- @NonNull List<MdnsRecord> additionalAnswers,
- long sendDelayMs,
- @NonNull InetSocketAddress destination) {
- this.answers = answers;
- this.additionalAnswers = additionalAnswers;
- this.sendDelayMs = sendDelayMs;
- this.destination = destination;
- }
-
- @Override
- public String toString() {
- return "{ReplyInfo to " + destination + ", answers: " + answers.size()
- + ", additionalAnswers: " + additionalAnswers.size()
- + ", sendDelayMs " + sendDelayMs + "}";
- }
- }
-
- /**
* Get the reply to send to an incoming packet.
*
* @param packet The incoming packet.
* @param src The source address of the incoming packet.
*/
@Nullable
- public ReplyInfo getReply(MdnsPacket packet, InetSocketAddress src) {
+ public MdnsReplyInfo getReply(MdnsPacket packet, InetSocketAddress src) {
final long now = SystemClock.elapsedRealtime();
final boolean replyUnicast = (packet.flags & MdnsConstants.QCLASS_UNICAST) != 0;
final ArrayList<MdnsRecord> additionalAnswerRecords = new ArrayList<>();
@@ -543,9 +509,9 @@
if (replyUnicast) {
dest = src;
} else if (src.getAddress() instanceof Inet4Address) {
- dest = IPV4_ADDR;
+ dest = IPV4_SOCKET_ADDR;
} else {
- dest = IPV6_ADDR;
+ dest = IPV6_SOCKET_ADDR;
}
// Build the list of answer records from their RecordInfo
@@ -559,7 +525,7 @@
answerRecords.add(info.record);
}
- return new ReplyInfo(answerRecords, additionalAnswerRecords, delayMs, dest);
+ return new MdnsReplyInfo(answerRecords, additionalAnswerRecords, delayMs, dest);
}
/**
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsReplyInfo.java b/service-t/src/com/android/server/connectivity/mdns/MdnsReplyInfo.java
new file mode 100644
index 0000000..ce61b54
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsReplyInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.mdns;
+
+import android.annotation.NonNull;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+
+/**
+ * Info about a mDNS reply to be sent.
+ */
+public final class MdnsReplyInfo {
+ @NonNull
+ public final List<MdnsRecord> answers;
+ @NonNull
+ public final List<MdnsRecord> additionalAnswers;
+ public final long sendDelayMs;
+ @NonNull
+ public final InetSocketAddress destination;
+
+ public MdnsReplyInfo(
+ @NonNull List<MdnsRecord> answers,
+ @NonNull List<MdnsRecord> additionalAnswers,
+ long sendDelayMs,
+ @NonNull InetSocketAddress destination) {
+ this.answers = answers;
+ this.additionalAnswers = additionalAnswers;
+ this.sendDelayMs = sendDelayMs;
+ this.destination = destination;
+ }
+
+ @Override
+ public String toString() {
+ return "{MdnsReplyInfo to " + destination + ", answers: " + answers.size()
+ + ", additionalAnswers: " + additionalAnswers.size()
+ + ", sendDelayMs " + sendDelayMs + "}";
+ }
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
index 3d64b5a..abf5d99 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
@@ -26,7 +26,6 @@
import android.os.Message;
import com.android.net.module.util.SharedLog;
-import com.android.server.connectivity.mdns.MdnsRecordRepository.ReplyInfo;
import com.android.server.connectivity.mdns.util.MdnsUtils;
import java.io.IOException;
@@ -45,7 +44,6 @@
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public class MdnsReplySender {
- private static final boolean DBG = MdnsAdvertiser.DBG;
private static final int MSG_SEND = 1;
private static final int PACKET_NOT_SENT = 0;
private static final int PACKET_SENT = 1;
@@ -58,24 +56,27 @@
private final byte[] mPacketCreationBuffer;
@NonNull
private final SharedLog mSharedLog;
+ private final boolean mEnableDebugLog;
public MdnsReplySender(@NonNull Looper looper, @NonNull MdnsInterfaceSocket socket,
- @NonNull byte[] packetCreationBuffer, @NonNull SharedLog sharedLog) {
+ @NonNull byte[] packetCreationBuffer, @NonNull SharedLog sharedLog,
+ boolean enableDebugLog) {
mHandler = new SendHandler(looper);
mSocket = socket;
mPacketCreationBuffer = packetCreationBuffer;
mSharedLog = sharedLog;
+ mEnableDebugLog = enableDebugLog;
}
/**
* Queue a reply to be sent when its send delay expires.
*/
- public void queueReply(@NonNull ReplyInfo reply) {
+ public void queueReply(@NonNull MdnsReplyInfo reply) {
ensureRunningOnHandlerThread(mHandler);
// TODO: implement response aggregation (RFC 6762 6.4)
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SEND, reply), reply.sendDelayMs);
- if (DBG) {
+ if (mEnableDebugLog) {
mSharedLog.v("Scheduling " + reply);
}
}
@@ -118,8 +119,8 @@
@Override
public void handleMessage(@NonNull Message msg) {
- final ReplyInfo replyInfo = (ReplyInfo) msg.obj;
- if (DBG) mSharedLog.v("Sending " + replyInfo);
+ final MdnsReplyInfo replyInfo = (MdnsReplyInfo) msg.obj;
+ if (mEnableDebugLog) mSharedLog.v("Sending " + replyInfo);
final int flags = 0x8400; // Response, authoritative (rfc6762 18.4)
final MdnsPacket packet = new MdnsPacket(flags,
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index a3cc0eb..050913f 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -90,14 +90,14 @@
final MdnsPacket mdnsPacket;
try {
- reader.readUInt16(); // transaction ID (not used)
+ final int transactionId = reader.readUInt16();
int flags = reader.readUInt16();
if ((flags & MdnsConstants.FLAGS_RESPONSE_MASK) != MdnsConstants.FLAGS_RESPONSE) {
throw new MdnsPacket.ParseException(
MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE, "Not a response", null);
}
- mdnsPacket = MdnsPacket.parseRecordsSection(reader, flags);
+ mdnsPacket = MdnsPacket.parseRecordsSection(reader, flags, transactionId);
if (mdnsPacket.answers.size() < 1) {
throw new MdnsPacket.ParseException(
MdnsResponseErrorCode.ERROR_NO_ANSWERS, "Response has no answers",
diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
index 0dcc560..d0f3d9a 100644
--- a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
+++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
@@ -189,7 +189,7 @@
// TODO: support packets over size (send in multiple packets with TC bit set)
final MdnsPacketWriter writer = new MdnsPacketWriter(packetCreationBuffer);
- writer.writeUInt16(0); // Transaction ID (advertisement: 0)
+ writer.writeUInt16(packet.transactionId); // Transaction ID (advertisement: 0)
writer.writeUInt16(packet.flags); // Response, authoritative (rfc6762 18.4)
writer.writeUInt16(packet.questions.size()); // questions count
writer.writeUInt16(packet.answers.size()); // answers count
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 4b24aaf..6a34a24 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -254,7 +254,7 @@
if (sInitialized) return;
if (sEnableJavaBpfMap == null) {
sEnableJavaBpfMap = SdkLevel.isAtLeastU() ||
- DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context,
BPF_NET_MAPS_FORCE_DISABLE_JAVA_BPF_MAP);
}
Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index bbb0fed..ea4d82a 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -97,12 +97,14 @@
import static android.system.OsConstants.ETH_P_ALL;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
+
import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static com.android.net.module.util.PermissionUtils.checkAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE;
+
import static java.util.Map.Entry;
import android.Manifest;
@@ -1315,6 +1317,10 @@
return SdkLevel.isAtLeastU();
}
+ public boolean isAtLeastV() {
+ return SdkLevel.isAtLeastV();
+ }
+
/**
* Get system properties to use in ConnectivityService.
*/
@@ -1428,7 +1434,7 @@
public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
@NonNull final Context context, @NonNull final TelephonyManager tm) {
if (isAtLeastT()) {
- return new CarrierPrivilegeAuthenticator(context, tm);
+ return new CarrierPrivilegeAuthenticator(context, this, tm);
} else {
return null;
}
@@ -4408,7 +4414,7 @@
updateCapabilitiesForNetwork(nai);
} else if (portalChanged) {
if (portal && ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
- == getCaptivePortalMode()) {
+ == getCaptivePortalMode(nai)) {
if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
nai.onPreventAutomaticReconnect();
teardownUnneededNetwork(nai);
@@ -4444,7 +4450,13 @@
}
}
- private int getCaptivePortalMode() {
+ private int getCaptivePortalMode(@NonNull NetworkAgentInfo nai) {
+ if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) &&
+ mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
+ // Do not avoid captive portal when network is wear proxy.
+ return ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT;
+ }
+
return Settings.Global.getInt(mContext.getContentResolver(),
ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE,
ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
@@ -11423,7 +11435,7 @@
public void onInterfaceLinkStateChanged(@NonNull String iface, boolean up) {
mHandler.post(() -> {
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.clatd.interfaceLinkStateChanged(iface, up);
+ nai.clatd.handleInterfaceLinkStateChanged(iface, up);
}
});
}
@@ -11432,7 +11444,7 @@
public void onInterfaceRemoved(@NonNull String iface) {
mHandler.post(() -> {
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.clatd.interfaceRemoved(iface);
+ nai.clatd.handleInterfaceRemoved(iface);
}
});
}
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index 3befcfa..11345d3 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -974,7 +974,7 @@
* @return whether the feature is enabled
*/
public boolean isTetheringFeatureNotChickenedOut(@NonNull final String name) {
- return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(name);
+ return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(mContext, name);
}
/**
diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
index 4325763..ab7b1a7 100644
--- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
+++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
@@ -16,10 +16,12 @@
package com.android.server.connectivity;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static com.android.server.connectivity.ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -35,6 +37,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -43,6 +46,7 @@
import com.android.networkstack.apishim.common.TelephonyManagerShim;
import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim;
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
+import com.android.server.ConnectivityService;
import java.util.ArrayList;
import java.util.List;
@@ -54,7 +58,7 @@
* carrier privileged app that provides the carrier config
* @hide
*/
-public class CarrierPrivilegeAuthenticator extends BroadcastReceiver {
+public class CarrierPrivilegeAuthenticator {
private static final String TAG = CarrierPrivilegeAuthenticator.class.getSimpleName();
private static final boolean DBG = true;
@@ -63,100 +67,100 @@
private final TelephonyManagerShim mTelephonyManagerShim;
private final TelephonyManager mTelephonyManager;
@GuardedBy("mLock")
- private int[] mCarrierServiceUid;
+ private final SparseIntArray mCarrierServiceUid = new SparseIntArray(2 /* initialCapacity */);
@GuardedBy("mLock")
private int mModemCount = 0;
private final Object mLock = new Object();
- private final HandlerThread mThread;
private final Handler mHandler;
@NonNull
- private final List<CarrierPrivilegesListenerShim> mCarrierPrivilegesChangedListeners =
- new ArrayList<>();
+ private final List<PrivilegeListener> mCarrierPrivilegesChangedListeners = new ArrayList<>();
+ private final boolean mUseCallbacksForServiceChanged;
public CarrierPrivilegeAuthenticator(@NonNull final Context c,
+ @NonNull final ConnectivityService.Dependencies deps,
@NonNull final TelephonyManager t,
- @NonNull final TelephonyManagerShimImpl telephonyManagerShim) {
+ @NonNull final TelephonyManagerShim telephonyManagerShim) {
mContext = c;
mTelephonyManager = t;
mTelephonyManagerShim = telephonyManagerShim;
- mThread = new HandlerThread(TAG);
- mThread.start();
- mHandler = new Handler(mThread.getLooper()) {};
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mHandler = new Handler(thread.getLooper());
+ mUseCallbacksForServiceChanged = deps.isFeatureEnabled(
+ c, CARRIER_SERVICE_CHANGED_USE_CALLBACK);
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
synchronized (mLock) {
- mModemCount = mTelephonyManager.getActiveModemCount();
- registerForCarrierChanges();
- updateCarrierServiceUid();
+ // Never unregistered because the system server never stops
+ c.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ switch (intent.getAction()) {
+ case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED:
+ simConfigChanged();
+ break;
+ default:
+ Log.d(TAG, "Unknown intent received, action: " + intent.getAction());
+ }
+ }
+ }, filter, null, mHandler);
+ simConfigChanged();
}
}
public CarrierPrivilegeAuthenticator(@NonNull final Context c,
+ @NonNull final ConnectivityService.Dependencies deps,
@NonNull final TelephonyManager t) {
- mContext = c;
- mTelephonyManager = t;
- mTelephonyManagerShim = TelephonyManagerShimImpl.newInstance(mTelephonyManager);
- mThread = new HandlerThread(TAG);
- mThread.start();
- mHandler = new Handler(mThread.getLooper()) {};
+ this(c, deps, t, TelephonyManagerShimImpl.newInstance(t));
+ }
+
+ private void simConfigChanged() {
synchronized (mLock) {
+ unregisterCarrierPrivilegesListeners();
mModemCount = mTelephonyManager.getActiveModemCount();
- registerForCarrierChanges();
+ registerCarrierPrivilegesListeners(mModemCount);
+ if (!mUseCallbacksForServiceChanged) updateCarrierServiceUid();
+ }
+ }
+
+ private class PrivilegeListener implements CarrierPrivilegesListenerShim {
+ public final int mLogicalSlot;
+ PrivilegeListener(final int logicalSlot) {
+ mLogicalSlot = logicalSlot;
+ }
+
+ @Override public void onCarrierPrivilegesChanged(
+ @NonNull List<String> privilegedPackageNames,
+ @NonNull int[] privilegedUids) {
+ if (mUseCallbacksForServiceChanged) return;
+ // Re-trigger the synchronous check (which is also very cheap due
+ // to caching in CarrierPrivilegesTracker). This allows consistency
+ // with the onSubscriptionsChangedListener and broadcasts.
updateCarrierServiceUid();
}
- }
- /**
- * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED
- *
- * <p>The broadcast receiver is registered with mHandler
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED:
- handleActionMultiSimConfigChanged(context, intent);
- break;
- default:
- Log.d(TAG, "Unknown intent received with action: " + intent.getAction());
+ @Override
+ public void onCarrierServiceChanged(@Nullable final String carrierServicePackageName,
+ final int carrierServiceUid) {
+ if (!mUseCallbacksForServiceChanged) {
+ // Re-trigger the synchronous check (which is also very cheap due
+ // to caching in CarrierPrivilegesTracker). This allows consistency
+ // with the onSubscriptionsChangedListener and broadcasts.
+ updateCarrierServiceUid();
+ return;
+ }
+ synchronized (mLock) {
+ mCarrierServiceUid.put(mLogicalSlot, carrierServiceUid);
+ }
}
}
- private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
- unregisterCarrierPrivilegesListeners();
- synchronized (mLock) {
- mModemCount = mTelephonyManager.getActiveModemCount();
- }
- registerCarrierPrivilegesListeners();
- updateCarrierServiceUid();
- }
-
- private void registerForCarrierChanges() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
- mContext.registerReceiver(this, filter, null, mHandler);
- registerCarrierPrivilegesListeners();
- }
-
- private void registerCarrierPrivilegesListeners() {
+ private void registerCarrierPrivilegesListeners(final int modemCount) {
final HandlerExecutor executor = new HandlerExecutor(mHandler);
- int modemCount;
- synchronized (mLock) {
- modemCount = mModemCount;
- }
try {
for (int i = 0; i < modemCount; i++) {
- CarrierPrivilegesListenerShim carrierPrivilegesListener =
- new CarrierPrivilegesListenerShim() {
- @Override
- public void onCarrierPrivilegesChanged(
- @NonNull List<String> privilegedPackageNames,
- @NonNull int[] privilegedUids) {
- // Re-trigger the synchronous check (which is also very cheap due
- // to caching in CarrierPrivilegesTracker). This allows consistency
- // with the onSubscriptionsChangedListener and broadcasts.
- updateCarrierServiceUid();
- }
- };
- addCarrierPrivilegesListener(i, executor, carrierPrivilegesListener);
+ PrivilegeListener carrierPrivilegesListener = new PrivilegeListener(i);
+ addCarrierPrivilegesListener(executor, carrierPrivilegesListener);
mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
}
} catch (IllegalArgumentException e) {
@@ -164,24 +168,13 @@
}
}
- private void addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor,
- CarrierPrivilegesListenerShim listener) {
- try {
- mTelephonyManagerShim.addCarrierPrivilegesListener(
- logicalSlotIndex, executor, listener);
- } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
- // Should not happen since CarrierPrivilegeAuthenticator is only used on T+
- Log.e(TAG, "addCarrierPrivilegesListener API is not available");
+ @GuardedBy("mLock")
+ private void unregisterCarrierPrivilegesListeners() {
+ for (PrivilegeListener carrierPrivilegesListener : mCarrierPrivilegesChangedListeners) {
+ removeCarrierPrivilegesListener(carrierPrivilegesListener);
+ mCarrierServiceUid.delete(carrierPrivilegesListener.mLogicalSlot);
}
- }
-
- private void removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener) {
- try {
- mTelephonyManagerShim.removeCarrierPrivilegesListener(listener);
- } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
- // Should not happen since CarrierPrivilegeAuthenticator is only used on T+
- Log.e(TAG, "removeCarrierPrivilegesListener API is not available");
- }
+ mCarrierPrivilegesChangedListeners.clear();
}
private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
@@ -195,14 +188,6 @@
return null;
}
- private void unregisterCarrierPrivilegesListeners() {
- for (CarrierPrivilegesListenerShim carrierPrivilegesListener :
- mCarrierPrivilegesChangedListeners) {
- removeCarrierPrivilegesListener(carrierPrivilegesListener);
- }
- mCarrierPrivilegesChangedListeners.clear();
- }
-
/**
* Check if a UID is the carrier service app of the subscription ID in the provided capabilities
*
@@ -233,9 +218,9 @@
@VisibleForTesting
void updateCarrierServiceUid() {
synchronized (mLock) {
- mCarrierServiceUid = new int[mModemCount];
+ mCarrierServiceUid.clear();
for (int i = 0; i < mModemCount; i++) {
- mCarrierServiceUid[i] = getCarrierServicePackageUidForSlot(i);
+ mCarrierServiceUid.put(i, getCarrierServicePackageUidForSlot(i));
}
}
}
@@ -244,11 +229,8 @@
int getCarrierServiceUidForSubId(int subId) {
final int slotId = getSlotIndex(subId);
synchronized (mLock) {
- if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mModemCount) {
- return mCarrierServiceUid[slotId];
- }
+ return mCarrierServiceUid.get(slotId, Process.INVALID_UID);
}
- return Process.INVALID_UID;
}
@VisibleForTesting
@@ -288,4 +270,26 @@
int getCarrierServicePackageUidForSlot(int slotId) {
return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId));
}
+
+ // Helper methods to avoid having to deal with UnsupportedApiLevelException.
+
+ private void addCarrierPrivilegesListener(@NonNull final Executor executor,
+ @NonNull final PrivilegeListener listener) {
+ try {
+ mTelephonyManagerShim.addCarrierPrivilegesListener(listener.mLogicalSlot, executor,
+ listener);
+ } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
+ // Should not happen since CarrierPrivilegeAuthenticator is only used on T+
+ Log.e(TAG, "addCarrierPrivilegesListener API is not available");
+ }
+ }
+
+ private void removeCarrierPrivilegesListener(PrivilegeListener listener) {
+ try {
+ mTelephonyManagerShim.removeCarrierPrivilegesListener(listener);
+ } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
+ // Should not happen since CarrierPrivilegeAuthenticator is only used on T+
+ Log.e(TAG, "removeCarrierPrivilegesListener API is not available");
+ }
+ }
}
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index eb3e7ce..17de146 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -78,7 +78,7 @@
@VisibleForTesting
static final int MTU_DELTA = 28;
@VisibleForTesting
- static final int CLAT_MAX_MTU = 65536;
+ static final int CLAT_MAX_MTU = 1500 + MTU_DELTA;
// This must match the interface prefix in clatd.c.
private static final String CLAT_PREFIX = "v4-";
@@ -673,7 +673,7 @@
throw new IOException("Detect MTU on " + tunIface + " failed: " + e);
}
final int mtu = adjustMtu(detectedMtu);
- Log.i(TAG, "ipv4 mtu is " + mtu);
+ Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu);
// Config tun interface mtu, address and bring up.
try {
diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java
index 9039a14..5aac8f1 100644
--- a/service/src/com/android/server/connectivity/ConnectivityFlags.java
+++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java
@@ -33,6 +33,10 @@
public static final String NO_REMATCH_ALL_REQUESTS_ON_REGISTER =
"no_rematch_all_requests_on_register";
+ @VisibleForTesting
+ public static final String CARRIER_SERVICE_CHANGED_USE_CALLBACK =
+ "carrier_service_changed_use_callback_version";
+
private boolean mNoRematchAllRequestsOnRegister;
/**
diff --git a/service/src/com/android/server/connectivity/ConnectivityNativeService.java b/service/src/com/android/server/connectivity/ConnectivityNativeService.java
index c1ba40e..e16117b 100644
--- a/service/src/com/android/server/connectivity/ConnectivityNativeService.java
+++ b/service/src/com/android/server/connectivity/ConnectivityNativeService.java
@@ -46,10 +46,6 @@
private static final String TAG = ConnectivityNativeService.class.getSimpleName();
private static final String CGROUP_PATH = "/sys/fs/cgroup";
- private static final String V4_PROG_PATH =
- "/sys/fs/bpf/net_shared/prog_block_bind4_block_port";
- private static final String V6_PROG_PATH =
- "/sys/fs/bpf/net_shared/prog_block_bind6_block_port";
private static final String BLOCKED_PORTS_MAP_PATH =
"/sys/fs/bpf/net_shared/map_block_blocked_ports_map";
@@ -95,7 +91,6 @@
protected ConnectivityNativeService(final Context context, @NonNull Dependencies deps) {
mContext = context;
mBpfBlockedPortsMap = deps.getBlockPortsMap();
- attachProgram();
}
@Override
@@ -155,23 +150,4 @@
public String getInterfaceHash() {
return this.HASH;
}
-
- /**
- * Attach BPF program
- */
- private void attachProgram() {
- try {
- BpfUtils.attachProgram(BPF_CGROUP_INET4_BIND, V4_PROG_PATH, CGROUP_PATH, 0);
- } catch (IOException e) {
- throw new UnsupportedOperationException("Unable to attach to BPF_CGROUP_INET4_BIND: "
- + e);
- }
- try {
- BpfUtils.attachProgram(BPF_CGROUP_INET6_BIND, V6_PROG_PATH, CGROUP_PATH, 0);
- } catch (IOException e) {
- throw new UnsupportedOperationException("Unable to attach to BPF_CGROUP_INET6_BIND: "
- + e);
- }
- Log.d(TAG, "Attached BPF_CGROUP_INET4_BIND and BPF_CGROUP_INET6_BIND programs");
- }
}
diff --git a/service/src/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java
index feba821..a51f09f 100644
--- a/service/src/com/android/server/connectivity/KeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveTracker.java
@@ -993,7 +993,7 @@
*/
public boolean isAddressTranslationEnabled(@NonNull Context context) {
return DeviceConfigUtils.isFeatureSupported(context, FEATURE_CLAT_ADDRESS_TRANSLATE)
- && DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ && DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context,
CONFIG_DISABLE_CLAT_ADDRESS_TRANSLATE);
}
}
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index f9e07fd..065922d 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -483,8 +483,9 @@
/**
* Adds stacked link on base link and transitions to RUNNING state.
+ * Must be called on the handler thread.
*/
- private void handleInterfaceLinkStateChanged(String iface, boolean up) {
+ public void handleInterfaceLinkStateChanged(String iface, boolean up) {
// TODO: if we call start(), then stop(), then start() again, and the
// interfaceLinkStateChanged notification for the first start is delayed past the first
// stop, then the code becomes out of sync with system state and will behave incorrectly.
@@ -499,6 +500,7 @@
// Once this code is converted to StateMachine, it will be possible to use deferMessage to
// ensure it stays in STARTING state until the interfaceLinkStateChanged notification fires,
// and possibly use a timeout (or provide some guarantees at the lower layer) to address #1.
+ ensureRunningOnHandlerThread();
if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
return;
}
@@ -519,8 +521,10 @@
/**
* Removes stacked link on base link and transitions to IDLE state.
+ * Must be called on the handler thread.
*/
- private void handleInterfaceRemoved(String iface) {
+ public void handleInterfaceRemoved(String iface) {
+ ensureRunningOnHandlerThread();
if (!Objects.equals(mIface, iface)) {
return;
}
@@ -536,14 +540,6 @@
stop();
}
- public void interfaceLinkStateChanged(String iface, boolean up) {
- mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
- }
-
- public void interfaceRemoved(String iface) {
- mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
- }
-
/**
* Translate the input v4 address to v6 clat address.
*/
diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
index e1e2585..3db37e5 100644
--- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
@@ -340,8 +340,9 @@
@TargetApi(Build.VERSION_CODES.S)
private int getMtuForTarget(InetAddress target) {
final int family = target instanceof Inet4Address ? AF_INET : AF_INET6;
+ FileDescriptor socket = null;
try {
- final FileDescriptor socket = Os.socket(family, SOCK_DGRAM, 0);
+ socket = Os.socket(family, SOCK_DGRAM, 0);
mNetwork.bindSocket(socket);
Os.connect(socket, target, 0);
if (family == AF_INET) {
@@ -352,6 +353,8 @@
} catch (ErrnoException | IOException e) {
Log.e(TAG, "Can't get MTU for destination " + target, e);
return -1;
+ } finally {
+ IoUtils.closeQuietly(socket);
}
}
diff --git a/service/src/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
index d94c8dc..c473444 100644
--- a/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -17,6 +17,8 @@
package com.android.server.connectivity;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -221,6 +223,19 @@
}
/**
+ * Returns whether the scorable has any of the PRIORITIZE_* capabilities.
+ *
+ * These capabilities code for customer slices, and a network that has one is a customer slice.
+ */
+ private boolean hasPrioritizedCapability(@NonNull final Scoreable nai) {
+ final NetworkCapabilities caps = nai.getCapsNoCopy();
+ final long anyPrioritizeCapability =
+ (1L << NET_CAPABILITY_PRIORITIZE_LATENCY)
+ | (1L << NET_CAPABILITY_PRIORITIZE_BANDWIDTH);
+ return 0 != (caps.getCapabilitiesInternal() & anyPrioritizeCapability);
+ }
+
+ /**
* Get the best network among a list of candidates according to policy.
* @param candidates the candidates
* @param currentSatisfier the current satisfier, or null if none
@@ -324,6 +339,12 @@
// change from the previous result. If there were, it's guaranteed candidates.size() > 0
// because accepted.size() > 0 above.
+ // If any network is not a slice with prioritized bandwidth or latency, don't choose one
+ // that is.
+ partitionInto(candidates, nai -> !hasPrioritizedCapability(nai), accepted, rejected);
+ if (accepted.size() == 1) return accepted.get(0);
+ if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
+
// If some of the networks have a better transport than others, keep only the ones with
// the best transports.
for (final int transport : PREFERRED_TRANSPORTS_ORDER) {
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 59a63f2..621759e 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -74,7 +74,10 @@
"framework-configinfrastructure",
"framework-connectivity.stubs.module_lib",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_defaults {
@@ -141,7 +144,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -169,7 +175,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -194,7 +203,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -223,7 +235,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -258,7 +273,10 @@
"//packages/modules/Wifi/framework/tests:__subpackages__",
"//packages/apps/Settings",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
errorprone: {
enabled: true,
// Error-prone checking only warns of problems when building. To make the build fail with
@@ -301,7 +319,10 @@
"//packages/modules/Bluetooth/android/app",
"//packages/modules/Wifi/service:__subpackages__",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -323,7 +344,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -346,7 +370,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
// Limited set of utilities for use by service-connectivity-mdns-standalone-build-test, to make sure
diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java
index 94af11b..f1546c0 100644
--- a/staticlibs/device/com/android/net/module/util/BpfUtils.java
+++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java
@@ -66,4 +66,6 @@
throws IOException;
private static native boolean native_detachSingleProgramFromCgroup(int type,
String programPath, String cgroupPath) throws IOException;
+ private static native int native_getProgramIdFromCgroup(int type, String cgroupPath)
+ throws IOException;
}
diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
index e646f37..42f26f4 100644
--- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
+++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Supplier;
/**
* Utilities for modules to query {@link DeviceConfig} and flags.
@@ -63,6 +64,9 @@
@VisibleForTesting
public static final long DEFAULT_PACKAGE_VERSION = 1000;
+ private static final String CORE_NETWORKING_TRUNK_STABLE_NAMESPACE = "android_core_networking";
+ private static final String CORE_NETWORKING_TRUNK_STABLE_FLAG_PACKAGE = "com.android.net.flags";
+
@VisibleForTesting
public static void resetPackageVersionCacheForTest() {
sPackageVersion = -1;
@@ -70,6 +74,9 @@
sNetworkStackModuleVersion = -1;
}
+ private static final int FORCE_ENABLE_FEATURE_FLAG_VALUE = 1;
+ private static final int FORCE_DISABLE_FEATURE_FLAG_VALUE = -1;
+
private static volatile long sPackageVersion = -1;
private static long getPackageVersion(@NonNull final Context context) {
// sPackageVersion may be set by another thread just after this check, but querying the
@@ -161,34 +168,19 @@
*
* This is useful to ensure that if a module install is rolled back, flags are not left fully
* rolled out on a version where they have not been well tested.
+ *
+ * If the feature is disabled by default and enabled by flag push, this method should be used.
+ * If the feature is enabled by default and disabled by flag push (kill switch),
+ * {@link #isNetworkStackFeatureNotChickenedOut(Context, String)} should be used.
+ *
* @param context The global context information about an app environment.
* @param name The name of the property to look up.
* @return true if this feature is enabled, or false if disabled.
*/
public static boolean isNetworkStackFeatureEnabled(@NonNull Context context,
@NonNull String name) {
- return isNetworkStackFeatureEnabled(context, name, false /* defaultEnabled */);
- }
-
- /**
- * Check whether or not one specific experimental feature for a particular namespace from
- * {@link DeviceConfig} is enabled by comparing module package version
- * with current version of property. If this property version is valid, the corresponding
- * experimental feature would be enabled, otherwise disabled.
- *
- * This is useful to ensure that if a module install is rolled back, flags are not left fully
- * rolled out on a version where they have not been well tested.
- * @param context The global context information about an app environment.
- * @param name The name of the property to look up.
- * @param defaultEnabled The value to return if the property does not exist or its value is
- * null.
- * @return true if this feature is enabled, or false if disabled.
- */
- public static boolean isNetworkStackFeatureEnabled(@NonNull Context context,
- @NonNull String name, boolean defaultEnabled) {
- final long packageVersion = getPackageVersion(context);
- return isFeatureEnabled(context, packageVersion, NAMESPACE_CONNECTIVITY, name,
- defaultEnabled);
+ return isFeatureEnabled(NAMESPACE_CONNECTIVITY, name, false /* defaultEnabled */,
+ () -> getPackageVersion(context));
}
/**
@@ -202,7 +194,7 @@
*
* If the feature is disabled by default and enabled by flag push, this method should be used.
* If the feature is enabled by default and disabled by flag push (kill switch),
- * {@link #isTetheringFeatureNotChickenedOut(String)} should be used.
+ * {@link #isTetheringFeatureNotChickenedOut(Context, String)} should be used.
*
* @param context The global context information about an app environment.
* @param name The name of the property to look up.
@@ -210,17 +202,24 @@
*/
public static boolean isTetheringFeatureEnabled(@NonNull Context context,
@NonNull String name) {
- final long packageVersion = getTetheringModuleVersion(context);
- return isFeatureEnabled(context, packageVersion, NAMESPACE_TETHERING, name,
- false /* defaultEnabled */);
+ return isFeatureEnabled(NAMESPACE_TETHERING, name, false /* defaultEnabled */,
+ () -> getTetheringModuleVersion(context));
}
- private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion,
- @NonNull String namespace, String name, boolean defaultEnabled) {
- final int propertyVersion = getDeviceConfigPropertyInt(namespace, name,
- 0 /* default value */);
- return (propertyVersion == 0 && defaultEnabled)
- || (propertyVersion != 0 && packageVersion >= (long) propertyVersion);
+ private static boolean isFeatureEnabled(@NonNull String namespace,
+ String name, boolean defaultEnabled, Supplier<Long> packageVersionSupplier) {
+ final int flagValue = getDeviceConfigPropertyInt(namespace, name, 0 /* default value */);
+ switch (flagValue) {
+ case 0:
+ return defaultEnabled;
+ case FORCE_DISABLE_FEATURE_FLAG_VALUE:
+ return false;
+ case FORCE_ENABLE_FEATURE_FLAG_VALUE:
+ return true;
+ default:
+ final long packageVersion = packageVersionSupplier.get();
+ return packageVersion >= (long) flagValue;
+ }
}
// Guess the tethering module name based on the package prefix of the connectivity resources
@@ -331,42 +330,38 @@
}
/**
- * Check whether one specific experimental feature in specific namespace from
- * {@link DeviceConfig} is not disabled. Feature can be disabled by setting a non-zero
- * value in the property. If the feature is enabled by default and disabled by flag push
- * (kill switch), this method should be used. If the feature is disabled by default and
- * enabled by flag push, {@link #isFeatureEnabled} should be used.
- *
- * @param namespace The namespace containing the property to look up.
- * @param name The name of the property to look up.
- * @return true if this feature is enabled, or false if disabled.
- */
- private static boolean isFeatureNotChickenedOut(String namespace, String name) {
- final int propertyVersion = getDeviceConfigPropertyInt(namespace, name,
- 0 /* default value */);
- return propertyVersion == 0;
- }
-
- /**
* Check whether one specific experimental feature in Tethering module from {@link DeviceConfig}
* is not disabled.
+ * If the feature is enabled by default and disabled by flag push (kill switch), this method
+ * should be used.
+ * If the feature is disabled by default and enabled by flag push,
+ * {@link #isTetheringFeatureEnabled(Context, String)} should be used.
*
+ * @param context The global context information about an app environment.
* @param name The name of the property in tethering module to look up.
* @return true if this feature is enabled, or false if disabled.
*/
- public static boolean isTetheringFeatureNotChickenedOut(String name) {
- return isFeatureNotChickenedOut(NAMESPACE_TETHERING, name);
+ public static boolean isTetheringFeatureNotChickenedOut(@NonNull Context context, String name) {
+ return isFeatureEnabled(NAMESPACE_TETHERING, name, true /* defaultEnabled */,
+ () -> getTetheringModuleVersion(context));
}
/**
* Check whether one specific experimental feature in NetworkStack module from
* {@link DeviceConfig} is not disabled.
+ * If the feature is enabled by default and disabled by flag push (kill switch), this method
+ * should be used.
+ * If the feature is disabled by default and enabled by flag push,
+ * {@link #isNetworkStackFeatureEnabled(Context, String)} should be used.
*
+ * @param context The global context information about an app environment.
* @param name The name of the property in NetworkStack module to look up.
* @return true if this feature is enabled, or false if disabled.
*/
- public static boolean isNetworkStackFeatureNotChickenedOut(String name) {
- return isFeatureNotChickenedOut(NAMESPACE_CONNECTIVITY, name);
+ public static boolean isNetworkStackFeatureNotChickenedOut(
+ @NonNull Context context, String name) {
+ return isFeatureEnabled(NAMESPACE_CONNECTIVITY, name, true /* defaultEnabled */,
+ () -> getPackageVersion(context));
}
/**
@@ -414,4 +409,31 @@
return pkgs.get(0).activityInfo.applicationInfo.packageName;
}
+
+ /**
+ * Check whether one specific trunk stable flag in android_core_networking namespace is enabled.
+ * This method reads trunk stable feature flag value from DeviceConfig directly since
+ * java_aconfig_library soong module is not available in the mainline branch.
+ * After the mainline branch support the aconfig soong module, this function must be removed and
+ * java_aconfig_library must be used instead to check if the feature is enabled.
+ *
+ * @param flagName The name of the trunk stable flag
+ * @return true if this feature is enabled, or false if disabled.
+ */
+ public static boolean isTrunkStableFeatureEnabled(final String flagName) {
+ return isTrunkStableFeatureEnabled(
+ CORE_NETWORKING_TRUNK_STABLE_NAMESPACE,
+ CORE_NETWORKING_TRUNK_STABLE_FLAG_PACKAGE,
+ flagName
+ );
+ }
+
+ private static boolean isTrunkStableFeatureEnabled(final String namespace,
+ final String packageName, final String flagName) {
+ return DeviceConfig.getBoolean(
+ namespace,
+ packageName + "." + flagName,
+ false /* defaultValue */
+ );
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/SocketUtils.java b/staticlibs/device/com/android/net/module/util/SocketUtils.java
index 9878ea5..5e6a6c6 100644
--- a/staticlibs/device/com/android/net/module/util/SocketUtils.java
+++ b/staticlibs/device/com/android/net/module/util/SocketUtils.java
@@ -19,6 +19,8 @@
import static android.net.util.SocketUtils.closeSocket;
import android.annotation.NonNull;
+import android.annotation.RequiresApi;
+import android.os.Build;
import android.system.NetlinkSocketAddress;
import java.io.FileDescriptor;
@@ -39,7 +41,7 @@
/**
* Make a socket address to communicate with netlink.
*/
- @NonNull
+ @NonNull @RequiresApi(Build.VERSION_CODES.S)
public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
return new NetlinkSocketAddress(portId, groupsMask);
}
diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
index 59d655c..176b7bc 100644
--- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
@@ -18,6 +18,8 @@
import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAPREFIX;
+import android.util.Log;
+
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@@ -52,6 +54,7 @@
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class IaPrefixOption extends Struct {
+ private static final String TAG = IaPrefixOption.class.getSimpleName();
public static final int LENGTH = 25; // option length excluding IAprefix-options
@Field(order = 0, type = Type.S16)
@@ -78,6 +81,33 @@
}
/**
+ * Check whether or not IA Prefix option in IA_PD option is valid per RFC8415#section-21.22.
+ */
+ public boolean isValid(int t2) {
+ if (preferred < 0 || valid < 0) {
+ Log.w(TAG, "IA_PD option with invalid lifetime, preferred lifetime " + preferred
+ + ", valid lifetime " + valid);
+ return false;
+ }
+ if (preferred > valid) {
+ Log.w(TAG, "IA_PD option with preferred lifetime " + preferred
+ + " greater than valid lifetime " + valid);
+ return false;
+ }
+ if (prefixLen > 64) {
+ Log.w(TAG, "IA_PD option with prefix length " + prefixLen
+ + " longer than 64");
+ return false;
+ }
+ // Either preferred lifetime or t2 might be 0 which is valid, then ignore it.
+ if (preferred != 0 && t2 != 0 && preferred < t2) {
+ Log.w(TAG, "preferred lifetime " + preferred + " is smaller than T2 " + t2);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Build an IA_PD prefix option with given specific parameters.
*/
public static ByteBuffer build(final short length, final long preferred, final long valid,
diff --git a/staticlibs/lint-baseline.xml b/staticlibs/lint-baseline.xml
deleted file mode 100644
index d413b2a..0000000
--- a/staticlibs/lint-baseline.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.LinkProperties#getAddresses`"
- errorLine1=" final Collection<InetAddress> leftAddresses = left.getAddresses();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/LinkPropertiesUtils.java"
- line="158"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.LinkProperties#getAddresses`"
- errorLine1=" final Collection<InetAddress> rightAddresses = right.getAddresses();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/LinkPropertiesUtils.java"
- line="159"
- column="62"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.NetworkStats#addEntry`"
- errorLine1=" stats = stats.addEntry(entry);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="113"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `new android.net.NetworkStats.Entry`"
- errorLine1=" return new android.net.NetworkStats.Entry("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="120"
- column="16"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `new android.net.NetworkStats`"
- errorLine1=" android.net.NetworkStats stats = new android.net.NetworkStats(0L, 0);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="108"
- column="42"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `new android.system.NetlinkSocketAddress`"
- errorLine1=" return new NetlinkSocketAddress(portId, groupsMask);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/device/com/android/net/module/util/SocketUtils.java"
- line="44"
- column="16"/>
- </issue>
-
-</issues>
\ No newline at end of file
diff --git a/staticlibs/native/bpf_headers/BpfMapTest.cpp b/staticlibs/native/bpf_headers/BpfMapTest.cpp
index 10afe86..862114d 100644
--- a/staticlibs/native/bpf_headers/BpfMapTest.cpp
+++ b/staticlibs/native/bpf_headers/BpfMapTest.cpp
@@ -107,12 +107,14 @@
BpfMap<uint32_t, uint32_t> testMap1;
checkMapInvalid(testMap1);
- BpfMap<uint32_t, uint32_t> testMap2(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap2;
+ ASSERT_RESULT_OK(testMap2.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
checkMapValid(testMap2);
}
TEST_F(BpfMapTest, basicHelpers) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
uint32_t key = TEST_KEY1;
uint32_t value_write = TEST_VALUE1;
writeToMapAndCheck(testMap, key, value_write);
@@ -126,7 +128,8 @@
}
TEST_F(BpfMapTest, reset) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
uint32_t key = TEST_KEY1;
uint32_t value_write = TEST_VALUE1;
writeToMapAndCheck(testMap, key, value_write);
@@ -138,7 +141,8 @@
}
TEST_F(BpfMapTest, moveConstructor) {
- BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap1;
+ ASSERT_RESULT_OK(testMap1.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
BpfMap<uint32_t, uint32_t> testMap2;
testMap2 = std::move(testMap1);
uint32_t key = TEST_KEY1;
@@ -149,7 +153,8 @@
TEST_F(BpfMapTest, SetUpMap) {
EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK));
- BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap1;
+ ASSERT_RESULT_OK(testMap1.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH));
EXPECT_EQ(0, access(PINNED_MAP_PATH, R_OK));
checkMapValid(testMap1);
@@ -164,7 +169,8 @@
}
TEST_F(BpfMapTest, iterate) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
populateMap(TEST_MAP_SIZE, testMap);
int totalCount = 0;
int totalSum = 0;
@@ -182,7 +188,8 @@
}
TEST_F(BpfMapTest, iterateWithValue) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
populateMap(TEST_MAP_SIZE, testMap);
int totalCount = 0;
int totalSum = 0;
@@ -202,7 +209,8 @@
}
TEST_F(BpfMapTest, mapIsEmpty) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC));
expectMapEmpty(testMap);
uint32_t key = TEST_KEY1;
uint32_t value_write = TEST_VALUE1;
@@ -232,7 +240,8 @@
}
TEST_F(BpfMapTest, mapClear) {
- BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
+ BpfMap<uint32_t, uint32_t> testMap;
+ ASSERT_RESULT_OK(testMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE));
populateMap(TEST_MAP_SIZE, testMap);
Result<bool> isEmpty = testMap.isEmpty();
ASSERT_RESULT_OK(isEmpty);
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h
index dd0804c..81be37d 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h
@@ -22,9 +22,15 @@
// Reject the packet
#define BPF_REJECT BPF_STMT(BPF_RET | BPF_K, 0)
+// Note arguments to BPF_JUMP(opcode, operand, true_offset, false_offset)
+
+// If not equal, jump over count instructions
+#define BPF_JUMP_IF_NOT_EQUAL(v, count) \
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 0, (count))
+
// *TWO* instructions: compare and if not equal jump over the accept statement
#define BPF2_ACCEPT_IF_EQUAL(v) \
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 0, 1), \
+ BPF_JUMP_IF_NOT_EQUAL((v), 1), \
BPF_ACCEPT
// *TWO* instructions: compare and if equal jump over the reject statement
@@ -32,8 +38,24 @@
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 1, 0), \
BPF_REJECT
+// *TWO* instructions: compare and if greater or equal jump over the reject statement
+#define BPF2_REJECT_IF_LESS_THAN(v) \
+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, (v), 1, 0), \
+ BPF_REJECT
+
+// *TWO* instructions: compare and if *NOT* greater jump over the reject statement
+#define BPF2_REJECT_IF_GREATER_THAN(v) \
+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, (v), 0, 1), \
+ BPF_REJECT
+
+// *THREE* instructions: compare and if *NOT* in range [lo, hi], jump over the reject statement
+#define BPF3_REJECT_IF_NOT_IN_RANGE(lo, hi) \
+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, (lo), 0, 1), \
+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, (hi), 0, 1), \
+ BPF_REJECT
+
// *TWO* instructions: compare and if none of the bits are set jump over the reject statement
-#define BPF2_REJECT_IF_ANY_BITS_SET(v) \
+#define BPF2_REJECT_IF_ANY_MASKED_BITS_SET(v) \
BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, (v), 0, 1), \
BPF_REJECT
@@ -108,3 +130,55 @@
_Static_assert(field_sizeof(struct ipv6hdr, field) == 4, "field of wrong size"); \
offsetof(ipv6hdr, field); \
}))
+
+// Load the length of the IPv4 header into X index register.
+// ie. X := 4 * IPv4.IHL, where IPv4.IHL is the bottom nibble
+// of the first byte of the IPv4 (aka network layer) header.
+#define BPF_LOADX_NET_RELATIVE_IPV4_HLEN \
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, (__u32)SKF_NET_OFF)
+
+// Blindly assumes no IPv6 extension headers, just does X := 40
+// You may later adjust this as you parse through IPv6 ext hdrs.
+#define BPF_LOADX_CONSTANT_IPV6_HLEN \
+ BPF_STMT(BPF_LDX | BPF_W | BPF_IMM, sizeof(struct ipv6hdr))
+
+// NOTE: all the following require X to be setup correctly (v4: 20+, v6: 40+)
+
+// 8-bit load from L4 (TCP/UDP/...) header
+#define BPF_LOAD_NETX_RELATIVE_L4_U8(ofs) \
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, (__u32)SKF_NET_OFF + (ofs))
+
+// Big/Network Endian 16-bit load from L4 (TCP/UDP/...) header
+#define BPF_LOAD_NETX_RELATIVE_L4_BE16(ofs) \
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, (__u32)SKF_NET_OFF + (ofs))
+
+// Big/Network Endian 32-bit load from L4 (TCP/UDP/...) header
+#define BPF_LOAD_NETX_RELATIVE_L4_BE32(ofs) \
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, (__u32)SKF_NET_OFF + (ofs))
+
+// Both ICMPv4 and ICMPv6 start with u8 type, u8 code
+#define BPF_LOAD_NETX_RELATIVE_ICMP_TYPE BPF_LOAD_NETX_RELATIVE_L4_U8(0)
+#define BPF_LOAD_NETX_RELATIVE_ICMP_CODE BPF_LOAD_NETX_RELATIVE_L4_U8(1)
+
+// IPv6 extension headers (HOPOPTS, DSTOPS, FRAG) begin with a u8 nexthdr
+#define BPF_LOAD_NETX_RELATIVE_V6EXTHDR_NEXTHDR BPF_LOAD_NETX_RELATIVE_L4_U8(0)
+
+// IPv6 fragment header is always exactly 8 bytes long
+#define BPF_LOAD_CONSTANT_V6FRAGHDR_LEN \
+ BPF_STMT(BPF_LD | BPF_IMM, 8)
+
+// HOPOPTS/DSTOPS follow up with 'u8 len', counting 8 byte units, (0->8, 1->16)
+// *THREE* instructions
+#define BPF3_LOAD_NETX_RELATIVE_V6EXTHDR_LEN \
+ BPF_LOAD_NETX_RELATIVE_L4_U8(1), \
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 1), \
+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 3)
+
+// *TWO* instructions: A += X; X := A
+#define BPF2_ADD_A_TO_X \
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), \
+ BPF_STMT(BPF_MISC | BPF_TAX, 0)
+
+// UDP/UDPLITE/TCP/SCTP/DCCP all start with be16 srcport, dstport
+#define BPF_LOAD_NETX_RELATIVE_SRC_PORT BPF_LOAD_NETX_RELATIVE_L4_BE16(0)
+#define BPF_LOAD_NETX_RELATIVE_DST_PORT BPF_LOAD_NETX_RELATIVE_L4_BE16(2)
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h
index 3be7067..5d7eb0d 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h
@@ -48,41 +48,32 @@
// is not safe to iterate over a map while another thread or process is deleting
// from it. In this case the iteration can return duplicate entries.
template <class Key, class Value>
-class BpfMap {
+class BpfMapRO {
public:
- BpfMap<Key, Value>() {};
+ BpfMapRO<Key, Value>() {};
// explicitly force no copy constructor, since it would need to dup the fd
// (later on, for testing, we still make available a copy assignment operator)
- BpfMap<Key, Value>(const BpfMap<Key, Value>&) = delete;
+ BpfMapRO<Key, Value>(const BpfMapRO<Key, Value>&) = delete;
- private:
- void abortOnKeyOrValueSizeMismatch() {
+ protected:
+ void abortOnMismatch(bool writable) const {
if (!mMapFd.ok()) abort();
if (isAtLeastKernelVersion(4, 14, 0)) {
+ int flags = bpfGetFdMapFlags(mMapFd);
+ if (flags < 0) abort();
+ if (flags & BPF_F_WRONLY) abort();
+ if (writable && (flags & BPF_F_RDONLY)) abort();
if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort();
if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort();
}
}
- protected:
- // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY
- BpfMap<Key, Value>(const char* pathname, uint32_t flags) {
- mMapFd.reset(mapRetrieve(pathname, flags));
- abortOnKeyOrValueSizeMismatch();
- }
-
public:
- explicit BpfMap<Key, Value>(const char* pathname) : BpfMap<Key, Value>(pathname, 0) {}
-
-#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
- // All bpf maps should be created by the bpfloader, so this constructor
- // is reserved for tests
- BpfMap<Key, Value>(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) {
- mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags));
- if (!mMapFd.ok()) abort();
+ explicit BpfMapRO<Key, Value>(const char* pathname) {
+ mMapFd.reset(mapRetrieveRO(pathname));
+ abortOnMismatch(/* writable */ false);
}
-#endif
Result<Key> getFirstKey() const {
Key firstKey;
@@ -100,13 +91,6 @@
return nextKey;
}
- Result<void> writeValue(const Key& key, const Value& value, uint64_t flags) {
- if (writeToMapEntry(mMapFd, &key, &value, flags)) {
- return ErrnoErrorf("Write to map {} failed", mMapFd.get());
- }
- return {};
- }
-
Result<Value> readValue(const Key key) const {
Value value;
if (findMapEntry(mMapFd, &key, &value)) {
@@ -115,6 +99,155 @@
return value;
}
+ protected:
+ [[clang::reinitializes]] Result<void> init(const char* path, int fd, bool writable) {
+ mMapFd.reset(fd);
+ if (!mMapFd.ok()) {
+ return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path);
+ }
+ // Normally we should return an error here instead of calling abort,
+ // but this cannot happen at runtime without a massive code bug (K/V type mismatch)
+ // and as such it's better to just blow the system up and let the developer fix it.
+ // Crashes are much more likely to be noticed than logs and missing functionality.
+ abortOnMismatch(writable);
+ return {};
+ }
+
+ public:
+ // Function that tries to get map from a pinned path.
+ [[clang::reinitializes]] Result<void> init(const char* path) {
+ return init(path, mapRetrieveRO(path), /* writable */ false);
+ }
+
+ // Iterate through the map and handle each key retrieved based on the filter
+ // without modification of map content.
+ Result<void> iterate(
+ const function<Result<void>(const Key& key,
+ const BpfMapRO<Key, Value>& map)>& filter) const;
+
+ // Iterate through the map and get each <key, value> pair, handle each <key,
+ // value> pair based on the filter without modification of map content.
+ Result<void> iterateWithValue(
+ const function<Result<void>(const Key& key, const Value& value,
+ const BpfMapRO<Key, Value>& map)>& filter) const;
+
+#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
+ const unique_fd& getMap() const { return mMapFd; };
+
+ // Copy assignment operator - due to need for fd duping, should not be used in non-test code.
+ BpfMapRO<Key, Value>& operator=(const BpfMapRO<Key, Value>& other) {
+ if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0));
+ return *this;
+ }
+#else
+ BpfMapRO<Key, Value>& operator=(const BpfMapRO<Key, Value>&) = delete;
+#endif
+
+ // Move assignment operator
+ BpfMapRO<Key, Value>& operator=(BpfMapRO<Key, Value>&& other) noexcept {
+ if (this != &other) {
+ mMapFd = std::move(other.mMapFd);
+ other.reset();
+ }
+ return *this;
+ }
+
+#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
+ // Note that unique_fd.reset() carefully saves and restores the errno,
+ // and BpfMap.reset() won't touch the errno if passed in fd is negative either,
+ // hence you can do something like BpfMap.reset(systemcall()) and then
+ // check BpfMap.isValid() and look at errno and see why systemcall() failed.
+ [[clang::reinitializes]] void reset(int fd) {
+ mMapFd.reset(fd);
+ if (mMapFd.ok()) abortOnMismatch(/* writable */ false); // false isn't ideal
+ }
+
+ // unique_fd has an implicit int conversion defined, which combined with the above
+ // reset(int) would result in double ownership of the fd, hence we either need a custom
+ // implementation of reset(unique_fd), or to delete it and thus cause compile failures
+ // to catch this and prevent it.
+ void reset(unique_fd fd) = delete;
+#endif
+
+ [[clang::reinitializes]] void reset() {
+ mMapFd.reset();
+ }
+
+ bool isValid() const { return mMapFd.ok(); }
+
+ Result<bool> isEmpty() const {
+ auto key = getFirstKey();
+ if (key.ok()) return false;
+ if (key.error().code() == ENOENT) return true;
+ return key.error();
+ }
+
+ protected:
+ unique_fd mMapFd;
+};
+
+template <class Key, class Value>
+Result<void> BpfMapRO<Key, Value>::iterate(
+ const function<Result<void>(const Key& key,
+ const BpfMapRO<Key, Value>& map)>& filter) const {
+ Result<Key> curKey = getFirstKey();
+ while (curKey.ok()) {
+ const Result<Key>& nextKey = getNextKey(curKey.value());
+ Result<void> status = filter(curKey.value(), *this);
+ if (!status.ok()) return status;
+ curKey = nextKey;
+ }
+ if (curKey.error().code() == ENOENT) return {};
+ return curKey.error();
+}
+
+template <class Key, class Value>
+Result<void> BpfMapRO<Key, Value>::iterateWithValue(
+ const function<Result<void>(const Key& key, const Value& value,
+ const BpfMapRO<Key, Value>& map)>& filter) const {
+ Result<Key> curKey = getFirstKey();
+ while (curKey.ok()) {
+ const Result<Key>& nextKey = getNextKey(curKey.value());
+ Result<Value> curValue = readValue(curKey.value());
+ if (!curValue.ok()) return curValue.error();
+ Result<void> status = filter(curKey.value(), curValue.value(), *this);
+ if (!status.ok()) return status;
+ curKey = nextKey;
+ }
+ if (curKey.error().code() == ENOENT) return {};
+ return curKey.error();
+}
+
+template <class Key, class Value>
+class BpfMap : public BpfMapRO<Key, Value> {
+ protected:
+ using BpfMapRO<Key, Value>::mMapFd;
+ using BpfMapRO<Key, Value>::abortOnMismatch;
+
+ public:
+ using BpfMapRO<Key, Value>::getFirstKey;
+ using BpfMapRO<Key, Value>::getNextKey;
+ using BpfMapRO<Key, Value>::readValue;
+
+ BpfMap<Key, Value>() {};
+
+ explicit BpfMap<Key, Value>(const char* pathname) {
+ mMapFd.reset(mapRetrieveRW(pathname));
+ abortOnMismatch(/* writable */ true);
+ }
+
+ // Function that tries to get map from a pinned path.
+ [[clang::reinitializes]] Result<void> init(const char* path) {
+ return BpfMapRO<Key,Value>::init(path, mapRetrieveRW(path), /* writable */ true);
+ }
+
+ Result<void> writeValue(const Key& key, const Value& value, uint64_t flags) {
+ if (writeToMapEntry(mMapFd, &key, &value, flags)) {
+ return ErrnoErrorf("Write to map {} failed", mMapFd.get());
+ }
+ return {};
+ }
+
Result<void> deleteValue(const Key& key) {
if (deleteMapEntry(mMapFd, &key)) {
return ErrnoErrorf("Delete entry from map {} failed", mMapFd.get());
@@ -122,37 +255,33 @@
return {};
}
- protected:
- [[clang::reinitializes]] Result<void> init(const char* path, int fd) {
- mMapFd.reset(fd);
- if (!mMapFd.ok()) {
- return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path);
+ Result<void> clear() {
+ while (true) {
+ auto key = getFirstKey();
+ if (!key.ok()) {
+ if (key.error().code() == ENOENT) return {}; // empty: success
+ return key.error(); // Anything else is an error
+ }
+ auto res = deleteValue(key.value());
+ if (!res.ok()) {
+ // Someone else could have deleted the key, so ignore ENOENT
+ if (res.error().code() == ENOENT) continue;
+ ALOGE("Failed to delete data %s", strerror(res.error().code()));
+ return res.error();
+ }
}
- // Normally we should return an error here instead of calling abort,
- // but this cannot happen at runtime without a massive code bug (K/V type mismatch)
- // and as such it's better to just blow the system up and let the developer fix it.
- // Crashes are much more likely to be noticed than logs and missing functionality.
- abortOnKeyOrValueSizeMismatch();
- return {};
}
- public:
- // Function that tries to get map from a pinned path.
- [[clang::reinitializes]] Result<void> init(const char* path) {
- return init(path, mapRetrieveRW(path));
- }
-
-
#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
- // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader
- // this should only ever be used by test code, it is equivalent to:
- // .reset(createMap(type, keysize, valuesize, max_entries, map_flags)
- // TODO: derive map_flags from BpfMap vs BpfMapRO
[[clang::reinitializes]] Result<void> resetMap(bpf_map_type map_type,
- uint32_t max_entries,
- uint32_t map_flags = 0) {
- mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags));
+ uint32_t max_entries,
+ uint32_t map_flags = 0) {
+ if (map_flags & BPF_F_WRONLY) abort();
+ if (map_flags & BPF_F_RDONLY) abort();
+ mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries,
+ map_flags));
if (!mMapFd.ok()) return ErrnoErrorf("Unable to create map.");
+ abortOnMismatch(/* writable */ true);
return {};
}
#endif
@@ -180,72 +309,6 @@
const function<Result<void>(const Key& key, const Value& value,
BpfMap<Key, Value>& map)>& filter);
-#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
- const unique_fd& getMap() const { return mMapFd; };
-
- // Copy assignment operator - due to need for fd duping, should not be used in non-test code.
- BpfMap<Key, Value>& operator=(const BpfMap<Key, Value>& other) {
- if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0));
- return *this;
- }
-#else
- BpfMap<Key, Value>& operator=(const BpfMap<Key, Value>&) = delete;
-#endif
-
- // Move assignment operator
- BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept {
- if (this != &other) {
- mMapFd = std::move(other.mMapFd);
- other.reset();
- }
- return *this;
- }
-
- void reset(unique_fd fd) = delete;
-
-#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING
- // Note that unique_fd.reset() carefully saves and restores the errno,
- // and BpfMap.reset() won't touch the errno if passed in fd is negative either,
- // hence you can do something like BpfMap.reset(systemcall()) and then
- // check BpfMap.isValid() and look at errno and see why systemcall() failed.
- [[clang::reinitializes]] void reset(int fd) {
- mMapFd.reset(fd);
- if (mMapFd.ok()) abortOnKeyOrValueSizeMismatch();
- }
-#endif
-
- [[clang::reinitializes]] void reset() {
- mMapFd.reset();
- }
-
- bool isValid() const { return mMapFd.ok(); }
-
- Result<void> clear() {
- while (true) {
- auto key = getFirstKey();
- if (!key.ok()) {
- if (key.error().code() == ENOENT) return {}; // empty: success
- return key.error(); // Anything else is an error
- }
- auto res = deleteValue(key.value());
- if (!res.ok()) {
- // Someone else could have deleted the key, so ignore ENOENT
- if (res.error().code() == ENOENT) continue;
- ALOGE("Failed to delete data %s", strerror(res.error().code()));
- return res.error();
- }
- }
- }
-
- Result<bool> isEmpty() const {
- auto key = getFirstKey();
- if (key.ok()) return false;
- if (key.error().code() == ENOENT) return true;
- return key.error();
- }
-
- private:
- unique_fd mMapFd;
};
template <class Key, class Value>
@@ -312,19 +375,5 @@
return curKey.error();
}
-template <class Key, class Value>
-class BpfMapRO : public BpfMap<Key, Value> {
- public:
- BpfMapRO<Key, Value>() {};
-
- explicit BpfMapRO<Key, Value>(const char* pathname)
- : BpfMap<Key, Value>(pathname, BPF_F_RDONLY) {}
-
- // Function that tries to get map from a pinned path.
- [[clang::reinitializes]] Result<void> init(const char* path) {
- return BpfMap<Key,Value>::init(path, mapRetrieveRO(path));
- }
-};
-
} // namespace bpf
} // namespace android
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 67ac0e4..baff09b 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -105,9 +105,19 @@
* implemented in the kernel sources.
*/
-#define KVER_NONE 0
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-#define KVER_INF 0xFFFFFFFFu
+struct kver_uint { unsigned int kver; };
+#define KVER_(v) ((struct kver_uint){ .kver = (v) })
+#define KVER(a, b, c) KVER_(((a) << 24) + ((b) << 16) + (c))
+#define KVER_NONE KVER_(0)
+#define KVER_4_14 KVER(4, 14, 0)
+#define KVER_4_19 KVER(4, 19, 0)
+#define KVER_5_4 KVER(5, 4, 0)
+#define KVER_5_8 KVER(5, 8, 0)
+#define KVER_5_9 KVER(5, 9, 0)
+#define KVER_5_15 KVER(5, 15, 0)
+#define KVER_INF KVER_(0xFFFFFFFFu)
+
+#define KVER_IS_AT_LEAST(kver, a, b, c) ((kver).kver >= KVER(a, b, c).kver)
/*
* BPFFS (ie. /sys/fs/bpf) labelling is as follows:
@@ -188,10 +198,12 @@
__attribute__ ((section(".maps." #name), used)) \
____btf_map_##name = { }
-#define BPF_ASSERT_LOADER_VERSION(min_loader, ignore_eng, ignore_user, ignore_userdebug) \
- _Static_assert( \
- (min_loader) >= BPFLOADER_IGNORED_ON_VERSION || \
- !((ignore_eng) || (ignore_user) || (ignore_userdebug)), \
+#define BPF_ASSERT_LOADER_VERSION(min_loader, ignore_eng, ignore_user, ignore_userdebug) \
+ _Static_assert( \
+ (min_loader) >= BPFLOADER_IGNORED_ON_VERSION || \
+ !((ignore_eng).ignore_on_eng || \
+ (ignore_user).ignore_on_user || \
+ (ignore_userdebug).ignore_on_userdebug), \
"bpfloader min version must be >= 0.33 in order to use ignored_on");
#define DEFINE_BPF_MAP_BASE(the_map, TYPE, keysize, valuesize, num_entries, \
@@ -209,14 +221,14 @@
.mode = (md), \
.bpfloader_min_ver = (minloader), \
.bpfloader_max_ver = (maxloader), \
- .min_kver = (minkver), \
- .max_kver = (maxkver), \
+ .min_kver = (minkver).kver, \
+ .max_kver = (maxkver).kver, \
.selinux_context = (selinux), \
.pin_subdir = (pindir), \
- .shared = (share), \
- .ignore_on_eng = (ignore_eng), \
- .ignore_on_user = (ignore_user), \
- .ignore_on_userdebug = (ignore_userdebug), \
+ .shared = (share).shared, \
+ .ignore_on_eng = (ignore_eng).ignore_on_eng, \
+ .ignore_on_user = (ignore_user).ignore_on_user, \
+ .ignore_on_userdebug = (ignore_userdebug).ignore_on_userdebug, \
}; \
BPF_ASSERT_LOADER_VERSION(minloader, ignore_eng, ignore_user, ignore_userdebug);
@@ -230,7 +242,7 @@
selinux, pindir, share, min_loader, max_loader, \
ignore_eng, ignore_user, ignore_userdebug) \
DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \
- selinux, pindir, share, KVER(5, 8, 0), KVER_INF, \
+ selinux, pindir, share, KVER_5_8, KVER_INF, \
min_loader, max_loader, ignore_eng, ignore_user, \
ignore_userdebug); \
\
@@ -312,11 +324,11 @@
#error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.28"
#endif
-#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \
- DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, /*ignore_on_eng*/false, \
- /*ignore_on_user*/false, /*ignore_on_userdebug*/false)
+#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \
+ DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, PRIVATE, \
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
+ LOAD_ON_USER, LOAD_ON_USERDEBUG)
#define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \
DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
@@ -362,16 +374,16 @@
const struct bpf_prog_def SECTION("progs") the_prog##_def = { \
.uid = (prog_uid), \
.gid = (prog_gid), \
- .min_kver = (min_kv), \
- .max_kver = (max_kv), \
- .optional = (opt), \
+ .min_kver = (min_kv).kver, \
+ .max_kver = (max_kv).kver, \
+ .optional = (opt).optional, \
.bpfloader_min_ver = (min_loader), \
.bpfloader_max_ver = (max_loader), \
.selinux_context = (selinux), \
.pin_subdir = (pindir), \
- .ignore_on_eng = (ignore_eng), \
- .ignore_on_user = (ignore_user), \
- .ignore_on_userdebug = (ignore_userdebug), \
+ .ignore_on_eng = (ignore_eng).ignore_on_eng, \
+ .ignore_on_user = (ignore_user).ignore_on_user, \
+ .ignore_on_userdebug = (ignore_userdebug).ignore_on_userdebug, \
}; \
SECTION(SECTION_NAME) \
int the_prog
@@ -389,7 +401,7 @@
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, opt, \
DEFAULT_BPF_PROG_SELINUX_CONTEXT, DEFAULT_BPF_PROG_PIN_SUBDIR, \
- false, false, false)
+ LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
// Programs (here used in the sense of functions/sections) marked optional are allowed to fail
// to load (for example due to missing kernel patches).
@@ -405,21 +417,24 @@
// programs requiring a kernel version >= min_kv && < max_kv
#define DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv) \
DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
- false)
+ MANDATORY)
#define DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, \
max_kv) \
- DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, true)
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
+ OPTIONAL)
// programs requiring a kernel version >= min_kv
#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
- false)
+ MANDATORY)
#define DEFINE_OPTIONAL_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
- true)
+ OPTIONAL)
// programs with no kernel version requirements
#define DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
- DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, false)
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \
+ MANDATORY)
#define DEFINE_OPTIONAL_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
- DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, true)
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \
+ OPTIONAL)
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
index e7428b6..ef03c4d 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
@@ -114,6 +114,31 @@
// BPF wants 8, but 32-bit x86 wants 4
//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
+
+// for maps:
+struct shared_bool { bool shared; };
+#define PRIVATE ((struct shared_bool){ .shared = false })
+#define SHARED ((struct shared_bool){ .shared = true })
+
+// for programs:
+struct optional_bool { bool optional; };
+#define MANDATORY ((struct optional_bool){ .optional = false })
+#define OPTIONAL ((struct optional_bool){ .optional = true })
+
+// for both maps and programs:
+struct ignore_on_eng_bool { bool ignore_on_eng; };
+#define LOAD_ON_ENG ((struct ignore_on_eng_bool){ .ignore_on_eng = false })
+#define IGNORE_ON_ENG ((struct ignore_on_eng_bool){ .ignore_on_eng = true })
+
+struct ignore_on_user_bool { bool ignore_on_user; };
+#define LOAD_ON_USER ((struct ignore_on_user_bool){ .ignore_on_user = false })
+#define IGNORE_ON_USER ((struct ignore_on_user_bool){ .ignore_on_user = true })
+
+struct ignore_on_userdebug_bool { bool ignore_on_userdebug; };
+#define LOAD_ON_USERDEBUG ((struct ignore_on_userdebug_bool){ .ignore_on_userdebug = false })
+#define IGNORE_ON_USERDEBUG ((struct ignore_on_userdebug_bool){ .ignore_on_userdebug = true })
+
+
// Length of strings (incl. selinux_context and pin_subdir)
// in the bpf_map_def and bpf_prog_def structs.
//
diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
index 13f7cb3..9995cb9 100644
--- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
+++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
@@ -44,6 +44,11 @@
return syscall(__NR_bpf, cmd, &attr, sizeof(attr));
}
+// this version is meant for use with cmd's which mutate the argument
+inline int bpf(enum bpf_cmd cmd, bpf_attr *attr) {
+ return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
+}
+
inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
uint32_t max_entries, uint32_t map_flags) {
return bpf(BPF_MAP_CREATE, {
@@ -160,6 +165,27 @@
});
}
+inline int queryProgram(const BPF_FD_TYPE cg_fd,
+ enum bpf_attach_type attach_type,
+ __u32 query_flags = 0,
+ __u32 attach_flags = 0) {
+ int prog_id = -1; // equivalent to an array of one integer.
+ bpf_attr arg = {
+ .query = {
+ .target_fd = BPF_FD_TO_U32(cg_fd),
+ .attach_type = attach_type,
+ .query_flags = query_flags,
+ .attach_flags = attach_flags,
+ .prog_ids = ptr_to_u64(&prog_id), // pointer to output array
+ .prog_cnt = 1, // in: space - nr of ints in the array, out: used
+ }
+ };
+ int v = bpf(BPF_PROG_QUERY, &arg);
+ if (v) return v; // error case
+ if (!arg.query.prog_cnt) return 0; // no program, kernel never returns zero id
+ return prog_id; // return actual id
+}
+
inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd,
const BPF_FD_TYPE cg_fd) {
return bpf(BPF_PROG_DETACH, {
diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
index cb06afb..ab83da6 100644
--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
+++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
@@ -27,7 +27,7 @@
}
static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env,
- jobject clazz,
+ jclass clazz,
jstring iface) {
ScopedUtfChars interface(env, iface);
bool result = false;
@@ -43,7 +43,7 @@
// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
// /sys/fs/bpf/... direct-action
static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf(
- JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio,
+ JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
jshort proto, jstring bpfProgPath) {
ScopedUtfChars pathname(env, bpfProgPath);
int error = tcAddBpfFilter(ifIndex, ingress, prio, proto, pathname.c_str());
@@ -59,7 +59,7 @@
// action bpf object-pinned .. \
// drop
static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(
- JNIEnv *env, jobject clazz, jint ifIndex, jshort prio, jshort proto,
+ JNIEnv *env, jclass clazz, jint ifIndex, jshort prio, jshort proto,
jint rateInBytesPerSec, jstring bpfProgPath) {
ScopedUtfChars pathname(env, bpfProgPath);
int error = tcAddIngressPoliceFilter(ifIndex, prio, proto, rateInBytesPerSec,
@@ -74,7 +74,7 @@
// tc filter del dev .. in/egress prio .. protocol ..
static void com_android_net_module_util_TcUtils_tcFilterDelDev(
- JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio,
+ JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
jshort proto) {
int error = tcDeleteFilter(ifIndex, ingress, prio, proto);
if (error) {
@@ -86,7 +86,7 @@
// tc qdisc add dev .. clsact
static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env,
- jobject clazz,
+ jclass clazz,
jint ifIndex) {
int error = tcAddQdiscClsact(ifIndex);
if (error) {
diff --git a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
index 0f2ebbd..cf09379 100644
--- a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
+++ b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
@@ -32,7 +32,7 @@
// If attach fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_attachProgramToCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) {
+ jclass clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -62,7 +62,7 @@
// If detach fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_detachProgramFromCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring cgroupPath) {
+ jclass clazz, jint type, jstring cgroupPath) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -83,7 +83,7 @@
// If detach single program fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath) {
+ jclass clazz, jint type, jstring bpfProgPath, jstring cgroupPath) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -110,6 +110,29 @@
return true;
}
+static jint com_android_net_module_util_BpfUtil_getProgramIdFromCgroup(JNIEnv *env,
+ jclass clazz, jint type, jstring cgroupPath) {
+
+ ScopedUtfChars dirPath(env, cgroupPath);
+ unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+ if (cg_fd == -1) {
+ jniThrowExceptionFmt(env, "java/io/IOException",
+ "Failed to open the cgroup directory %s: %s",
+ dirPath.c_str(), strerror(errno));
+ return -1;
+ }
+
+ int id = bpf::queryProgram(cg_fd, (bpf_attach_type) type);
+ if (id < 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException",
+ "Failed to query bpf program %d at %s: %s",
+ type, dirPath.c_str(), strerror(errno));
+ return -1;
+ }
+ return id; // may return 0 meaning none
+}
+
+
/*
* JNI registration.
*/
@@ -121,6 +144,8 @@
(void*) com_android_net_module_util_BpfUtil_detachProgramFromCgroup },
{ "native_detachSingleProgramFromCgroup", "(ILjava/lang/String;Ljava/lang/String;)Z",
(void*) com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup },
+ { "native_getProgramIdFromCgroup", "(ILjava/lang/String;)I",
+ (void*) com_android_net_module_util_BpfUtil_getProgramIdFromCgroup },
};
int register_com_android_net_module_util_BpfUtils(JNIEnv* env, char const* class_name) {
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
index 5a96bcb..06b3e2f 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
@@ -71,6 +71,10 @@
public class DeviceConfigUtilsTest {
private static final String TEST_NAME_SPACE = "connectivity";
private static final String TEST_EXPERIMENT_FLAG = "experiment_flag";
+ private static final String CORE_NETWORKING_TRUNK_STABLE_NAMESPACE = "android_core_networking";
+ private static final String TEST_TRUNK_STABLE_FLAG = "trunk_stable_feature";
+ private static final String TEST_CORE_NETWORKING_TRUNK_STABLE_FLAG_PROPERTY =
+ "com.android.net.flags.trunk_stable_feature";
private static final int TEST_FLAG_VALUE = 28;
private static final String TEST_FLAG_VALUE_STRING = "28";
private static final int TEST_DEFAULT_FLAG_VALUE = 0;
@@ -228,27 +232,57 @@
}
@Test
- public void testIsNetworkStackFeatureEnabled() {
+ public void testIsFeatureEnabled() {
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
TEST_EXPERIMENT_FLAG));
- assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
- }
-
- @Test
- public void testIsTetheringFeatureEnabled() {
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
}
-
@Test
- public void testFeatureDefaultEnabled() {
+ public void testIsFeatureEnabledFeatureDefaultDisabled() throws Exception {
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
TEST_EXPERIMENT_FLAG));
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
+
+ // If the flag is unset, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
+ public void testIsFeatureEnabledFeatureForceEnabled() throws Exception {
+ doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
+
+ // If the feature is force enabled, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
+ public void testIsFeatureEnabledFeatureForceDisabled() throws Exception {
+ doReturn("-1").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn("-1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
+ assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
+
+ // If the feature is force disabled, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
}
@Test
@@ -271,15 +305,12 @@
assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
- // Follow defaultEnabled if the flag is not set
+ // If the flag is not set feature is disabled
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
TEST_EXPERIMENT_FLAG));
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
TEST_EXPERIMENT_FLAG));
- assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG,
- false /* defaultEnabled */));
- assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG,
- true /* defaultEnabled */));
+ assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
}
@@ -415,25 +446,86 @@
}
@Test
- public void testIsTetheringFeatureNotChickenedOut() throws Exception {
- doReturn("0").when(() -> DeviceConfig.getProperty(
- eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG)));
- assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG));
-
- doReturn(TEST_FLAG_VALUE_STRING).when(
- () -> DeviceConfig.getProperty(eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG)));
- assertFalse(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG));
+ public void testIsFeatureNotChickenedOut() {
+ doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
}
@Test
- public void testIsNetworkStackFeatureNotChickenedOut() throws Exception {
- doReturn("0").when(() -> DeviceConfig.getProperty(
- eq(NAMESPACE_CONNECTIVITY), eq(TEST_EXPERIMENT_FLAG)));
- assertTrue(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG));
+ public void testIsFeatureNotChickenedOutFeatureDefaultEnabled() throws Exception {
+ doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
- doReturn(TEST_FLAG_VALUE_STRING).when(
- () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
- eq(TEST_EXPERIMENT_FLAG)));
- assertFalse(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG));
+ // If the flag is unset, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
+ public void testIsFeatureNotChickenedOutFeatureForceEnabled() throws Exception {
+ doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+ assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+
+ // If the feature is force enabled, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
+ public void testIsFeatureNotChickenedOutFeatureForceDisabled() throws Exception {
+ doReturn("-1").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
+ TEST_EXPERIMENT_FLAG));
+ doReturn("-1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
+ TEST_EXPERIMENT_FLAG));
+ assertFalse(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+ assertFalse(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ mContext, TEST_EXPERIMENT_FLAG));
+
+ // If the feature is force disabled, package info is not queried
+ verify(mContext, never()).getPackageManager();
+ verify(mContext, never()).getPackageName();
+ verify(mPm, never()).getPackageInfo(anyString(), anyInt());
+ }
+
+ @Test
+ public void testIsCoreNetworkingTrunkStableFeatureEnabled() {
+ doReturn(null).when(() -> DeviceConfig.getProperty(
+ CORE_NETWORKING_TRUNK_STABLE_NAMESPACE,
+ TEST_CORE_NETWORKING_TRUNK_STABLE_FLAG_PROPERTY));
+ assertFalse(DeviceConfigUtils.isTrunkStableFeatureEnabled(
+ TEST_TRUNK_STABLE_FLAG));
+
+ doReturn("false").when(() -> DeviceConfig.getProperty(
+ CORE_NETWORKING_TRUNK_STABLE_NAMESPACE,
+ TEST_CORE_NETWORKING_TRUNK_STABLE_FLAG_PROPERTY));
+ assertFalse(DeviceConfigUtils.isTrunkStableFeatureEnabled(
+ TEST_TRUNK_STABLE_FLAG));
+
+ doReturn("true").when(() -> DeviceConfig.getProperty(
+ CORE_NETWORKING_TRUNK_STABLE_NAMESPACE,
+ TEST_CORE_NETWORKING_TRUNK_STABLE_FLAG_PROPERTY));
+ assertTrue(DeviceConfigUtils.isTrunkStableFeatureEnabled(
+ TEST_TRUNK_STABLE_FLAG));
}
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
index 3a72dd1..5e9b004 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
@@ -88,6 +88,11 @@
if (SdkLevel.isAtLeastT() && targetSdk > 31) {
var ctxt = new String(Files.readAllBytes(Paths.get("/proc/thread-self/attr/current")));
assumeFalse("must not be platform app", ctxt.startsWith("u:r:platform_app:s0:"));
+ // NetworkStackCoverageTests uses the same UID with NetworkStack module, which
+ // still has the permission to send RTM_GETNEIGH message (sepolicy just blocks the
+ // access from untrusted_apps), also exclude the NetworkStackCoverageTests.
+ assumeFalse("network_stack context is expected to have permission to send RTM_GETNEIGH",
+ ctxt.startsWith("u:r:network_stack:s0"));
try {
NetlinkUtils.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS);
fail("RTM_GETNEIGH is not allowed for apps targeting SDK > 31 on T+ platforms,"
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
index 2e73666..2d281fd 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
@@ -19,6 +19,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import java.lang.reflect.Modifier
import org.junit.runner.Description
import org.junit.runner.Runner
import org.junit.runner.manipulation.Filter
@@ -27,7 +28,7 @@
import org.junit.runner.manipulation.Sortable
import org.junit.runner.manipulation.Sorter
import org.junit.runner.notification.RunNotifier
-import kotlin.jvm.Throws
+import org.junit.runners.Parameterized
/**
* A runner that can skip tests based on the development SDK as defined in [DevSdkIgnoreRule].
@@ -41,6 +42,9 @@
* the whole class if they do not match the development SDK as defined in [DevSdkIgnoreRule].
* Otherwise, it will delegate to [AndroidJUnit4] to run the test as usual.
*
+ * This class automatically uses the Parameterized runner as its base runner when needed, so the
+ * @Parameterized.Parameters annotation and its friends can be used in tests using this runner.
+ *
* Example usage:
*
* @RunWith(DevSdkIgnoreRunner::class)
@@ -48,13 +52,34 @@
* class MyTestClass { ... }
*/
class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner(), Filterable, Sortable {
- private val baseRunner = klass.let {
+ // Inference correctly infers Runner & Filterable & Sortable for |baseRunner|, but the
+ // Java bytecode doesn't have a way to express this. Give this type a name by wrapping it.
+ private class RunnerWrapper<T>(private val wrapped: T) :
+ Runner(), Filterable by wrapped, Sortable by wrapped
+ where T : Runner, T : Filterable, T : Sortable {
+ override fun getDescription(): Description = wrapped.description
+ override fun run(notifier: RunNotifier?) = wrapped.run(notifier)
+ }
+
+ private val baseRunner: RunnerWrapper<*>? = klass.let {
val ignoreAfter = it.getAnnotation(IgnoreAfter::class.java)
val ignoreUpTo = it.getAnnotation(IgnoreUpTo::class.java)
- if (isDevSdkInRange(ignoreUpTo, ignoreAfter)) AndroidJUnit4(klass) else null
+ if (!isDevSdkInRange(ignoreUpTo, ignoreAfter)) {
+ null
+ } else if (it.hasParameterizedMethod()) {
+ // Parameterized throws if there is no static method annotated with @Parameters, which
+ // isn't too useful. Use it if there are, otherwise use its base AndroidJUnit4 runner.
+ RunnerWrapper(Parameterized(klass))
+ } else {
+ RunnerWrapper(AndroidJUnit4(klass))
+ }
}
+ private fun <T> Class<T>.hasParameterizedMethod(): Boolean = methods.any {
+ Modifier.isStatic(it.modifiers) &&
+ it.isAnnotationPresent(Parameterized.Parameters::class.java) }
+
override fun run(notifier: RunNotifier) {
if (baseRunner != null) {
baseRunner.run(notifier)
@@ -88,4 +113,4 @@
override fun sort(sorter: Sorter?) {
baseRunner?.sort(sorter)
}
-}
\ No newline at end of file
+}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 5f321bb..d92fb01 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -199,7 +199,8 @@
protected void tearDown() throws Exception {
executeShellCommand("cmd netpolicy stop-watching");
mServiceClient.unbind();
- if (mLock.isHeld()) mLock.release();
+ final PowerManager.WakeLock lock = mLock;
+ if (null != lock && lock.isHeld()) lock.release();
}
protected int getUid(String packageName) throws Exception {
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index 6de663a..b86de25 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -55,7 +55,7 @@
"junit-params",
"modules-utils-build",
"net-utils-framework-common",
- "truth-prebuilt",
+ "truth",
"TetheringIntegrationTestsBaseLib",
],
@@ -74,7 +74,10 @@
// devices.
android_test {
name: "CtsNetTestCases",
- defaults: ["CtsNetTestCasesDefaults", "ConnectivityNextEnableDefaults"],
+ defaults: [
+ "CtsNetTestCasesDefaults",
+ "ConnectivityNextEnableDefaults",
+ ],
static_libs: [
"DhcpPacketLib",
"NetworkStackApiCurrentShims",
@@ -129,7 +132,7 @@
}
android_test {
- name: "CtsNetTestCasesMaxTargetSdk33", // Must match CtsNetTestCasesMaxTargetSdk33 annotation.
+ name: "CtsNetTestCasesMaxTargetSdk33", // Must match CtsNetTestCasesMaxTargetSdk33 annotation.
defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
target_sdk_version: "33",
package_name: "android.net.cts.maxtargetsdk33",
@@ -137,17 +140,17 @@
}
android_test {
- name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation.
+ name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation.
defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
target_sdk_version: "31",
- package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique.
+ package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique.
instrumentation_target_package: "android.net.cts.maxtargetsdk31",
}
android_test {
- name: "CtsNetTestCasesMaxTargetSdk30", // Must match CtsNetTestCasesMaxTargetSdk30 annotation.
+ name: "CtsNetTestCasesMaxTargetSdk30", // Must match CtsNetTestCasesMaxTargetSdk30 annotation.
defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"],
target_sdk_version: "30",
- package_name: "android.net.cts.maxtargetsdk30", // CTS package names must be unique.
+ package_name: "android.net.cts.maxtargetsdk30", // CTS package names must be unique.
instrumentation_target_package: "android.net.cts.maxtargetsdk30",
}
diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp
index 9b81a56..1f1dd5d 100644
--- a/tests/cts/net/api23Test/Android.bp
+++ b/tests/cts/net/api23Test/Android.bp
@@ -41,7 +41,7 @@
"mockwebserver",
"junit",
"junit-params",
- "truth-prebuilt",
+ "truth",
],
platform_apis: true,
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 59aefa5..62614c1 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -47,6 +47,7 @@
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
@@ -2723,7 +2724,8 @@
// the network with the TEST transport. Also wait for validation here, in case there
// is a bug that's only visible when the network is validated.
setWifiMeteredStatusAndWait(ssid, true /* isMetered */, true /* waitForValidation */);
- defaultCallback.expect(CallbackEntry.LOST, wifiNetwork, NETWORK_CALLBACK_TIMEOUT_MS);
+ defaultCallback.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
+ l -> l.getNetwork().equals(wifiNetwork));
waitForAvailable(defaultCallback, tnt.getNetwork());
// Depending on if this device has cellular connectivity or not, multiple available
// callbacks may be received. Eventually, metered Wi-Fi should be the final available
@@ -3590,6 +3592,15 @@
}
}
+ private void setUidFirewallRule(final int chain, final int uid, final int rule) {
+ try {
+ mCm.setUidFirewallRule(chain, uid, rule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ }
+
private static final boolean EXPECT_OPEN = false;
private static final boolean EXPECT_CLOSE = true;
@@ -3598,6 +3609,8 @@
runWithShellPermissionIdentity(() -> {
// Firewall chain status will be restored after the test.
final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain);
+ final int myUid = Process.myUid();
+ final int previousMyUidFirewallRule = mCm.getUidFirewallRule(chain, myUid);
final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, targetUid);
final Socket socket = new Socket(TEST_HOST, HTTP_PORT);
socket.setSoTimeout(NETWORK_REQUEST_TIMEOUT_MS);
@@ -3605,12 +3618,12 @@
mCm.setFirewallChainEnabled(chain, false /* enable */);
assertSocketOpen(socket);
- try {
- mCm.setUidFirewallRule(chain, targetUid, rule);
- } catch (IllegalStateException ignored) {
- // Removing match causes an exception when the rule entry for the uid does
- // not exist. But this is fine and can be ignored.
+ setUidFirewallRule(chain, targetUid, rule);
+ if (targetUid != myUid) {
+ // If this test does not set rule on myUid, remove existing rule on myUid
+ setUidFirewallRule(chain, myUid, FIREWALL_RULE_DEFAULT);
}
+
mCm.setFirewallChainEnabled(chain, true /* enable */);
if (expectClose) {
@@ -3623,11 +3636,9 @@
mCm.setFirewallChainEnabled(chain, wasChainEnabled);
}, /* cleanup */ () -> {
// Restore the uid firewall rule status
- try {
- mCm.setUidFirewallRule(chain, targetUid, previousUidFirewallRule);
- } catch (IllegalStateException ignored) {
- // Removing match causes an exception when the rule entry for the uid does
- // not exist. But this is fine and can be ignored.
+ setUidFirewallRule(chain, targetUid, previousUidFirewallRule);
+ if (targetUid != myUid) {
+ setUidFirewallRule(chain, myUid, previousMyUidFirewallRule);
}
}, /* cleanup */ () -> {
socket.close();
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index 805dd65..6b7954a 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -22,6 +22,7 @@
import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
@@ -34,12 +35,14 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Ikev2VpnProfile;
import android.net.IpSecAlgorithm;
@@ -60,11 +63,7 @@
import com.android.internal.util.HexDump;
import com.android.networkstack.apishim.ConstantsShim;
-import com.android.networkstack.apishim.Ikev2VpnProfileBuilderShimImpl;
-import com.android.networkstack.apishim.Ikev2VpnProfileShimImpl;
import com.android.networkstack.apishim.VpnManagerShimImpl;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileBuilderShim;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileShim;
import com.android.networkstack.apishim.common.VpnManagerShim;
import com.android.networkstack.apishim.common.VpnProfileStateShim;
import com.android.testutils.DevSdkIgnoreRule;
@@ -75,6 +74,7 @@
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -203,6 +203,12 @@
mUserCertKey = generateRandomCertAndKeyPair();
}
+ @Before
+ public void setUp() {
+ assumeFalse("Skipping test because watches don't support VPN",
+ sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+ }
+
@After
public void tearDown() {
for (TestableNetworkCallback callback : mCallbacksToUnregister) {
@@ -210,6 +216,15 @@
}
setAppop(AppOpsManager.OP_ACTIVATE_VPN, false);
setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false);
+
+ // Make sure the VpnProfile is not provisioned already.
+ sVpnMgr.stopProvisionedVpnProfile();
+
+ try {
+ sVpnMgr.startProvisionedVpnProfile();
+ fail("Expected SecurityException for missing consent");
+ } catch (SecurityException expected) {
+ }
}
/**
@@ -227,28 +242,25 @@
}
private Ikev2VpnProfile buildIkev2VpnProfileCommon(
- @NonNull Ikev2VpnProfileBuilderShim builderShim, boolean isRestrictedToTestNetworks,
+ @NonNull Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks,
boolean requiresValidation, boolean automaticIpVersionSelectionEnabled,
boolean automaticNattKeepaliveTimerEnabled) throws Exception {
- builderShim.setBypassable(true)
+ builder.setBypassable(true)
.setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
- if (TestUtils.shouldTestTApis()) {
- builderShim.setRequiresInternetValidation(requiresValidation);
+ if (isAtLeastT()) {
+ builder.setRequiresInternetValidation(requiresValidation);
}
- if (TestUtils.shouldTestUApis()) {
- builderShim.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled);
- builderShim.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled);
+ if (isAtLeastU()) {
+ builder.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled);
+ builder.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled);
}
- // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
- // method and is not defined in shims.
// TODO: replace it in alternative way to remove the hidden method usage
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -264,16 +276,14 @@
? IkeSessionTestUtils.IKE_PARAMS_V6 : IkeSessionTestUtils.IKE_PARAMS_V4,
IkeSessionTestUtils.CHILD_PARAMS);
- final Ikev2VpnProfileBuilderShim builderShim =
- Ikev2VpnProfileBuilderShimImpl.newInstance(params)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(params)
.setRequiresInternetValidation(requiresValidation)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
- // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
- // method and is not defined in shims.
+
// TODO: replace it in alternative way to remove the hidden method usage
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -283,8 +293,8 @@
private Ikev2VpnProfile buildIkev2VpnProfilePsk(@NonNull String remote,
boolean isRestrictedToTestNetworks, boolean requiresValidation)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(remote, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
requiresValidation, false /* automaticIpVersionSelectionEnabled */,
@@ -293,8 +303,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */,
@@ -303,8 +313,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthDigitalSignature(
mUserCertKey.cert, mUserCertKey.key, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
@@ -347,7 +357,6 @@
@Test
public void testBuildIkev2VpnProfileWithIkeTunnelConnectionParams() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- assumeTrue(TestUtils.shouldTestTApis());
final IkeTunnelConnectionParams expectedParams = new IkeTunnelConnectionParams(
IkeSessionTestUtils.IKE_PARAMS_V6, IkeSessionTestUtils.CHILD_PARAMS);
@@ -567,7 +576,7 @@
// regardless of its value. However, there is a race in Vpn(see b/228574221) that VPN may
// misuse VPN network itself as the underlying network. The fix is not available without
// SDK > T platform. Thus, verify this only on T+ platform.
- if (!requiresValidation && TestUtils.shouldTestTApis()) {
+ if (!requiresValidation && isAtLeastT()) {
cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, TIMEOUT_MS,
entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
.hasCapability(NET_CAPABILITY_VALIDATED));
@@ -647,7 +656,6 @@
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileV4WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
}
@@ -660,35 +668,30 @@
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileV6WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV4() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV4WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV6() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV6WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@@ -696,7 +699,6 @@
@IgnoreUpTo(SC_V2)
@Test
public void testStartProvisionedVpnV4ProfileSession() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, false /* requiresValidation */,
true /* testSessionKey */, false /* testIkeTunConnParams */);
}
@@ -704,59 +706,44 @@
@IgnoreUpTo(SC_V2)
@Test
public void testStartProvisionedVpnV6ProfileSession() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, false /* requiresValidation */,
true /* testSessionKey */, false /* testIkeTunConnParams */);
}
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
@Test
public void testBuildIkev2VpnProfileWithAutomaticNattKeepaliveTimerEnabled() throws Exception {
- // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
- // 34 shims, and @IgnoreUpTo does not check that.
- assumeTrue(TestUtils.shouldTestUApis());
-
final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
- Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
- assertFalse(shimWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled());
+ assertFalse(profileWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled());
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
false /* isRestrictedToTestNetworks */,
false /* requiresValidation */,
false /* automaticIpVersionSelectionEnabled */,
true /* automaticNattKeepaliveTimerEnabled */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
- Ikev2VpnProfileShimImpl.newInstance(profile);
- assertTrue(shim.isAutomaticNattKeepaliveTimerEnabled());
+ assertTrue(profile.isAutomaticNattKeepaliveTimerEnabled());
}
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
@Test
public void testBuildIkev2VpnProfileWithAutomaticIpVersionSelectionEnabled() throws Exception {
- // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
- // 34 shims, and @IgnoreUpTo does not check that.
- assumeTrue(TestUtils.shouldTestUApis());
-
final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
- Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
- assertFalse(shimWithDefaultValue.isAutomaticIpVersionSelectionEnabled());
+ assertFalse(profileWithDefaultValue.isAutomaticIpVersionSelectionEnabled());
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
false /* isRestrictedToTestNetworks */,
false /* requiresValidation */,
true /* automaticIpVersionSelectionEnabled */,
false /* automaticNattKeepaliveTimerEnabled */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
- Ikev2VpnProfileShimImpl.newInstance(profile);
- assertTrue(shim.isAutomaticIpVersionSelectionEnabled());
+ assertTrue(profile.isAutomaticIpVersionSelectionEnabled());
}
private static class CertificateAndKey {
diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
index 7bccbde..6a019b7 100644
--- a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
@@ -387,6 +387,7 @@
now = System.currentTimeMillis();
}
}
+ mCm.unregisterNetworkCallback(callback);
if (callback.success) {
mNetworkInterfacesToTest[networkTypeIndex].setMetered(callback.metered);
mNetworkInterfacesToTest[networkTypeIndex].setRoaming(callback.roaming);
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
index c2bb7cd..f374181 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
@@ -23,6 +23,7 @@
import android.net.TetheringManager.TetheringRequest
import android.net.nsd.NsdManager
import android.os.Build
+import android.platform.test.annotations.AppModeFull
import androidx.test.filters.SmallTest
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
@@ -41,6 +42,7 @@
@RunWith(DevSdkIgnoreRunner::class)
@SmallTest
@ConnectivityModuleTest
+@AppModeFull(reason = "WifiManager cannot be obtained in instant mode")
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class NsdManagerDownstreamTetheringTest : EthernetTetheringTestBase() {
private val nsdManager by lazy { context.getSystemService(NsdManager::class.java)!! }
diff --git a/tests/cts/net/src/android/net/cts/RateLimitTest.java b/tests/cts/net/src/android/net/cts/RateLimitTest.java
index 5c93738..36b98fc 100644
--- a/tests/cts/net/src/android/net/cts/RateLimitTest.java
+++ b/tests/cts/net/src/android/net/cts/RateLimitTest.java
@@ -36,7 +36,6 @@
import android.icu.text.MessageFormat;
import android.net.ConnectivityManager;
import android.net.ConnectivitySettingsManager;
-import android.net.ConnectivityThread;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -190,19 +189,7 @@
// whatever happens, don't leave the device in rate limited state.
ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond(mContext, -1);
}
- if (mSocket == null) {
- // HACK(b/272147742): dump ConnectivityThread if test initialization failed.
- final StackTraceElement[] elements = ConnectivityThread.get().getStackTrace();
- final StringBuilder sb = new StringBuilder();
- // Skip first element as it includes the invocation of getStackTrace()
- for (int i = 1; i < elements.length; i++) {
- sb.append(elements[i]);
- sb.append("\n");
- }
- Log.e(TAG, sb.toString());
- } else {
- mSocket.close();
- }
+ if (mSocket != null) mSocket.close();
if (mNetworkAgent != null) mNetworkAgent.unregister();
if (mTunInterface != null) mTunInterface.getFileDescriptor().close();
if (mCm != null) mCm.unregisterNetworkCallback(mNetworkCallback);
diff --git a/tests/cts/net/src/android/net/cts/VpnServiceTest.java b/tests/cts/net/src/android/net/cts/VpnServiceTest.java
index 5c7b5ca..f343e83 100644
--- a/tests/cts/net/src/android/net/cts/VpnServiceTest.java
+++ b/tests/cts/net/src/android/net/cts/VpnServiceTest.java
@@ -15,12 +15,28 @@
*/
package android.net.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import android.test.AndroidTestCase;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.net.DatagramSocket;
import java.net.Socket;
@@ -30,12 +46,21 @@
* blocks us from writing tests for positive cases. For now we only test for
* negative cases, and we will try to cover the rest in the future.
*/
-public class VpnServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class VpnServiceTest {
private static final String TAG = VpnServiceTest.class.getSimpleName();
+ private final Context mContext = InstrumentationRegistry.getContext();
private VpnService mVpnService = new VpnService();
+ @Before
+ public void setUp() {
+ assumeFalse("Skipping test because watches don't support VPN",
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+ }
+
+ @Test
@AppModeFull(reason = "PackageManager#queryIntentActivities cannot access in instant app mode")
public void testPrepare() throws Exception {
// Should never return null since we are not prepared.
@@ -47,6 +72,7 @@
assertEquals(1, count);
}
+ @Test
@AppModeFull(reason = "establish() requires prepare(), which requires PackageManager access")
public void testEstablish() throws Exception {
ParcelFileDescriptor descriptor = null;
@@ -63,6 +89,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_DatagramSocket() throws Exception {
DatagramSocket socket = new DatagramSocket();
@@ -78,6 +105,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_Socket() throws Exception {
Socket socket = new Socket();
@@ -93,6 +121,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_int() throws Exception {
DatagramSocket socket = new DatagramSocket();
@@ -114,6 +143,7 @@
}
}
+ @Test
public void testTunDevice() throws Exception {
File file = new File("/dev/tun");
assertTrue(file.exists());
diff --git a/tests/integration/AndroidManifest.xml b/tests/integration/AndroidManifest.xml
index 50f02d3..cea83c7 100644
--- a/tests/integration/AndroidManifest.xml
+++ b/tests/integration/AndroidManifest.xml
@@ -40,6 +40,8 @@
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<!-- Querying the resources package -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <!-- Register UidFrozenStateChangedCallback -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<application android:debuggable="true">
<uses-library android:name="android.test.runner"/>
diff --git a/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
index edd201d..ec09f9e 100644
--- a/tests/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -19,6 +19,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
@@ -123,6 +124,10 @@
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
+ case TRANSPORT_BLUETOOTH:
+ // Score for Wear companion proxy network; not BLUETOOTH tethering.
+ mScore = new NetworkScore.Builder().setLegacyInt(100).build();
+ break;
case TRANSPORT_ETHERNET:
mScore = new NetworkScore.Builder().setLegacyInt(70).build();
break;
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 15263cc..cff4d6f 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -40,6 +40,7 @@
#define TETHERING "/sys/fs/bpf/tethering/"
#define PRIVATE "/sys/fs/bpf/net_private/"
#define SHARED "/sys/fs/bpf/net_shared/"
+#define NETD_RO "/sys/fs/bpf/netd_readonly/"
#define NETD "/sys/fs/bpf/netd_shared/"
class BpfExistenceTest : public ::testing::Test {
@@ -119,9 +120,9 @@
};
// Provided by *current* mainline module for T+ devices with 5.4+ kernels
-static const set<string> MAINLINE_FOR_T_5_4_PLUS = {
- SHARED "prog_block_bind4_block_port",
- SHARED "prog_block_bind6_block_port",
+static const set<string> MAINLINE_FOR_T_4_19_PLUS = {
+ NETD_RO "prog_block_bind4_block_port",
+ NETD_RO "prog_block_bind6_block_port",
};
// Provided by *current* mainline module for T+ devices with 5.15+ kernels
@@ -129,6 +130,16 @@
SHARED "prog_dscpPolicy_schedcls_set_dscp_ether",
};
+// Provided by *current* mainline module for U+ devices
+static const set<string> MAINLINE_FOR_U_PLUS = {
+ NETD "map_netd_packet_trace_enabled_map",
+};
+
+// Provided by *current* mainline module for U+ devices with 5.10+ kernels
+static const set<string> MAINLINE_FOR_U_5_10_PLUS = {
+ NETD "map_netd_packet_trace_ringbuf",
+};
+
static void addAll(set<string>& a, const set<string>& b) {
a.insert(b.begin(), b.end());
}
@@ -166,11 +177,13 @@
// T still only requires Linux Kernel 4.9+.
DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS);
- DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 4, 0), MAINLINE_FOR_T_5_4_PLUS);
+ DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 19, 0), MAINLINE_FOR_T_4_19_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
// U requires Linux Kernel 4.14+, but nothing (as yet) added or removed in U.
if (IsAtLeastU()) ASSERT_TRUE(isAtLeastKernelVersion(4, 14, 0));
+ DO_EXPECT(IsAtLeastU(), MAINLINE_FOR_U_PLUS);
+ DO_EXPECT(IsAtLeastU() && isAtLeastKernelVersion(5, 10, 0), MAINLINE_FOR_U_5_10_PLUS);
// V requires Linux Kernel 4.19+, but nothing (as yet) added or removed in V.
if (IsAtLeastV()) ASSERT_TRUE(isAtLeastKernelVersion(4, 19, 0));
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index 5d4bdf7..2853f31 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -49,6 +49,9 @@
<uses-permission android:name="android.permission.NETWORK_FACTORY" />
<uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
<uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
+ <!-- Workaround for flakes where the launcher package is not found despite the <queries> tag
+ below (b/286550950). -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Declare the intent that the test intends to query. This is necessary for
UiDevice.getLauncherPackageName which is used in NetworkNotificationManagerTest
diff --git a/tests/unit/java/android/net/VpnManagerTest.java b/tests/unit/java/android/net/VpnManagerTest.java
index 532081a..2ab4e45 100644
--- a/tests/unit/java/android/net/VpnManagerTest.java
+++ b/tests/unit/java/android/net/VpnManagerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
@@ -27,11 +28,13 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.test.mock.MockContext;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.MessageUtils;
@@ -47,6 +50,7 @@
@RunWith(DevSdkIgnoreRunner.class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class VpnManagerTest {
+
private static final String PKG_NAME = "fooPackage";
private static final String SESSION_NAME_STRING = "testSession";
@@ -66,6 +70,9 @@
@Before
public void setUp() throws Exception {
+ assumeFalse("Skipping test because watches don't support VPN",
+ InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH));
mMockService = mock(IVpnManager.class);
mVpnManager = new VpnManager(mMockContext, mMockService);
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 2fccdcb..eb03157 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -30,6 +30,7 @@
import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN;
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
@@ -128,6 +129,7 @@
import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_NONE;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
@@ -152,6 +154,7 @@
import static android.system.OsConstants.IPPROTO_TCP;
import static com.android.server.ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION;
+import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION;
import static com.android.server.ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID;
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED;
@@ -250,6 +253,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -1903,6 +1907,7 @@
mServiceContext.setPermission(CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_GRANTED);
mServiceContext.setPermission(PACKET_KEEPALIVE_OFFLOAD, PERMISSION_GRANTED);
mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(READ_DEVICE_CONFIG, PERMISSION_GRANTED);
mAlarmManagerThread = new HandlerThread("TestAlarmManager");
mAlarmManagerThread.start();
@@ -2058,7 +2063,8 @@
@Override
public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
- @NonNull final Context context, @NonNull final TelephonyManager tm) {
+ @NonNull final Context context,
+ @NonNull final TelephonyManager tm) {
return mDeps.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null;
}
@@ -2150,6 +2156,7 @@
public boolean isFeatureEnabled(Context context, String name) {
switch (name) {
case ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER:
+ case ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK:
return true;
case KEY_DESTROY_FROZEN_SOCKETS_VERSION:
return true;
@@ -2404,6 +2411,7 @@
final String myPackageName = mContext.getPackageName();
final PackageInfo myPackageInfo = mContext.getPackageManager().getPackageInfo(
myPackageName, PackageManager.GET_PERMISSIONS);
+ myPackageInfo.setLongVersionCode(9_999_999L);
doReturn(new String[] {myPackageName}).when(mPackageManager)
.getPackagesForUid(Binder.getCallingUid());
doReturn(myPackageInfo).when(mPackageManager).getPackageInfoAsUser(
@@ -2415,6 +2423,13 @@
buildPackageInfo(/* SYSTEM */ false, VPN_UID)
})).when(mPackageManager).getInstalledPackagesAsUser(eq(GET_PERMISSIONS), anyInt());
+ final ModuleInfo moduleInfo = new ModuleInfo();
+ moduleInfo.setPackageName(TETHERING_MODULE_NAME);
+ doReturn(moduleInfo).when(mPackageManager)
+ .getModuleInfo(TETHERING_MODULE_NAME, PackageManager.MODULE_APEX_NAME);
+ doReturn(myPackageInfo).when(mPackageManager)
+ .getPackageInfo(TETHERING_MODULE_NAME, PackageManager.MATCH_APEX);
+
// Create a fake always-on VPN package.
final int userId = UserHandle.getCallingUserId();
final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -4871,6 +4886,34 @@
}
@Test
+ public void testNoAvoidCaptivePortalOnWearProxy() throws Exception {
+ // Bring up a BLUETOOTH network which is companion proxy on wear
+ // then set captive portal.
+ mockHasSystemFeature(PackageManager.FEATURE_WATCH, true);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
+ TestNetworkAgentWrapper btAgent = new TestNetworkAgentWrapper(TRANSPORT_BLUETOOTH);
+ final String firstRedirectUrl = "http://example.com/firstPath";
+
+ btAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */);
+ btAgent.assertNotDisconnected(TIMEOUT_MS);
+ }
+
+ @Test
+ public void testAvoidCaptivePortalOnBluetooth() throws Exception {
+ // When not on Wear, BLUETOOTH is just regular network,
+ // then set captive portal.
+ mockHasSystemFeature(PackageManager.FEATURE_WATCH, false);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
+ TestNetworkAgentWrapper btAgent = new TestNetworkAgentWrapper(TRANSPORT_BLUETOOTH);
+ final String firstRedirectUrl = "http://example.com/firstPath";
+
+ btAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */);
+
+ btAgent.expectDisconnected();
+ btAgent.expectPreventReconnectReceived();
+ }
+
+ @Test
public void testCaptivePortalApi() throws Exception {
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
@@ -10772,6 +10815,8 @@
final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
final RouteInfo stackedDefault =
new RouteInfo((IpPrefix) null, myIpv4.getAddress(), CLAT_MOBILE_IFNAME);
+ final BaseNetdUnsolicitedEventListener netdUnsolicitedListener =
+ getRegisteredNetdUnsolicitedEventListener();
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR)
@@ -10839,7 +10884,6 @@
assertRoutesRemoved(cellNetId, ipv4Subnet);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
- Nat464Xlat clat = getNat464Xlat(mCellAgent);
assertNull(mCm.getLinkProperties(mCellAgent.getNetwork()).getNat64Prefix());
mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
@@ -10850,7 +10894,8 @@
verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
+ netdUnsolicitedListener.onInterfaceLinkStateChanged(
+ CLAT_MOBILE_IFNAME, true);
networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent);
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellAgent.getNetwork())
.getStackedLinks();
@@ -10896,7 +10941,7 @@
kOtherNat64Prefix.toString());
networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
cb -> cb.getLp().getNat64Prefix().equals(kOtherNat64Prefix));
- clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
+ netdUnsolicitedListener.onInterfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
cb -> cb.getLp().getStackedLinks().size() == 1);
assertRoutesAdded(cellNetId, stackedDefault);
@@ -10924,7 +10969,7 @@
assertRoutesRemoved(cellNetId, stackedDefault);
// The interface removed callback happens but has no effect after stop is called.
- clat.interfaceRemoved(CLAT_MOBILE_IFNAME);
+ netdUnsolicitedListener.onInterfaceRemoved(CLAT_MOBILE_IFNAME);
networkCallback.assertNoCallback();
verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME);
@@ -10961,7 +11006,7 @@
verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
+ netdUnsolicitedListener.onInterfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true);
networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
cb -> cb.getLp().getStackedLinks().size() == 1
&& cb.getLp().getNat64Prefix() != null);
@@ -11029,8 +11074,7 @@
// Clatd is started and clat iface comes up. Expect stacked link to be added.
verifyClatdStart(null /* inOrder */, MOBILE_IFNAME, cellNetId, kNat64Prefix.toString());
- clat = getNat464Xlat(mCellAgent);
- clat.interfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true /* up */);
+ netdUnsolicitedListener.onInterfaceLinkStateChanged(CLAT_MOBILE_IFNAME, true /* up */);
networkCallback.expect(LINK_PROPERTIES_CHANGED, mCellAgent,
cb -> cb.getLp().getStackedLinks().size() == 1
&& cb.getLp().getNat64Prefix().equals(kNat64Prefix));
diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
index 3849e49..8113626 100644
--- a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
@@ -20,12 +20,15 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+import static com.android.server.connectivity.ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
@@ -34,9 +37,9 @@
import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.NetworkCapabilities;
@@ -49,14 +52,17 @@
import com.android.networkstack.apishim.TelephonyManagerShimImpl;
import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim;
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
+import com.android.server.ConnectivityService;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import org.mockito.ArgumentCaptor;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@@ -79,11 +85,13 @@
@NonNull private TestCarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
private final int mCarrierConfigPkgUid = 12345;
private final String mTestPkg = "com.android.server.connectivity.test";
+ private final BroadcastReceiver mMultiSimBroadcastReceiver;
public class TestCarrierPrivilegeAuthenticator extends CarrierPrivilegeAuthenticator {
TestCarrierPrivilegeAuthenticator(@NonNull final Context c,
+ @NonNull final ConnectivityService.Dependencies deps,
@NonNull final TelephonyManager t) {
- super(c, t, mTelephonyManagerShim);
+ super(c, deps, t, mTelephonyManagerShim);
}
@Override
protected int getSlotIndex(int subId) {
@@ -92,15 +100,20 @@
}
}
- public CarrierPrivilegeAuthenticatorTest() {
+ /** Parameters to test both using callbacks or the old broadcast */
+ @Parameterized.Parameters
+ public static Collection<Boolean> shouldUseCallbacks() {
+ return Arrays.asList(true, false);
+ }
+
+ public CarrierPrivilegeAuthenticatorTest(final boolean useCallbacks) throws Exception {
mContext = mock(Context.class);
mTelephonyManager = mock(TelephonyManager.class);
mTelephonyManagerShim = mock(TelephonyManagerShimImpl.class);
mPackageManager = mock(PackageManager.class);
- }
-
- @Before
- public void setUp() throws Exception {
+ final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
+ doReturn(useCallbacks).when(deps).isFeatureEnabled(any() /* context */,
+ eq(CARRIER_SERVICE_CHANGED_USE_CALLBACK));
doReturn(SUBSCRIPTION_COUNT).when(mTelephonyManager).getActiveModemCount();
doReturn(mTestPkg).when(mTelephonyManagerShim)
.getCarrierServicePackageNameForLogicalSlot(anyInt());
@@ -109,13 +122,13 @@
applicationInfo.uid = mCarrierConfigPkgUid;
doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(mTestPkg), anyInt());
mCarrierPrivilegeAuthenticator =
- new TestCarrierPrivilegeAuthenticator(mContext, mTelephonyManager);
- }
-
- private IntentFilter getIntentFilter() {
- final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
- return captor.getValue();
+ new TestCarrierPrivilegeAuthenticator(mContext, deps, mTelephonyManager);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(receiverCaptor.capture(), argThat(filter ->
+ filter.getAction(0).equals(ACTION_MULTI_SIM_CONFIG_CHANGED)
+ ), any() /* broadcast permissions */, any() /* handler */);
+ mMultiSimBroadcastReceiver = receiverCaptor.getValue();
}
private Map<Integer, CarrierPrivilegesListenerShim> getCarrierPrivilegesListeners() {
@@ -138,15 +151,6 @@
}
@Test
public void testConstructor() throws Exception {
- verify(mContext).registerReceiver(
- eq(mCarrierPrivilegeAuthenticator),
- any(IntentFilter.class),
- any(),
- any());
- final IntentFilter filter = getIntentFilter();
- assertEquals(1, filter.countActions());
- assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED));
-
// Two listeners originally registered, one for slot 0 and one for slot 1
final Map<Integer, CarrierPrivilegesListenerShim> initialListeners =
getCarrierPrivilegesListeners();
@@ -154,6 +158,8 @@
assertNotNull(initialListeners.get(1));
assertEquals(2, initialListeners.size());
+ initialListeners.get(0).onCarrierServiceChanged(null, mCarrierConfigPkgUid);
+
final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_CELLULAR)
.setNetworkSpecifier(new TelephonyNetworkSpecifier(0));
@@ -174,8 +180,11 @@
assertEquals(2, initialListeners.size());
doReturn(1).when(mTelephonyManager).getActiveModemCount();
- mCarrierPrivilegeAuthenticator.onReceive(
- mContext, buildTestMultiSimConfigBroadcastIntent());
+
+ // This is a little bit cavalier in that the call to onReceive is not on the handler
+ // thread that was specified in registerReceiver.
+ // TODO : capture the handler and call this on it if this causes flakiness.
+ mMultiSimBroadcastReceiver.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent());
// Check all listeners have been removed
for (CarrierPrivilegesListenerShim listener : initialListeners.values()) {
verify(mTelephonyManagerShim).removeCarrierPrivilegesListener(eq(listener));
@@ -187,6 +196,8 @@
assertNotNull(newListeners.get(0));
assertEquals(1, newListeners.size());
+ newListeners.get(0).onCarrierServiceChanged(null, mCarrierConfigPkgUid);
+
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(0);
final NetworkCapabilities nc = new NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_CELLULAR)
@@ -212,6 +223,7 @@
applicationInfo.uid = mCarrierConfigPkgUid + 1;
doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(mTestPkg), anyInt());
listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
+ listener.onCarrierServiceChanged(null, applicationInfo.uid);
assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
mCarrierConfigPkgUid, nc));
@@ -221,6 +233,9 @@
@Test
public void testDefaultSubscription() throws Exception {
+ final CarrierPrivilegesListenerShim listener = getCarrierPrivilegesListeners().get(0);
+ listener.onCarrierServiceChanged(null, mCarrierConfigPkgUid);
+
final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder();
ncBuilder.addTransportType(TRANSPORT_CELLULAR);
assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index 4158663..88044be 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -508,10 +508,10 @@
// Expected mtu is that the detected mtu minus MTU_DELTA(28).
assertEquals(1372, ClatCoordinator.adjustMtu(1400));
assertEquals(1472, ClatCoordinator.adjustMtu(ETHER_MTU));
- assertEquals(65508, ClatCoordinator.adjustMtu(CLAT_MAX_MTU));
+ assertEquals(1500, ClatCoordinator.adjustMtu(CLAT_MAX_MTU));
- // Expected mtu is that CLAT_MAX_MTU(65536) minus MTU_DELTA(28).
- assertEquals(65508, ClatCoordinator.adjustMtu(CLAT_MAX_MTU + 1 /* over maximum mtu */));
+ // Expected mtu is that CLAT_MAX_MTU(1528) minus MTU_DELTA(28).
+ assertEquals(1500, ClatCoordinator.adjustMtu(CLAT_MAX_MTU + 1 /* over maximum mtu */));
}
private void verifyDump(final ClatCoordinator coordinator, boolean clatStarted) {
diff --git a/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
index 58c0114..2fe8713 100644
--- a/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -86,7 +86,6 @@
@Mock ClatCoordinator mClatCoordinator;
TestLooper mLooper;
- Handler mHandler;
NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
Nat464Xlat makeNat464Xlat(boolean isCellular464XlatEnabled) {
@@ -96,6 +95,14 @@
}
};
+ // The test looper needs to be created here on the test case thread and not in setUp,
+ // because setUp and test cases are run in different threads. Creating the test looper in
+ // setUp would make Looper.getThread() return the setUp thread, which does not match the
+ // test case thread that is actually used to process the messages.
+ mLooper = new TestLooper();
+ final Handler handler = new Handler(mLooper.getLooper());
+ doReturn(handler).when(mNai).handler();
+
return new Nat464Xlat(mNai, mNetd, mDnsResolver, deps) {
@Override protected int getNetId() {
return NETID;
@@ -117,9 +124,6 @@
@Before
public void setUp() throws Exception {
- mLooper = new TestLooper();
- mHandler = new Handler(mLooper.getLooper());
-
MockitoAnnotations.initMocks(this);
mNai.linkProperties = new LinkProperties();
@@ -130,7 +134,6 @@
markNetworkConnected();
when(mNai.connService()).thenReturn(mConnectivity);
when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
- when(mNai.handler()).thenReturn(mHandler);
final InterfaceConfigurationParcel mConfig = new InterfaceConfigurationParcel();
when(mNetd.interfaceGetCfg(eq(STACKED_IFACE))).thenReturn(mConfig);
mConfig.ipv4Addr = ADDR.getAddress().getHostAddress();
@@ -272,8 +275,7 @@
verifyClatdStart(null /* inOrder */);
// Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, true);
verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
@@ -294,8 +296,7 @@
// Verify the generated v6 is reset when clat is stopped.
assertNull(nat.mIPv6Address);
// Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
+ nat.handleInterfaceRemoved(STACKED_IFACE);
verifyNoMoreInteractions(mNetd, mConnectivity);
}
@@ -324,8 +325,7 @@
verifyClatdStart(inOrder);
// Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, true);
inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
@@ -344,10 +344,8 @@
if (interfaceRemovedFirst) {
// Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
+ nat.handleInterfaceRemoved(STACKED_IFACE);
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, false);
}
assertTrue(c.getValue().getStackedLinks().isEmpty());
@@ -361,15 +359,12 @@
if (!interfaceRemovedFirst) {
// Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
+ nat.handleInterfaceRemoved(STACKED_IFACE);
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, false);
}
// Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, true);
inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
@@ -411,8 +406,7 @@
verifyClatdStart(null /* inOrder */);
// Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, true);
verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
@@ -421,8 +415,7 @@
assertRunning(nat);
// Stacked interface removed notification arrives (clatd crashed, ...).
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
+ nat.handleInterfaceRemoved(STACKED_IFACE);
verifyClatdStop(null /* inOrder */);
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
@@ -457,12 +450,10 @@
assertIdle(nat);
// In-flight interface up notification arrives: no-op
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
+ nat.handleInterfaceLinkStateChanged(STACKED_IFACE, true);
// Interface removed notification arrives after stopClatd() takes effect: no-op.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
+ nat.handleInterfaceRemoved(STACKED_IFACE);
assertIdle(nat);
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
index 1e3f389..87f7369 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -18,9 +18,12 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL as NET_CAP_PORTAL
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET as NET_CAP_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH as NET_CAP_PRIO_BW
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkScore.KEEP_CONNECTED_NONE
+import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY
import android.net.NetworkScore.POLICY_EXITING as EXITING
import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY as PRIMARY
import android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI as YIELD_TO_BAD_WIFI
@@ -50,8 +53,8 @@
class NetworkRankerTest(private val activelyPreferBadWifi: Boolean) {
private val mRanker = NetworkRanker(NetworkRanker.Configuration(activelyPreferBadWifi))
- private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities)
- : NetworkRanker.Scoreable {
+ private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities) :
+ NetworkRanker.Scoreable {
override fun getScore() = sc
override fun getCapsNoCopy(): NetworkCapabilities = nc
}
@@ -196,4 +199,41 @@
val badExitingWifi = TestScore(score(EVER_EVALUATED, EVER_VALIDATED, EXITING), CAPS_WIFI)
assertEquals(cell, rank(cell, badExitingWifi))
}
+
+ @Test
+ fun testValidatedPolicyStrongerThanSlice() {
+ val unvalidatedNonslice = TestScore(score(EVER_EVALUATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val slice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(slice, rank(slice, unvalidatedNonslice))
+ }
+
+ @Test
+ fun testPrimaryPolicyStrongerThanSlice() {
+ val nonslice = TestScore(score(EVER_EVALUATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val primarySlice = TestScore(score(EVER_EVALUATED, POLICY_TRANSPORT_PRIMARY),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(primarySlice, rank(nonslice, primarySlice))
+ }
+
+ @Test
+ fun testPreferNonSlices() {
+ // Slices lose to non-slices for general ranking
+ val nonslice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val slice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(nonslice, rank(slice, nonslice))
+ }
+
+ @Test
+ fun testSlicePolicyStrongerThanTransport() {
+ val nonSliceCell = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val sliceWifi = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_WIFI, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(nonSliceCell, rank(nonSliceCell, sliceWifi))
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
index c39ee1e..2797462 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
@@ -82,7 +82,8 @@
@Test
fun testAnnounce() {
- val replySender = MdnsReplySender( thread.looper, socket, buffer, sharedLog)
+ val replySender = MdnsReplySender(
+ thread.looper, socket, buffer, sharedLog, true /* enableDebugLog */)
@Suppress("UNCHECKED_CAST")
val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java)
as MdnsPacketRepeater.PacketRepeaterCallback<BaseAnnouncementInfo>
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
index c19747e..a67dc5e 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
@@ -190,8 +190,8 @@
fun testReplyToQuery() {
addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1)
- val mockReply = mock(MdnsRecordRepository.ReplyInfo::class.java)
- doReturn(mockReply).`when`(repository).getReply(any(), any())
+ val testReply = MdnsReplyInfo(emptyList(), emptyList(), 0, InetSocketAddress(0))
+ doReturn(testReply).`when`(repository).getReply(any(), any())
// Query obtained with:
// scapy.raw(scapy.DNS(
@@ -216,7 +216,7 @@
assertContentEquals(arrayOf("_testservice", "_tcp", "local"), it.questions[0].name)
}
- verify(replySender).queueReply(mockReply)
+ verify(replySender).queueReply(testReply)
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt
index b667e5f..28ea4b6 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketTest.kt
@@ -32,7 +32,7 @@
// Probe packet with 1 question for Android.local, and 4 additionalRecords with 4 addresses
// for Android.local (similar to legacy mdnsresponder probes, although it used to put 4
// identical questions(!!) for Android.local when there were 4 addresses).
- val packetHex = "00000000000100000004000007416e64726f6964056c6f63616c0000ff0001c00c000100" +
+ val packetHex = "007b0000000100000004000007416e64726f6964056c6f63616c0000ff0001c00c000100" +
"01000000780004c000027bc00c001c000100000078001020010db8000000000000000000000123c0" +
"0c001c000100000078001020010db8000000000000000000000456c00c001c000100000078001020" +
"010db8000000000000000000000789"
@@ -41,6 +41,7 @@
val reader = MdnsPacketReader(bytes, bytes.size)
val packet = MdnsPacket.parse(reader)
+ assertEquals(123, packet.transactionId)
assertEquals(1, packet.questions.size)
assertEquals(0, packet.answers.size)
assertEquals(4, packet.authorityRecords.size)
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
index f284819..5b7c0ba 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
@@ -119,7 +119,8 @@
@Test
fun testProbe() {
- val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val replySender = MdnsReplySender(
+ thread.looper, socket, buffer, sharedLog, true /* enableDebugLog */)
val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(
listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890)))
@@ -143,7 +144,8 @@
@Test
fun testProbeMultipleRecords() {
- val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val replySender = MdnsReplySender(
+ thread.looper, socket, buffer, sharedLog, true /* enableDebugLog */)
val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(listOf(
makeServiceRecord(TEST_SERVICE_NAME_1, 37890),
@@ -181,7 +183,8 @@
@Test
fun testStopProbing() {
- val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val replySender = MdnsReplySender(
+ thread.looper, socket, buffer, sharedLog, true /* enableDebugLog */)
val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(
listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890)),
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
index 88fb66a..c9b502e 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -105,6 +105,7 @@
assertEquals(TEST_SERVICE_ID_1, probingInfo.serviceId)
val packet = probingInfo.getPacket(0)
+ assertEquals(0, packet.transactionId)
assertEquals(MdnsConstants.FLAGS_QUERY, packet.flags)
assertEquals(0, packet.answers.size)
assertEquals(0, packet.additionalRecords.size)
@@ -173,6 +174,7 @@
assertEquals(1, repository.servicesCount)
val packet = exitAnnouncement.getPacket(0)
+ assertEquals(0, packet.transactionId)
assertEquals(0x8400 /* response, authoritative */, packet.flags)
assertEquals(0, packet.questions.size)
assertEquals(0, packet.authorityRecords.size)
@@ -202,6 +204,7 @@
assertEquals(1, repository.servicesCount)
val packet = exitAnnouncement.getPacket(0)
+ assertEquals(0, packet.transactionId)
assertEquals(0x8400 /* response, authoritative */, packet.flags)
assertEquals(0, packet.questions.size)
assertEquals(0, packet.authorityRecords.size)
@@ -249,6 +252,7 @@
repository.onAdvertisementSent(TEST_SERVICE_ID_1, 2 /* sentPacketCount */)
val packet = announcementInfo.getPacket(0)
+ assertEquals(0, packet.transactionId)
assertEquals(0x8400 /* response, authoritative */, packet.flags)
assertEquals(0, packet.questions.size)
assertEquals(0, packet.authorityRecords.size)
@@ -372,6 +376,7 @@
val serviceName = arrayOf("MyTestService", "_testservice", "_tcp", "local")
val serviceType = arrayOf("_testservice", "_tcp", "local")
val offloadPacket = repository.getOffloadPacket(TEST_SERVICE_ID_1)
+ assertEquals(0, offloadPacket.transactionId)
assertEquals(0x8400, offloadPacket.flags)
assertEquals(0, offloadPacket.questions.size)
assertEquals(0, offloadPacket.additionalRecords.size)
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSBasicMethodsTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSBasicMethodsTest.kt
index 6f8ba6c..58f20a9 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSBasicMethodsTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSBasicMethodsTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
@file:Suppress("DEPRECATION") // This file tests a bunch of deprecated methods : don't warn about it
package com.android.server
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
index 5ae9232..c558586 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server
import android.content.Context
@@ -131,4 +147,8 @@
}
mgr.unregisterNetworkCallback(cb)
}
+
+ fun disconnect() {
+ agent.unregister()
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
index 68613a6..9a1e509 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server
import android.content.BroadcastReceiver
@@ -10,27 +26,25 @@
import android.net.ConnectivityManager
import android.net.INetd
import android.net.InetAddresses
-import android.net.IpPrefix
-import android.net.LinkAddress
import android.net.LinkProperties
import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
-import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
import android.net.NetworkPolicyManager
import android.net.NetworkProvider
import android.net.NetworkScore
import android.net.PacProxyManager
-import android.net.RouteInfo
import android.net.networkstack.NetworkStackClientBase
+import android.os.BatteryStatsManager
import android.os.Handler
import android.os.HandlerThread
import android.os.UserHandle
import android.os.UserManager
import android.telephony.TelephonyManager
import android.testing.TestableContext
+import android.util.ArraySet
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.app.IBatteryStats
import com.android.internal.util.test.BroadcastInterceptingContext
import com.android.modules.utils.build.SdkLevel
import com.android.networkstack.apishim.common.UnsupportedApiLevelException
@@ -41,6 +55,7 @@
import com.android.server.connectivity.MultinetworkPolicyTracker
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies
import com.android.server.connectivity.ProxyTracker
+import com.android.testutils.visibleOnHandlerThread
import com.android.testutils.waitForIdle
import org.mockito.AdditionalAnswers.delegatesTo
import org.mockito.Mockito.doAnswer
@@ -56,6 +71,14 @@
open class FromS<Type>(val value: Type)
+internal const val VERSION_UNMOCKED = -1
+internal const val VERSION_R = 1
+internal const val VERSION_S = 2
+internal const val VERSION_T = 3
+internal const val VERSION_U = 4
+internal const val VERSION_V = 5
+internal const val VERSION_MAX = VERSION_V
+
/**
* Base class for tests testing ConnectivityService and its satellites.
*
@@ -71,7 +94,7 @@
init {
if (!SdkLevel.isAtLeastS()) {
throw UnsupportedApiLevelException("CSTest subclasses must be annotated to only " +
- "run on S+, e.g. @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)");
+ "run on S+, e.g. @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)")
}
}
@@ -107,17 +130,19 @@
val packageManager = makeMockPackageManager()
val connResources = makeMockConnResources(sysResources, packageManager)
+ val netd = mock<INetd>()
val bpfNetMaps = mock<BpfNetMaps>()
val clatCoordinator = mock<ClatCoordinator>()
val proxyTracker = ProxyTracker(context, mock<Handler>(), 16 /* EVENT_PROXY_HAS_CHANGED */)
val alarmManager = makeMockAlarmManager()
val systemConfigManager = makeMockSystemConfigManager()
+ val batteryManager = BatteryStatsManager(mock<IBatteryStats>())
val telephonyManager = mock<TelephonyManager>().also {
doReturn(true).`when`(it).isDataCapable()
}
val deps = CSDeps()
- val service = makeConnectivityService(context, deps).also { it.systemReadyInternal() }
+ val service = makeConnectivityService(context, netd, deps).also { it.systemReadyInternal() }
val cm = ConnectivityManager(context, service)
val csHandler = Handler(csHandlerThread.looper)
@@ -130,8 +155,10 @@
override fun makeHandlerThread() = csHandlerThread
override fun makeProxyTracker(context: Context, connServiceHandler: Handler) = proxyTracker
- override fun makeCarrierPrivilegeAuthenticator(context: Context, tm: TelephonyManager) =
- if (SdkLevel.isAtLeastT()) mock<CarrierPrivilegeAuthenticator>() else null
+ override fun makeCarrierPrivilegeAuthenticator(
+ context: Context,
+ tm: TelephonyManager
+ ) = if (SdkLevel.isAtLeastT()) mock<CarrierPrivilegeAuthenticator>() else null
private inner class AOOKTDeps(c: Context) : AutomaticOnOffKeepaliveTracker.Dependencies(c) {
override fun isTetheringFeatureNotChickenedOut(name: String): Boolean {
@@ -150,6 +177,43 @@
// checking permissions.
override fun isFeatureEnabled(context: Context?, name: String?) =
enabledFeatures[name] ?: fail("Unmocked feature $name, see CSTest.enabledFeatures")
+
+ // Mocked change IDs
+ private val enabledChangeIds = ArraySet<Long>()
+ fun setChangeIdEnabled(enabled: Boolean, changeId: Long) {
+ // enabledChangeIds is read on the handler thread and maybe the test thread, so
+ // make sure both threads see it before continuing.
+ visibleOnHandlerThread(csHandler) {
+ if (enabled) {
+ enabledChangeIds.add(changeId)
+ } else {
+ enabledChangeIds.remove(changeId)
+ }
+ }
+ }
+
+ override fun isChangeEnabled(changeId: Long, pkg: String, user: UserHandle) =
+ changeId in enabledChangeIds
+ override fun isChangeEnabled(changeId: Long, uid: Int) =
+ changeId in enabledChangeIds
+
+ // In AOSP, build version codes can't always distinguish between some versions (e.g. at the
+ // time of this writing U == V). Define custom ones.
+ private var sdkLevel = VERSION_UNMOCKED
+ private val isSdkUnmocked get() = sdkLevel == VERSION_UNMOCKED
+
+ fun setBuildSdk(sdkLevel: Int) {
+ require(sdkLevel <= VERSION_MAX) {
+ "setBuildSdk must not be called with Build.VERSION constants but " +
+ "CsTest.VERSION_* constants"
+ }
+ visibleOnHandlerThread(csHandler) { this.sdkLevel = sdkLevel }
+ }
+
+ override fun isAtLeastS() = if (isSdkUnmocked) super.isAtLeastS() else sdkLevel >= VERSION_S
+ override fun isAtLeastT() = if (isSdkUnmocked) super.isAtLeastT() else sdkLevel >= VERSION_T
+ override fun isAtLeastU() = if (isSdkUnmocked) super.isAtLeastU() else sdkLevel >= VERSION_U
+ override fun isAtLeastV() = if (isSdkUnmocked) super.isAtLeastV() else sdkLevel >= VERSION_V
}
inner class CSContext(base: Context) : BroadcastInterceptingContext(base) {
@@ -196,6 +260,7 @@
Context.ACTIVITY_SERVICE -> activityManager
Context.SYSTEM_CONFIG_SERVICE -> systemConfigManager
Context.TELEPHONY_SERVICE -> telephonyManager
+ Context.BATTERY_STATS_SERVICE -> batteryManager
Context.STATS_MANAGER -> null // Stats manager is final and can't be mocked
else -> super.getSystemService(serviceName)
}
@@ -204,19 +269,6 @@
// Utility methods for subclasses to use
fun waitForIdle() = csHandlerThread.waitForIdle(HANDLER_TIMEOUT_MS)
- private fun emptyAgentConfig() = NetworkAgentConfig.Builder().build()
- private fun defaultNc() = NetworkCapabilities.Builder()
- // Add sensible defaults for agents that don't want to care
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .build()
- private fun defaultScore() = FromS<NetworkScore>(NetworkScore.Builder().build())
- private fun defaultLp() = LinkProperties().apply {
- addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 32))
- addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
- }
-
// Network agents. See CSAgentWrapper. This class contains utility methods to simplify
// creation.
fun Agent(
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTestHelpers.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTestHelpers.kt
index b8f2151..2d8607b 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTestHelpers.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTestHelpers.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
@file:JvmName("CsTestHelpers")
package com.android.server
@@ -14,6 +30,13 @@
import android.content.res.Resources
import android.net.IDnsResolver
import android.net.INetd
+import android.net.IpPrefix
+import android.net.LinkAddress
+import android.net.LinkProperties
+import android.net.NetworkAgentConfig
+import android.net.NetworkCapabilities
+import android.net.NetworkScore
+import android.net.RouteInfo
import android.net.metrics.IpConnectivityLog
import android.os.Handler
import android.os.HandlerThread
@@ -44,6 +67,22 @@
internal inline fun <reified T> mock() = Mockito.mock(T::class.java)
internal inline fun <reified T> any() = any(T::class.java)
+internal fun emptyAgentConfig() = NetworkAgentConfig.Builder().build()
+
+internal fun defaultNc() = NetworkCapabilities.Builder()
+ // Add sensible defaults for agents that don't want to care
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+
+internal fun defaultScore() = FromS(NetworkScore.Builder().build())
+
+internal fun defaultLp() = LinkProperties().apply {
+ addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 32))
+ addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
+}
+
internal fun makeMockContentResolver(context: Context) = MockContentResolver(context).apply {
addProvider(Settings.AUTHORITY, FakeSettingsProvider())
}
@@ -129,12 +168,13 @@
private val TEST_LINGER_DELAY_MS = 400
private val TEST_NASCENT_DELAY_MS = 300
-internal fun makeConnectivityService(context: Context, deps: Dependencies) = ConnectivityService(
- context,
- mock<IDnsResolver>(),
- mock<IpConnectivityLog>(),
- mock<INetd>(),
- deps).also {
- it.mLingerDelayMs = TEST_LINGER_DELAY_MS
- it.mNascentDelayMs = TEST_NASCENT_DELAY_MS
-}
+internal fun makeConnectivityService(context: Context, netd: INetd, deps: Dependencies) =
+ ConnectivityService(
+ context,
+ mock<IDnsResolver>(),
+ mock<IpConnectivityLog>(),
+ netd,
+ deps).also {
+ it.mLingerDelayMs = TEST_LINGER_DELAY_MS
+ it.mNascentDelayMs = TEST_NASCENT_DELAY_MS
+ }
diff --git a/thread/tests/cts/Android.bp b/thread/tests/cts/Android.bp
index 96056c6..278798e 100644
--- a/thread/tests/cts/Android.bp
+++ b/thread/tests/cts/Android.bp
@@ -38,7 +38,7 @@
"compatibility-device-util-axt",
"ctstestrunner-axt",
"net-tests-utils",
- "truth-prebuilt",
+ "truth",
],
libs: [
"android.test.base",