Merge "Fix EthernetTetheringTest flaky"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index f3d6aee..3ab1ec2 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -26,6 +26,21 @@
}
java_defaults {
+ name: "TetheringExternalLibs",
+ // Libraries not including Tethering's own framework-tethering (different flavors of that one
+ // are needed depending on the build rule)
+ libs: [
+ "framework-connectivity.stubs.module_lib",
+ "framework-connectivity-t.stubs.module_lib",
+ "framework-statsd.stubs.module_lib",
+ "framework-wifi",
+ "framework-bluetooth",
+ "unsupportedappusage",
+ ],
+ defaults_visibility: ["//visibility:private"],
+}
+
+java_defaults {
name: "TetheringAndroidLibraryDefaults",
srcs: [
"apishim/**/*.java",
@@ -51,14 +66,9 @@
"netd-client",
"tetheringstatsprotos",
],
+ defaults: ["TetheringExternalLibs"],
libs: [
- "framework-connectivity",
- "framework-connectivity-t.stubs.module_lib",
- "framework-statsd.stubs.module_lib",
"framework-tethering.impl",
- "framework-wifi",
- "framework-bluetooth",
- "unsupportedappusage",
],
plugins: ["java_api_finder"],
manifest: "AndroidManifestBase.xml",
@@ -148,9 +158,17 @@
resource_dirs: [
"res",
],
+ // Libs are not actually needed to build here since build rules using these defaults are just
+ // packaging the TetheringApiXLibs in APKs, but they are necessary so that R8 has the right
+ // references to optimize the code. Without these, there will be missing class warnings and code
+ // may be wrongly optimized.
+ // R8 runs after jarjar, so the framework-X libraries need to be the post-jarjar artifacts
+ // (framework-tethering.impl), if they are not just stubs, so that the name of jarjared
+ // classes match.
+ // TODO(b/229727645): ensure R8 fails the build fully if libraries are missing
+ defaults: ["TetheringExternalLibs"],
libs: [
- "framework-tethering",
- "framework-wifi",
+ "framework-tethering.impl",
],
jarjar_rules: "jarjar-rules.txt",
optimize: {
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index b3f0cf2..cd914d3 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -1273,8 +1273,10 @@
@Override
public int hashCode() {
- return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
- mTetherableWifiRegexs);
+ return Objects.hash(
+ Arrays.hashCode(mTetherableBluetoothRegexs),
+ Arrays.hashCode(mTetherableUsbRegexs),
+ Arrays.hashCode(mTetherableWifiRegexs));
}
@Override
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index ac0bbd4..05a2884 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -64,7 +64,7 @@
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.S32;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.net.module.util.bpf.TetherStatsKey;
@@ -575,7 +575,7 @@
if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream, rule.srcMac,
NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, NetworkStackConstants.ETHER_MTU)) {
mLog.e("Failed to enable upstream IPv6 forwarding from "
- + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
+ + getIfName(downstream) + " to " + getIfName(upstream));
}
}
@@ -616,7 +616,7 @@
if (!mBpfCoordinatorShim.stopUpstreamIpv6Forwarding(downstream, upstream,
rule.srcMac)) {
mLog.e("Failed to disable upstream IPv6 forwarding from "
- + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
+ + getIfName(downstream) + " to " + getIfName(upstream));
}
}
@@ -960,8 +960,12 @@
}
// TODO: make mInterfaceNames accessible to the shim and move this code to there.
- private String getIfName(long ifindex) {
- return mInterfaceNames.get((int) ifindex, Long.toString(ifindex));
+ // This function should only be used for logging/dump purposes.
+ private String getIfName(int ifindex) {
+ // TODO: return something more useful on lookup failure
+ // likely use the 'iface_index_name_map' bpf map and/or if_nametoindex
+ // perhaps should even check that all 3 match if available.
+ return mInterfaceNames.get(ifindex, Integer.toString(ifindex));
}
/**
@@ -1038,8 +1042,8 @@
for (int i = 0; i < mStats.size(); i++) {
final int upstreamIfindex = mStats.keyAt(i);
final ForwardedStats stats = mStats.get(upstreamIfindex);
- pw.println(String.format("%d(%s) - %s", upstreamIfindex, mInterfaceNames.get(
- upstreamIfindex), stats.toString()));
+ pw.println(String.format("%d(%s) - %s", upstreamIfindex, getIfName(upstreamIfindex),
+ stats.toString()));
}
}
private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
@@ -1082,8 +1086,9 @@
for (Ipv6ForwardingRule rule : rules.values()) {
final int upstreamIfindex = rule.upstreamIfindex;
pw.println(String.format("%d(%s) %d(%s) %s [%s] [%s]", upstreamIfindex,
- mInterfaceNames.get(upstreamIfindex), rule.downstreamIfindex,
- downstreamIface, rule.address.getHostAddress(), rule.srcMac, rule.dstMac));
+ getIfName(upstreamIfindex), rule.downstreamIfindex,
+ getIfName(rule.downstreamIfindex), rule.address.getHostAddress(),
+ rule.srcMac, rule.dstMac));
}
pw.decreaseIndent();
}
@@ -1278,18 +1283,18 @@
pw.println("No counter support");
return;
}
- try (BpfMap<U32, U32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
- U32.class, U32.class)) {
+ try (BpfMap<S32, S32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
+ S32.class, S32.class)) {
map.forEach((k, v) -> {
String counterName;
try {
- counterName = sBpfCounterNames[(int) k.val];
+ counterName = sBpfCounterNames[k.val];
} catch (IndexOutOfBoundsException e) {
// Should never happen because this code gets the counter name from the same
// include file as the BPF program that increments the counter.
Log.wtf(TAG, "Unknown tethering counter type " + k.val);
- counterName = Long.toString(k.val);
+ counterName = Integer.toString(k.val);
}
if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
});
@@ -1817,8 +1822,7 @@
// TODO: Perhaps stop the coordinator.
boolean success = updateDataLimit(upstreamIfindex);
if (!success) {
- final String iface = mInterfaceNames.get(upstreamIfindex);
- mLog.e("Setting data limit for " + iface + " failed.");
+ mLog.e("Setting data limit for " + getIfName(upstreamIfindex) + " failed.");
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java b/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
index 4283c1b..997080c 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
@@ -22,10 +22,10 @@
/** The key of BpfMap which is used for mapping interface index. */
public class TetherDevKey extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long ifIndex; // interface index
+ @Field(order = 0, type = Type.S32)
+ public final int ifIndex; // interface index
- public TetherDevKey(final long ifIndex) {
+ public TetherDevKey(final int ifIndex) {
this.ifIndex = ifIndex;
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java b/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
index 1cd99b5..b6e0c73 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
@@ -22,10 +22,10 @@
/** The key of BpfMap which is used for mapping interface index. */
public class TetherDevValue extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long ifIndex; // interface index
+ @Field(order = 0, type = Type.S32)
+ public final int ifIndex; // interface index
- public TetherDevValue(final long ifIndex) {
+ public TetherDevValue(final int ifIndex) {
this.ifIndex = ifIndex;
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
index a08ad4a..e34b3f1 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
@@ -32,8 +32,8 @@
/** The key of BpfMap which is used for bpf offload. */
public class TetherDownstream6Key extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long iif; // The input interface index.
+ @Field(order = 0, type = Type.S32)
+ public final int iif; // The input interface index.
@Field(order = 1, type = Type.EUI48, padding = 2)
public final MacAddress dstMac; // Destination ethernet mac address (zeroed iff rawip ingress).
@@ -41,7 +41,7 @@
@Field(order = 2, type = Type.ByteArray, arraysize = 16)
public final byte[] neigh6; // The destination IPv6 address.
- public TetherDownstream6Key(final long iif, @NonNull final MacAddress dstMac,
+ public TetherDownstream6Key(final int iif, @NonNull final MacAddress dstMac,
final byte[] neigh6) {
Objects.requireNonNull(dstMac);
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java b/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
index bc9bb47..a7e8ccf 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
@@ -22,10 +22,10 @@
/** The key of BpfMap which is used for tethering per-interface limit. */
public class TetherLimitKey extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long ifindex; // upstream interface index
+ @Field(order = 0, type = Type.S32)
+ public final int ifindex; // upstream interface index
- public TetherLimitKey(final long ifindex) {
+ public TetherLimitKey(final int ifindex) {
this.ifindex = ifindex;
}
@@ -43,7 +43,7 @@
@Override
public int hashCode() {
- return Long.hashCode(ifindex);
+ return Integer.hashCode(ifindex);
}
@Override
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 5191bb7..0d1b22e 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -97,6 +97,7 @@
import android.net.TetheringInterface;
import android.net.TetheringManager.TetheringRequest;
import android.net.TetheringRequestParcel;
+import android.net.Uri;
import android.net.ip.IpServer;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiManager;
@@ -343,9 +344,8 @@
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
});
- mSettingsObserver = new SettingsObserver(mHandler);
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(TETHER_FORCE_USB_FUNCTIONS), false, mSettingsObserver);
+ mSettingsObserver = new SettingsObserver(mContext, mHandler);
+ mSettingsObserver.startObserve();
mStateReceiver = new StateReceiver();
@@ -397,18 +397,42 @@
}
private class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
+ private final Uri mForceUsbFunctions;
+ private final Uri mTetherSupported;
+ private final Context mContext;
+
+ SettingsObserver(Context ctx, Handler handler) {
super(handler);
+ mContext = ctx;
+ mForceUsbFunctions = Settings.Global.getUriFor(TETHER_FORCE_USB_FUNCTIONS);
+ mTetherSupported = Settings.Global.getUriFor(Settings.Global.TETHER_SUPPORTED);
+ }
+
+ public void startObserve() {
+ mContext.getContentResolver().registerContentObserver(mForceUsbFunctions, false, this);
+ mContext.getContentResolver().registerContentObserver(mTetherSupported, false, this);
}
@Override
public void onChange(boolean selfChange) {
- mLog.i("OBSERVED Settings change");
- final boolean isUsingNcm = mConfig.isUsingNcm();
- updateConfiguration();
- if (isUsingNcm != mConfig.isUsingNcm()) {
- stopTetheringInternal(TETHERING_USB);
- stopTetheringInternal(TETHERING_NCM);
+ Log.wtf(TAG, "Should never be reached.");
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (mForceUsbFunctions.equals(uri)) {
+ mLog.i("OBSERVED TETHER_FORCE_USB_FUNCTIONS settings change");
+ final boolean isUsingNcm = mConfig.isUsingNcm();
+ updateConfiguration();
+ if (isUsingNcm != mConfig.isUsingNcm()) {
+ stopTetheringInternal(TETHERING_USB);
+ stopTetheringInternal(TETHERING_NCM);
+ }
+ } else if (mTetherSupported.equals(uri)) {
+ mLog.i("OBSERVED TETHER_SUPPORTED settings change");
+ updateSupportedDownstreams(mConfig);
+ } else {
+ mLog.e("Unexpected settings change: " + uri);
}
}
}
@@ -1322,7 +1346,9 @@
}
private void handleUserRestrictionAction() {
- mTetheringRestriction.onUserRestrictionsChanged();
+ if (mTetheringRestriction.onUserRestrictionsChanged()) {
+ updateSupportedDownstreams(mConfig);
+ }
}
private void handleDataSaverChanged() {
@@ -1350,6 +1376,8 @@
return getTetheredIfaces().length > 0;
}
+ // TODO: Refine TetheringTest then remove UserRestrictionActionListener class and handle
+ // onUserRestrictionsChanged inside Tethering#handleUserRestrictionAction directly.
@VisibleForTesting
protected static class UserRestrictionActionListener {
private final UserManager mUserMgr;
@@ -1365,7 +1393,8 @@
mDisallowTethering = false;
}
- public void onUserRestrictionsChanged() {
+ // return whether tethering disallowed is changed.
+ public boolean onUserRestrictionsChanged() {
// getUserRestrictions gets restriction for this process' user, which is the primary
// user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
// user. See UserManager.DISALLOW_CONFIG_TETHERING.
@@ -1376,15 +1405,13 @@
mDisallowTethering = newlyDisallowed;
final boolean tetheringDisallowedChanged = (newlyDisallowed != prevDisallowed);
- if (!tetheringDisallowedChanged) {
- return;
- }
+ if (!tetheringDisallowedChanged) return false;
if (!newlyDisallowed) {
// Clear the restricted notification when user is allowed to have tethering
// function.
mNotificationUpdater.tetheringRestrictionLifted();
- return;
+ return true;
}
if (mTethering.isTetheringActive()) {
@@ -1395,6 +1422,8 @@
// Untether from all downstreams since tethering is disallowed.
mTethering.untetherAll();
}
+
+ return true;
// TODO(b/148139325): send tetheringSupported on restriction change
}
}
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 3b4f46b..880a285 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -24,13 +24,14 @@
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringTester.TestDnsPacket;
import static android.net.TetheringTester.isExpectedIcmpv6Packet;
+import static android.net.TetheringTester.isExpectedUdpDnsPacket;
import static android.net.TetheringTester.isExpectedUdpPacket;
import static android.system.OsConstants.IPPROTO_IP;
import static android.system.OsConstants.IPPROTO_IPV6;
import static android.system.OsConstants.IPPROTO_UDP;
-import static com.android.net.module.util.BpfDump.BASE64_DELIMITER;
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
import static com.android.net.module.util.HexDump.dumpHexString;
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
@@ -65,8 +66,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.VintfRuntimeInfo;
-import android.text.TextUtils;
-import android.util.Base64;
import android.util.Log;
import android.util.Pair;
@@ -76,6 +75,7 @@
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.BpfDump;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.PacketBuilder;
import com.android.net.module.util.Struct;
@@ -83,7 +83,9 @@
import com.android.net.module.util.bpf.Tether4Value;
import com.android.net.module.util.bpf.TetherStatsKey;
import com.android.net.module.util.bpf.TetherStatsValue;
+import com.android.net.module.util.structs.Ipv4Header;
import com.android.net.module.util.structs.Ipv6Header;
+import com.android.net.module.util.structs.UdpHeader;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DeviceInfoUtils;
@@ -106,7 +108,6 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -159,6 +160,8 @@
private static final ByteBuffer TEST_REACHABILITY_PAYLOAD =
ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
+ private static final short DNS_PORT = 53;
+
private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
@@ -168,6 +171,66 @@
private static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x60000000;
private static final short HOP_LIMIT = 0x40;
+ // TODO: use class DnsPacket to build DNS query and reply message once DnsPacket supports
+ // building packet for given arguments.
+ private static final ByteBuffer DNS_QUERY = ByteBuffer.wrap(new byte[] {
+ // scapy.DNS(
+ // id=0xbeef,
+ // qr=0,
+ // qd=scapy.DNSQR(qname="hello.example.com"))
+ //
+ /* Header */
+ (byte) 0xbe, (byte) 0xef, /* Transaction ID: 0xbeef */
+ (byte) 0x01, (byte) 0x00, /* Flags: rd */
+ (byte) 0x00, (byte) 0x01, /* Questions: 1 */
+ (byte) 0x00, (byte) 0x00, /* Answer RRs: 0 */
+ (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
+ (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
+ /* Queries */
+ (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
+ (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
+ (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
+ (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
+ (byte) 0x6f, (byte) 0x6d, (byte) 0x00, /* Name: hello.example.com */
+ (byte) 0x00, (byte) 0x01, /* Type: A */
+ (byte) 0x00, (byte) 0x01 /* Class: IN */
+ });
+
+ private static final byte[] DNS_REPLY = new byte[] {
+ // scapy.DNS(
+ // id=0,
+ // qr=1,
+ // qd=scapy.DNSQR(qname="hello.example.com"),
+ // an=scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4'))
+ //
+ /* Header */
+ (byte) 0x00, (byte) 0x00, /* Transaction ID: 0x0, must be updated by dns query id */
+ (byte) 0x81, (byte) 0x00, /* Flags: qr rd */
+ (byte) 0x00, (byte) 0x01, /* Questions: 1 */
+ (byte) 0x00, (byte) 0x01, /* Answer RRs: 1 */
+ (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
+ (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
+ /* Queries */
+ (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
+ (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
+ (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
+ (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
+ (byte) 0x6f, (byte) 0x6d, (byte) 0x00, /* Name: hello.example.com */
+ (byte) 0x00, (byte) 0x01, /* Type: A */
+ (byte) 0x00, (byte) 0x01, /* Class: IN */
+ /* Answers */
+ (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
+ (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
+ (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
+ (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
+ (byte) 0x6f, (byte) 0x6d, (byte) 0x00, /* Name: hello.example.com */
+ (byte) 0x00, (byte) 0x01, /* Type: A */
+ (byte) 0x00, (byte) 0x01, /* Class: IN */
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, /* Time to live: 0 */
+ (byte) 0x00, (byte) 0x04, /* Data length: 4 */
+ (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04 /* Address: 1.2.3.4 */
+ };
+
private final Context mContext = InstrumentationRegistry.getContext();
private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
@@ -1273,32 +1336,6 @@
runUdp4Test(true /* verifyBpf */);
}
- @Nullable
- private <K extends Struct, V extends Struct> Pair<K, V> parseMapKeyValue(
- Class<K> keyClass, Class<V> valueClass, @NonNull String dumpStr) {
- Log.w(TAG, "Parsing string: " + dumpStr);
-
- String[] keyValueStrs = dumpStr.split(BASE64_DELIMITER);
- if (keyValueStrs.length != 2 /* key + value */) {
- fail("The length is " + keyValueStrs.length + " but expect 2. "
- + "Split string(s): " + TextUtils.join(",", keyValueStrs));
- }
-
- final byte[] keyBytes = Base64.decode(keyValueStrs[0], Base64.DEFAULT);
- Log.d(TAG, "keyBytes: " + dumpHexString(keyBytes));
- final ByteBuffer keyByteBuffer = ByteBuffer.wrap(keyBytes);
- keyByteBuffer.order(ByteOrder.nativeOrder());
- final K k = Struct.parse(keyClass, keyByteBuffer);
-
- final byte[] valueBytes = Base64.decode(keyValueStrs[1], Base64.DEFAULT);
- Log.d(TAG, "valueBytes: " + dumpHexString(valueBytes));
- final ByteBuffer valueByteBuffer = ByteBuffer.wrap(valueBytes);
- valueByteBuffer.order(ByteOrder.nativeOrder());
- final V v = Struct.parse(valueClass, valueByteBuffer);
-
- return new Pair<>(k, v);
- }
-
@NonNull
private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
@@ -1309,7 +1346,8 @@
final HashMap<K, V> map = new HashMap<>();
for (final String line : rawMapStr.split(LINE_DELIMITER)) {
- final Pair<K, V> rule = parseMapKeyValue(keyClass, valueClass, line.trim());
+ final Pair<K, V> rule =
+ BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
map.put(rule.first, rule.second);
}
return map;
@@ -1399,6 +1437,94 @@
runClatUdpTest();
}
+ @NonNull
+ private ByteBuffer buildDnsReplyMessageById(short id) {
+ byte[] replyMessage = Arrays.copyOf(DNS_REPLY, DNS_REPLY.length);
+ // Assign transaction id of reply message pattern with a given DNS transaction id.
+ replyMessage[0] = (byte) ((id >> 8) & 0xff);
+ replyMessage[1] = (byte) (id & 0xff);
+ Log.d(TAG, "Built DNS reply: " + dumpHexString(replyMessage));
+
+ return ByteBuffer.wrap(replyMessage);
+ }
+
+ @NonNull
+ private void sendDownloadPacketDnsV4(@NonNull final Inet4Address srcIp,
+ @NonNull final Inet4Address dstIp, short srcPort, short dstPort, short dnsId,
+ @NonNull final TetheringTester tester) throws Exception {
+ // DNS response transaction id must be copied from DNS query. Used by the requester
+ // to match up replies to outstanding queries. See RFC 1035 section 4.1.1.
+ final ByteBuffer dnsReplyMessage = buildDnsReplyMessageById(dnsId);
+ final ByteBuffer testPacket = buildUdpPacket((InetAddress) srcIp,
+ (InetAddress) dstIp, srcPort, dstPort, dnsReplyMessage);
+
+ tester.verifyDownload(testPacket, p -> {
+ Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
+ return isExpectedUdpDnsPacket(p, true /* hasEther */, true /* isIpv4 */,
+ dnsReplyMessage);
+ });
+ }
+
+ // Send IPv4 UDP DNS packet and return the forwarded DNS packet on upstream.
+ @NonNull
+ private byte[] sendUploadPacketDnsV4(@NonNull final MacAddress srcMac,
+ @NonNull final MacAddress dstMac, @NonNull final Inet4Address srcIp,
+ @NonNull final Inet4Address dstIp, short srcPort, short dstPort,
+ @NonNull final TetheringTester tester) throws Exception {
+ final ByteBuffer testPacket = buildUdpPacket(srcMac, dstMac, srcIp, dstIp,
+ srcPort, dstPort, DNS_QUERY);
+
+ return tester.verifyUpload(testPacket, p -> {
+ Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
+ return isExpectedUdpDnsPacket(p, false /* hasEther */, true /* isIpv4 */,
+ DNS_QUERY);
+ });
+ }
+
+ @Test
+ public void testTetherUdpV4Dns() throws Exception {
+ final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
+ toList(TEST_IP4_DNS));
+ final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
+
+ // TODO: remove the connectivity verification for upstream connected notification race.
+ // See the same reason in runUdp4Test().
+ probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
+
+ // [1] Send DNS query.
+ // tethered device --> downstream --> dnsmasq forwarding --> upstream --> DNS server
+ //
+ // Need to extract DNS transaction id and source port from dnsmasq forwarded DNS query
+ // packet. dnsmasq forwarding creats new query which means UDP source port and DNS
+ // transaction id are changed from original sent DNS query. See forward_query() in
+ // external/dnsmasq/src/forward.c. Note that #TetheringTester.isExpectedUdpDnsPacket
+ // guarantees that |forwardedQueryPacket| is a valid DNS packet. So we can parse it as DNS
+ // packet.
+ final MacAddress srcMac = tethered.macAddr;
+ final MacAddress dstMac = tethered.routerMacAddr;
+ final Inet4Address clientIp = tethered.ipv4Addr;
+ final Inet4Address gatewayIp = tethered.ipv4Gatway;
+ final byte[] forwardedQueryPacket = sendUploadPacketDnsV4(srcMac, dstMac, clientIp,
+ gatewayIp, LOCAL_PORT, DNS_PORT, tester);
+ final ByteBuffer buf = ByteBuffer.wrap(forwardedQueryPacket);
+ Struct.parse(Ipv4Header.class, buf);
+ final UdpHeader udpHeader = Struct.parse(UdpHeader.class, buf);
+ final TestDnsPacket dnsQuery = TestDnsPacket.getTestDnsPacket(buf);
+ assertNotNull(dnsQuery);
+ Log.d(TAG, "Forwarded UDP source port: " + udpHeader.srcPort + ", DNS query id: "
+ + dnsQuery.getHeader().id);
+
+ // [2] Send DNS reply.
+ // DNS server --> upstream --> dnsmasq forwarding --> downstream --> tethered device
+ //
+ // DNS reply transaction id must be copied from DNS query. Used by the requester to match
+ // up replies to outstanding queries. See RFC 1035 section 4.1.1.
+ final Inet4Address remoteIp = (Inet4Address) TEST_IP4_DNS;
+ final Inet4Address tetheringUpstreamIp = (Inet4Address) TEST_IP4_ADDR.getAddress();
+ sendDownloadPacketDnsV4(remoteIp, tetheringUpstreamIp, DNS_PORT,
+ (short) udpHeader.srcPort, (short) dnsQuery.getHeader().id, tester);
+ }
+
private <T> List<T> toList(T... array) {
return Arrays.asList(array);
}
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java
index 4d90d39..9cc2e49 100644
--- a/Tethering/tests/integration/src/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/src/android/net/TetheringTester.java
@@ -20,6 +20,11 @@
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.IPPROTO_UDP;
+import static com.android.net.module.util.DnsPacket.ANSECTION;
+import static com.android.net.module.util.DnsPacket.ARSECTION;
+import static com.android.net.module.util.DnsPacket.NSSECTION;
+import static com.android.net.module.util.DnsPacket.QDSECTION;
+import static com.android.net.module.util.HexDump.dumpHexString;
import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
@@ -41,12 +46,14 @@
import android.net.dhcp.DhcpAckPacket;
import android.net.dhcp.DhcpOfferPacket;
import android.net.dhcp.DhcpPacket;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.net.module.util.DnsPacket;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.EthernetHeader;
@@ -79,7 +86,7 @@
*/
public final class TetheringTester {
private static final String TAG = TetheringTester.class.getSimpleName();
- private static final int PACKET_READ_TIMEOUT_MS = 100;
+ private static final int PACKET_READ_TIMEOUT_MS = 500;
private static final int DHCP_DISCOVER_ATTEMPTS = 10;
private static final int READ_RA_ATTEMPTS = 10;
private static final byte[] DHCP_REQUESTED_PARAMS = new byte[] {
@@ -124,12 +131,14 @@
public final MacAddress macAddr;
public final MacAddress routerMacAddr;
public final Inet4Address ipv4Addr;
+ public final Inet4Address ipv4Gatway;
public final Inet6Address ipv6Addr;
private TetheredDevice(MacAddress mac, boolean hasIpv6) throws Exception {
macAddr = mac;
DhcpResults dhcpResults = runDhcp(macAddr.toByteArray());
ipv4Addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
+ ipv4Gatway = (Inet4Address) dhcpResults.gateway;
routerMacAddr = getRouterMacAddressFromArp(ipv4Addr, macAddr,
dhcpResults.serverAddress);
ipv6Addr = hasIpv6 ? runSlaac(macAddr, routerMacAddr) : null;
@@ -386,8 +395,8 @@
}
}
- public static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
- boolean isIpv4, @NonNull final ByteBuffer payload) {
+ private static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
+ boolean isIpv4, Predicate<ByteBuffer> payloadVerifier) {
final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
try {
if (hasEth && !hasExpectedEtherHeader(buf, isIpv4)) return false;
@@ -395,15 +404,178 @@
if (!hasExpectedIpHeader(buf, isIpv4, IPPROTO_UDP)) return false;
if (Struct.parse(UdpHeader.class, buf) == null) return false;
+
+ if (!payloadVerifier.test(buf)) return false;
} catch (Exception e) {
// Parsing packet fail means it is not udp packet.
return false;
}
+ return true;
+ }
- if (buf.remaining() != payload.limit()) return false;
+ // Returns remaining bytes in the ByteBuffer in a new byte array of the right size. The
+ // ByteBuffer will be empty upon return. Used to avoid lint warning.
+ // See https://errorprone.info/bugpattern/ByteBufferBackingArray
+ private static byte[] getRemaining(final ByteBuffer buf) {
+ final byte[] bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ Log.d(TAG, "Get remaining bytes: " + dumpHexString(bytes));
+ return bytes;
+ }
- return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
- payload.array());
+ // |expectedPayload| is copied as read-only because the caller may reuse it.
+ public static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
+ boolean isIpv4, @NonNull final ByteBuffer expectedPayload) {
+ return isExpectedUdpPacket(rawPacket, hasEth, isIpv4, p -> {
+ if (p.remaining() != expectedPayload.limit()) return false;
+
+ return Arrays.equals(getRemaining(p), getRemaining(
+ expectedPayload.asReadOnlyBuffer()));
+ });
+ }
+
+ // |expectedPayload| is copied as read-only because the caller may reuse it.
+ // See hasExpectedDnsMessage.
+ public static boolean isExpectedUdpDnsPacket(@NonNull final byte[] rawPacket, boolean hasEth,
+ boolean isIpv4, @NonNull final ByteBuffer expectedPayload) {
+ return isExpectedUdpPacket(rawPacket, hasEth, isIpv4, p -> {
+ return hasExpectedDnsMessage(p, expectedPayload);
+ });
+ }
+
+ public static class TestDnsPacket extends DnsPacket {
+ TestDnsPacket(byte[] data) throws DnsPacket.ParseException {
+ super(data);
+ }
+
+ @Nullable
+ public static TestDnsPacket getTestDnsPacket(final ByteBuffer buf) {
+ try {
+ // The ByteBuffer will be empty upon return.
+ return new TestDnsPacket(getRemaining(buf));
+ } catch (DnsPacket.ParseException e) {
+ return null;
+ }
+ }
+
+ public DnsHeader getHeader() {
+ return mHeader;
+ }
+
+ public List<DnsRecord> getRecordList(int secType) {
+ return mRecords[secType];
+ }
+
+ public int getANCount() {
+ return mHeader.getRecordCount(ANSECTION);
+ }
+
+ public int getQDCount() {
+ return mHeader.getRecordCount(QDSECTION);
+ }
+
+ public int getNSCount() {
+ return mHeader.getRecordCount(NSSECTION);
+ }
+
+ public int getARCount() {
+ return mHeader.getRecordCount(ARSECTION);
+ }
+
+ private boolean isRecordsEquals(int type, @NonNull final TestDnsPacket other) {
+ List<DnsRecord> records = getRecordList(type);
+ List<DnsRecord> otherRecords = other.getRecordList(type);
+
+ if (records.size() != otherRecords.size()) return false;
+
+ // Expect that two compared resource records are in the same order. For current tests
+ // in EthernetTetheringTest, it is okay because dnsmasq doesn't reorder the forwarded
+ // resource records.
+ // TODO: consider allowing that compare records out of order.
+ for (int i = 0; i < records.size(); i++) {
+ // TODO: use DnsRecord.equals once aosp/1387135 is merged.
+ if (!TextUtils.equals(records.get(i).dName, otherRecords.get(i).dName)
+ || records.get(i).nsType != otherRecords.get(i).nsType
+ || records.get(i).nsClass != otherRecords.get(i).nsClass
+ || records.get(i).ttl != otherRecords.get(i).ttl
+ || !Arrays.equals(records.get(i).getRR(), otherRecords.get(i).getRR())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isQDRecordsEquals(@NonNull final TestDnsPacket other) {
+ return isRecordsEquals(QDSECTION, other);
+ }
+
+ public boolean isANRecordsEquals(@NonNull final TestDnsPacket other) {
+ return isRecordsEquals(ANSECTION, other);
+ }
+ }
+
+ // The ByteBuffer |actual| will be empty upon return. The ByteBuffer |excepted| will be copied
+ // as read-only because the caller may reuse it.
+ private static boolean hasExpectedDnsMessage(@NonNull final ByteBuffer actual,
+ @NonNull final ByteBuffer excepted) {
+ // Forwarded DNS message is extracted from remaining received packet buffer which has
+ // already parsed ethernet header, if any, IP header and UDP header.
+ final TestDnsPacket forwardedDns = TestDnsPacket.getTestDnsPacket(actual);
+ if (forwardedDns == null) return false;
+
+ // Original DNS message is the payload of the sending test UDP packet. It is used to check
+ // that the forwarded DNS query and reply have corresponding contents.
+ final TestDnsPacket originalDns = TestDnsPacket.getTestDnsPacket(
+ excepted.asReadOnlyBuffer());
+ assertNotNull(originalDns);
+
+ // Compare original DNS message which is sent to dnsmasq and forwarded DNS message which
+ // is forwarded by dnsmasq. The original message and forwarded message may be not identical
+ // because dnsmasq may change the header flags or even recreate the DNS query message and
+ // so on. We only simple check on forwarded packet and monitor if test will be broken by
+ // vendor dnsmasq customization. See forward_query() in external/dnsmasq/src/forward.c.
+ //
+ // DNS message format. See rfc1035 section 4.1.
+ // +---------------------+
+ // | Header |
+ // +---------------------+
+ // | Question | the question for the name server
+ // +---------------------+
+ // | Answer | RRs answering the question
+ // +---------------------+
+ // | Authority | RRs pointing toward an authority
+ // +---------------------+
+ // | Additional | RRs holding additional information
+ // +---------------------+
+
+ // [1] Header section. See rfc1035 section 4.1.1.
+ // Verify QR flag bit, QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT.
+ if (originalDns.getHeader().isResponse() != forwardedDns.getHeader().isResponse()) {
+ return false;
+ }
+ if (originalDns.getQDCount() != forwardedDns.getQDCount()) return false;
+ if (originalDns.getANCount() != forwardedDns.getANCount()) return false;
+ if (originalDns.getNSCount() != forwardedDns.getNSCount()) return false;
+ if (originalDns.getARCount() != forwardedDns.getARCount()) return false;
+
+ // [2] Question section. See rfc1035 section 4.1.2.
+ // Question section has at least one entry either DNS query or DNS reply.
+ if (forwardedDns.getRecordList(QDSECTION).isEmpty()) return false;
+ // Expect that original and forwarded message have the same question records (usually 1).
+ if (!originalDns.isQDRecordsEquals(forwardedDns)) return false;
+
+ // [3] Answer section. See rfc1035 section 4.1.3.
+ if (forwardedDns.getHeader().isResponse()) {
+ // DNS reply has at least have one answer in our tests.
+ // See EthernetTetheringTest#testTetherUdpV4Dns.
+ if (forwardedDns.getRecordList(ANSECTION).isEmpty()) return false;
+ // Expect that original and forwarded message have the same answer records.
+ if (!originalDns.isANRecordsEquals(forwardedDns)) return false;
+ }
+
+ // Ignore checking {Authority, Additional} sections because they are not tested
+ // in EthernetTetheringTest.
+ return true;
}
private void sendUploadPacket(ByteBuffer packet) throws Exception {
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 536ab2d..0e8b044 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -98,7 +98,7 @@
assertTrue(mTestMap.isEmpty());
}
- private TetherDownstream6Key createTetherDownstream6Key(long iif, String mac,
+ private TetherDownstream6Key createTetherDownstream6Key(int iif, String mac,
String address) throws Exception {
final MacAddress dstMac = MacAddress.fromString(mac);
final InetAddress ipv6Address = InetAddress.getByName(address);
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 63bb731..b100f58 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -222,7 +222,7 @@
private static class TestUpstream4Key {
public static class Builder {
- private long mIif = DOWNSTREAM_IFINDEX;
+ private int mIif = DOWNSTREAM_IFINDEX;
private MacAddress mDstMac = DOWNSTREAM_MAC;
private short mL4proto = (short) IPPROTO_TCP;
private byte[] mSrc4 = PRIVATE_ADDR.getAddress();
@@ -246,7 +246,7 @@
private static class TestDownstream4Key {
public static class Builder {
- private long mIif = UPSTREAM_IFINDEX;
+ private int mIif = UPSTREAM_IFINDEX;
private MacAddress mDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
private short mL4proto = (short) IPPROTO_TCP;
private byte[] mSrc4 = REMOTE_ADDR.getAddress();
@@ -270,7 +270,7 @@
private static class TestUpstream4Value {
public static class Builder {
- private long mOif = UPSTREAM_IFINDEX;
+ private int mOif = UPSTREAM_IFINDEX;
private MacAddress mEthDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
private MacAddress mEthSrcMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
private int mEthProto = ETH_P_IP;
@@ -290,7 +290,7 @@
private static class TestDownstream4Value {
public static class Builder {
- private long mOif = DOWNSTREAM_IFINDEX;
+ private int mOif = DOWNSTREAM_IFINDEX;
private MacAddress mEthDstMac = MAC_A /* client mac */;
private MacAddress mEthSrcMac = DOWNSTREAM_MAC;
private int mEthProto = ETH_P_IP;
@@ -941,11 +941,11 @@
@Test
public void testRuleMakeTetherDownstream6Key() throws Exception {
- final Integer mobileIfIndex = 100;
+ final int mobileIfIndex = 100;
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
final TetherDownstream6Key key = rule.makeTetherDownstream6Key();
- assertEquals(key.iif, (long) mobileIfIndex);
+ assertEquals(key.iif, mobileIfIndex);
assertEquals(key.dstMac, MacAddress.ALL_ZEROS_ADDRESS); // rawip upstream
assertTrue(Arrays.equals(key.neigh6, NEIGH_A.getAddress()));
// iif (4) + dstMac(6) + padding(2) + neigh6 (16) = 28.
@@ -954,7 +954,7 @@
@Test
public void testRuleMakeTether6Value() throws Exception {
- final Integer mobileIfIndex = 100;
+ final int mobileIfIndex = 100;
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
final Tether6Value value = rule.makeTether6Value();
@@ -974,7 +974,7 @@
final BpfCoordinator coordinator = makeBpfCoordinator();
final String mobileIface = "rmnet_data0";
- final Integer mobileIfIndex = 100;
+ final int mobileIfIndex = 100;
coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
// [1] Default limit.
@@ -1018,7 +1018,7 @@
final BpfCoordinator coordinator = makeBpfCoordinator();
final String mobileIface = "rmnet_data0";
- final Integer mobileIfIndex = 100;
+ final int mobileIfIndex = 100;
coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
// Applying a data limit to the current upstream does not take any immediate action.
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 66ad167..a36d67f 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -2899,9 +2899,13 @@
}
private void forceUsbTetheringUse(final int function) {
- Settings.Global.putInt(mContentResolver, TETHER_FORCE_USB_FUNCTIONS, function);
+ setSetting(TETHER_FORCE_USB_FUNCTIONS, function);
+ }
+
+ private void setSetting(final String key, final int value) {
+ Settings.Global.putInt(mContentResolver, key, value);
final ContentObserver observer = mTethering.getSettingsObserverForTest();
- observer.onChange(false /* selfChange */);
+ observer.onChange(false /* selfChange */, Settings.Global.getUriFor(key));
mLooper.dispatchAll();
}
@@ -2957,74 +2961,86 @@
TETHERING_WIFI_P2P, TETHERING_BLUETOOTH, TETHERING_ETHERNET });
}
+ private void setUserRestricted(boolean restricted) {
+ final Bundle restrictions = new Bundle();
+ restrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, restricted);
+ when(mUserManager.getUserRestrictions()).thenReturn(restrictions);
+ when(mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(restricted);
+
+ final Intent intent = new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
+ mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mLooper.dispatchAll();
+ }
+
@Test
public void testTetheringSupported() throws Exception {
final ArraySet<Integer> expectedTypes = getAllSupportedTetheringTypes();
// Check tethering is supported after initialization.
- setTetheringSupported(true /* supported */);
TestTetheringEventCallback callback = new TestTetheringEventCallback();
mTethering.registerTetheringEventCallback(callback);
mLooper.dispatchAll();
- updateConfigAndVerifySupported(callback, expectedTypes);
+ verifySupported(callback, expectedTypes);
- // Could disable tethering supported by settings.
- Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0);
- updateConfigAndVerifySupported(callback, new ArraySet<>());
+ // Could change tethering supported by settings.
+ setSetting(Settings.Global.TETHER_SUPPORTED, 0);
+ verifySupported(callback, new ArraySet<>());
+ setSetting(Settings.Global.TETHER_SUPPORTED, 1);
+ verifySupported(callback, expectedTypes);
- // Could disable tethering supported by user restriction.
- setTetheringSupported(true /* supported */);
- updateConfigAndVerifySupported(callback, expectedTypes);
- when(mUserManager.hasUserRestriction(
- UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true);
- updateConfigAndVerifySupported(callback, new ArraySet<>());
+ // Could change tethering supported by user restriction.
+ setUserRestricted(true /* restricted */);
+ verifySupported(callback, new ArraySet<>());
+ setUserRestricted(false /* restricted */);
+ verifySupported(callback, expectedTypes);
- // Tethering is supported if it has any supported downstream.
- setTetheringSupported(true /* supported */);
- updateConfigAndVerifySupported(callback, expectedTypes);
// Usb tethering is not supported:
expectedTypes.remove(TETHERING_USB);
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, expectedTypes);
// Wifi tethering is not supported:
expectedTypes.remove(TETHERING_WIFI);
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, expectedTypes);
// Bluetooth tethering is not supported:
expectedTypes.remove(TETHERING_BLUETOOTH);
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
.thenReturn(new String[0]);
if (isAtLeastT()) {
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, expectedTypes);
// P2p tethering is not supported:
expectedTypes.remove(TETHERING_WIFI_P2P);
when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, expectedTypes);
// Ncm tethering is not supported:
expectedTypes.remove(TETHERING_NCM);
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, expectedTypes);
// Ethernet tethering (last supported type) is not supported:
expectedTypes.remove(TETHERING_ETHERNET);
mForceEthernetServiceUnavailable = true;
- updateConfigAndVerifySupported(callback, new ArraySet<>());
-
+ sendConfigurationChanged();
+ verifySupported(callback, new ArraySet<>());
} else {
// If wifi, usb and bluetooth are all not supported, all the types are not supported.
- expectedTypes.clear();
- updateConfigAndVerifySupported(callback, expectedTypes);
+ sendConfigurationChanged();
+ verifySupported(callback, new ArraySet<>());
}
}
- private void updateConfigAndVerifySupported(final TestTetheringEventCallback callback,
+ private void verifySupported(final TestTetheringEventCallback callback,
final ArraySet<Integer> expectedTypes) {
- sendConfigurationChanged();
-
assertEquals(expectedTypes.size() > 0, mTethering.isTetheringSupported());
callback.expectSupportedTetheringTypes(expectedTypes);
}
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index 3e4456f..72f63c6 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -62,8 +62,8 @@
uint8_t protocol = 0; // TODO: Use are reserved value? Or int (-1) and cast to uint below?
struct in6_addr src_ip = {};
struct in6_addr dst_ip = {};
- uint8_t tos = 0; // Only used for IPv4
- uint32_t old_first_u32 = 0; // Only used for IPv6
+ uint8_t tos = 0; // Only used for IPv4
+ __be32 old_first_be32 = 0; // Only used for IPv6
if (ipv4) {
const struct iphdr* const iph = (void*)(eth + 1);
hdr_size = l2_header_size + sizeof(struct iphdr);
@@ -96,7 +96,7 @@
src_ip = ip6h->saddr;
dst_ip = ip6h->daddr;
protocol = ip6h->nexthdr;
- old_first_u32 = *(uint32_t*)ip6h;
+ old_first_be32 = *(__be32*)ip6h;
}
switch (protocol) {
@@ -135,9 +135,9 @@
sizeof(uint16_t));
bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &newTos, sizeof(newTos), 0);
} else {
- uint32_t new_first_u32 =
- htonl(ntohl(old_first_u32) & 0xF03FFFFF | (existing_rule->dscp_val << 22));
- bpf_skb_store_bytes(skb, l2_header_size, &new_first_u32, sizeof(uint32_t),
+ __be32 new_first_be32 =
+ htonl(ntohl(old_first_be32) & 0xF03FFFFF | (existing_rule->dscp_val << 22));
+ bpf_skb_store_bytes(skb, l2_header_size, &new_first_be32, sizeof(__be32),
BPF_F_RECOMPUTE_CSUM);
}
return;
@@ -214,8 +214,8 @@
bpf_l3_csum_replace(skb, IP4_OFFSET(check, l2_header_size), htons(tos), htons(new_tos), 2);
bpf_skb_store_bytes(skb, IP4_OFFSET(tos, l2_header_size), &new_tos, sizeof(new_tos), 0);
} else {
- uint32_t new_first_u32 = htonl(ntohl(old_first_u32) & 0xF03FFFFF | (new_dscp << 22));
- bpf_skb_store_bytes(skb, l2_header_size, &new_first_u32, sizeof(uint32_t),
+ __be32 new_first_be32 = htonl(ntohl(old_first_be32) & 0xF03FFFFF | (new_dscp << 22));
+ bpf_skb_store_bytes(skb, l2_header_size, &new_first_be32, sizeof(__be32),
BPF_F_RECOMPUTE_CSUM);
}
return;
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Key.java b/common/src/com/android/net/module/util/bpf/Tether4Key.java
index 638576f..8273e6a 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Key.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Key.java
@@ -30,8 +30,8 @@
/** Key type for downstream & upstream IPv4 forwarding maps. */
public class Tether4Key extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long iif;
+ @Field(order = 0, type = Type.S32)
+ public final int iif;
@Field(order = 1, type = Type.EUI48)
public final MacAddress dstMac;
@@ -51,7 +51,7 @@
@Field(order = 6, type = Type.UBE16)
public final int dstPort;
- public Tether4Key(final long iif, @NonNull final MacAddress dstMac, final short l4proto,
+ public Tether4Key(final int iif, @NonNull final MacAddress dstMac, final short l4proto,
final byte[] src4, final byte[] dst4, final int srcPort,
final int dstPort) {
Objects.requireNonNull(dstMac);
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Value.java b/common/src/com/android/net/module/util/bpf/Tether4Value.java
index de98766..74fdda2 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Value.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Value.java
@@ -30,8 +30,8 @@
/** Value type for downstream & upstream IPv4 forwarding maps. */
public class Tether4Value extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long oif;
+ @Field(order = 0, type = Type.S32)
+ public final int oif;
// The ethhdr struct which is defined in uapi/linux/if_ether.h
@Field(order = 1, type = Type.EUI48)
@@ -60,7 +60,7 @@
@Field(order = 9, type = Type.U63)
public final long lastUsed;
- public Tether4Value(final long oif, @NonNull final MacAddress ethDstMac,
+ public Tether4Value(final int oif, @NonNull final MacAddress ethDstMac,
@NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu,
final byte[] src46, final byte[] dst46, final int srcPort,
final int dstPort, final long lastUsed) {
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 8818460..1226eea 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -295,6 +295,13 @@
if (DBG) Log.d(TAG, "Discover services");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in discovery");
+ break;
+ }
if (requestLimitReached(clientInfo)) {
clientInfo.onDiscoverServicesFailed(
@@ -321,6 +328,13 @@
if (DBG) Log.d(TAG, "Stop service discovery");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in stop discovery");
+ break;
+ }
try {
id = clientInfo.mClientIds.get(clientId);
@@ -341,6 +355,14 @@
if (DBG) Log.d(TAG, "Register service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in registration");
+ break;
+ }
+
if (requestLimitReached(clientInfo)) {
clientInfo.onRegisterServiceFailed(
clientId, NsdManager.FAILURE_MAX_LIMIT);
@@ -363,6 +385,9 @@
if (DBG) Log.d(TAG, "unregister service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
if (clientInfo == null) {
Log.e(TAG, "Unknown connector in unregistration");
break;
@@ -380,6 +405,13 @@
if (DBG) Log.d(TAG, "Resolve service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in resolution");
+ break;
+ }
if (clientInfo.mResolvedService != null) {
clientInfo.onResolveServiceFailed(
diff --git a/service-t/src/com/android/server/ethernet/EthernetCallback.java b/service-t/src/com/android/server/ethernet/EthernetCallback.java
new file mode 100644
index 0000000..5461156
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetCallback.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.ethernet;
+
+import android.net.EthernetNetworkManagementException;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/** Convenience wrapper for INetworkInterfaceOutcomeReceiver */
+@VisibleForTesting
+public class EthernetCallback {
+ private static final String TAG = EthernetCallback.class.getSimpleName();
+ private final INetworkInterfaceOutcomeReceiver mReceiver;
+
+ public EthernetCallback(INetworkInterfaceOutcomeReceiver receiver) {
+ mReceiver = receiver;
+ }
+
+ /** Calls INetworkInterfaceOutcomeReceiver#onResult */
+ public void onResult(String ifname) {
+ try {
+ if (mReceiver != null) {
+ mReceiver.onResult(ifname);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to report error to OutcomeReceiver", e);
+ }
+ }
+
+ /** Calls INetworkInterfaceOutcomeReceiver#onError */
+ public void onError(String msg) {
+ try {
+ if (mReceiver != null) {
+ mReceiver.onError(new EthernetNetworkManagementException(msg));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to report error to OutcomeReceiver", e);
+ }
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
index e5bddf6..56c21eb 100644
--- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -22,9 +22,7 @@
import android.net.ConnectivityManager;
import android.net.ConnectivityResources;
import android.net.EthernetManager;
-import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkSpecifier;
-import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
@@ -42,7 +40,6 @@
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
-import android.os.RemoteException;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArraySet;
@@ -190,22 +187,19 @@
* {@code null} is passed, then the network's current
* {@link NetworkCapabilities} will be used in support of existing APIs as
* the public API does not allow this.
- * @param listener an optional {@link INetworkInterfaceOutcomeReceiver} to notify callers of
- * completion.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
protected void updateInterface(@NonNull final String ifaceName,
@Nullable final IpConfiguration ipConfig,
- @Nullable final NetworkCapabilities capabilities,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ @Nullable final NetworkCapabilities capabilities) {
if (!hasInterface(ifaceName)) {
- maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener);
return;
}
final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
- iface.updateInterface(ipConfig, capabilities, listener);
+ iface.updateInterface(ipConfig, capabilities);
mTrackingInterfaces.put(ifaceName, iface);
+ return;
}
private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc,
@@ -238,10 +232,8 @@
/** Returns true if state has been modified */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up) {
if (!hasInterface(ifaceName)) {
- maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener);
return false;
}
@@ -250,14 +242,7 @@
}
NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
- return iface.updateLinkState(up, listener);
- }
-
- private void maybeSendNetworkManagementCallbackForUntracked(
- String ifaceName, INetworkInterfaceOutcomeReceiver listener) {
- maybeSendNetworkManagementCallback(listener, null,
- new EthernetNetworkManagementException(
- ifaceName + " can't be updated as it is not available."));
+ return iface.updateLinkState(up);
}
@VisibleForTesting
@@ -265,25 +250,6 @@
return mTrackingInterfaces.containsKey(ifaceName);
}
- private static void maybeSendNetworkManagementCallback(
- @Nullable final INetworkInterfaceOutcomeReceiver listener,
- @Nullable final String iface,
- @Nullable final EthernetNetworkManagementException e) {
- if (null == listener) {
- return;
- }
-
- try {
- if (iface != null) {
- listener.onResult(iface);
- } else {
- listener.onError(e);
- }
- } catch (RemoteException re) {
- Log.e(TAG, "Can't send onComplete for network management callback", re);
- }
- }
-
@VisibleForTesting
static class NetworkInterfaceState {
final String name;
@@ -332,11 +298,6 @@
private class EthernetIpClientCallback extends IpClientCallbacks {
private final ConditionVariable mIpClientStartCv = new ConditionVariable(false);
private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false);
- @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener;
-
- EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
- mNetworkManagementListener = listener;
- }
@Override
public void onIpClientCreated(IIpClient ipClient) {
@@ -372,14 +333,14 @@
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
- handleIpEvent(() -> onIpLayerStarted(newLp, mNetworkManagementListener));
+ handleIpEvent(() -> onIpLayerStarted(newLp));
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
// This cannot happen due to provisioning timeout, because our timeout is 0. It can
// happen due to errors while provisioning or on provisioning loss.
- handleIpEvent(() -> onIpLayerStopped(mNetworkManagementListener));
+ handleIpEvent(() -> onIpLayerStopped());
}
@Override
@@ -491,13 +452,11 @@
}
void updateInterface(@Nullable final IpConfiguration ipConfig,
- @Nullable final NetworkCapabilities capabilities,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ @Nullable final NetworkCapabilities capabilities) {
if (DBG) {
Log.d(TAG, "updateInterface, iface: " + name
+ ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig
+ ", capabilities: " + capabilities + ", old capabilities: " + mCapabilities
- + ", listener: " + listener
);
}
@@ -510,7 +469,7 @@
// TODO: Update this logic to only do a restart if required. Although a restart may
// be required due to the capabilities or ipConfiguration values, not all
// capabilities changes require a restart.
- restart(listener);
+ restart();
}
boolean isRestricted() {
@@ -518,10 +477,6 @@
}
private void start() {
- start(null);
- }
-
- private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
if (mIpClient != null) {
if (DBG) Log.d(TAG, "IpClient already started");
return;
@@ -530,7 +485,7 @@
Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name));
}
- mIpClientCallback = new EthernetIpClientCallback(listener);
+ mIpClientCallback = new EthernetIpClientCallback();
mDeps.makeIpClient(mContext, name, mIpClientCallback);
mIpClientCallback.awaitIpClientStart();
@@ -540,8 +495,7 @@
provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
}
- void onIpLayerStarted(@NonNull final LinkProperties linkProperties,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ void onIpLayerStarted(@NonNull final LinkProperties linkProperties) {
if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
stop();
@@ -573,40 +527,18 @@
});
mNetworkAgent.register();
mNetworkAgent.markConnected();
- realizeNetworkManagementCallback(name, null);
}
- void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ void onIpLayerStopped() {
// There is no point in continuing if the interface is gone as stop() will be triggered
// by removeInterface() when processed on the handler thread and start() won't
// work for a non-existent interface.
if (null == mDeps.getNetworkInterfaceByName(name)) {
if (DBG) Log.d(TAG, name + " is no longer available.");
// Send a callback in case a provisioning request was in progress.
- maybeSendNetworkManagementCallbackForAbort();
return;
}
- restart(listener);
- }
-
- private void maybeSendNetworkManagementCallbackForAbort() {
- realizeNetworkManagementCallback(null,
- new EthernetNetworkManagementException(
- "The IP provisioning request has been aborted."));
- }
-
- // Must be called on the handler thread
- private void realizeNetworkManagementCallback(@Nullable final String iface,
- @Nullable final EthernetNetworkManagementException e) {
- ensureRunningOnEthernetHandlerThread();
- if (null == mIpClientCallback) {
- return;
- }
-
- EthernetNetworkFactory.maybeSendNetworkManagementCallback(
- mIpClientCallback.mNetworkManagementListener, iface, e);
- // Only send a single callback per listener.
- mIpClientCallback.mNetworkManagementListener = null;
+ restart();
}
private void ensureRunningOnEthernetHandlerThread() {
@@ -636,12 +568,8 @@
}
/** Returns true if state has been modified */
- boolean updateLinkState(final boolean up,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ boolean updateLinkState(final boolean up) {
if (mLinkUp == up) {
- EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null,
- new EthernetNetworkManagementException(
- "No changes with requested link state " + up + " for " + name));
return false;
}
mLinkUp = up;
@@ -654,7 +582,6 @@
registerNetworkOffer();
}
- EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null);
return true;
}
@@ -665,8 +592,7 @@
mIpClientCallback.awaitIpClientShutdown();
mIpClient = null;
}
- // Send an abort callback if an updateInterface request was in progress.
- maybeSendNetworkManagementCallbackForAbort();
+
mIpClientCallback = null;
if (mNetworkAgent != null) {
@@ -723,13 +649,9 @@
}
void restart() {
- restart(null);
- }
-
- void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
if (DBG) Log.d(TAG, "reconnecting Ethernet");
stop();
- start(listener);
+ start();
}
@Override
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
index dae3d2a..edf04b2 100644
--- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -260,7 +260,7 @@
@Override
public void updateConfiguration(@NonNull final String iface,
@NonNull final EthernetNetworkUpdateRequest request,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ @Nullable final INetworkInterfaceOutcomeReceiver cb) {
Objects.requireNonNull(iface);
Objects.requireNonNull(request);
throwIfEthernetNotStarted();
@@ -277,31 +277,31 @@
}
mTracker.updateConfiguration(
- iface, request.getIpConfiguration(), nc, listener);
+ iface, request.getIpConfiguration(), nc, new EthernetCallback(cb));
}
@Override
public void enableInterface(@NonNull final String iface,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
- Log.i(TAG, "enableInterface called with: iface=" + iface + ", listener=" + listener);
+ @Nullable final INetworkInterfaceOutcomeReceiver cb) {
+ Log.i(TAG, "enableInterface called with: iface=" + iface + ", cb=" + cb);
Objects.requireNonNull(iface);
throwIfEthernetNotStarted();
enforceAdminPermission(iface, false, "enableInterface()");
- mTracker.enableInterface(iface, listener);
+ mTracker.enableInterface(iface, new EthernetCallback(cb));
}
@Override
public void disableInterface(@NonNull final String iface,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
- Log.i(TAG, "disableInterface called with: iface=" + iface + ", listener=" + listener);
+ @Nullable final INetworkInterfaceOutcomeReceiver cb) {
+ Log.i(TAG, "disableInterface called with: iface=" + iface + ", cb=" + cb);
Objects.requireNonNull(iface);
throwIfEthernetNotStarted();
enforceAdminPermission(iface, false, "disableInterface()");
- mTracker.disableInterface(iface, listener);
+ mTracker.disableInterface(iface, new EthernetCallback(cb));
}
@Override
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index ba367cf..00dff5b 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -29,7 +29,6 @@
import android.net.EthernetManager;
import android.net.IEthernetServiceListener;
import android.net.INetd;
-import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.ITetheredInterfaceCallback;
import android.net.InterfaceConfigurationParcel;
import android.net.IpConfiguration;
@@ -271,7 +270,7 @@
}
writeIpConfiguration(iface, ipConfiguration);
mHandler.post(() -> {
- mFactory.updateInterface(iface, ipConfiguration, null, null);
+ mFactory.updateInterface(iface, ipConfiguration, null);
broadcastInterfaceStateChange(iface);
});
}
@@ -335,7 +334,7 @@
protected void updateConfiguration(@NonNull final String iface,
@Nullable final IpConfiguration ipConfig,
@Nullable final NetworkCapabilities capabilities,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ @Nullable final EthernetCallback cb) {
if (DBG) {
Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities
+ ", ipConfig: " + ipConfig);
@@ -353,21 +352,29 @@
mNetworkCapabilities.put(iface, capabilities);
}
mHandler.post(() -> {
- mFactory.updateInterface(iface, localIpConfig, capabilities, listener);
- broadcastInterfaceStateChange(iface);
+ mFactory.updateInterface(iface, localIpConfig, capabilities);
+
+ // only broadcast state change when the ip configuration is updated.
+ if (ipConfig != null) {
+ broadcastInterfaceStateChange(iface);
+ }
+ // Always return success. Even if the interface does not currently exist, the
+ // IpConfiguration and NetworkCapabilities were saved and will be applied if an
+ // interface with the given name is ever added.
+ cb.onResult(iface);
});
}
@VisibleForTesting(visibility = PACKAGE)
protected void enableInterface(@NonNull final String iface,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
- mHandler.post(() -> updateInterfaceState(iface, true, listener));
+ @Nullable final EthernetCallback cb) {
+ mHandler.post(() -> updateInterfaceState(iface, true, cb));
}
@VisibleForTesting(visibility = PACKAGE)
protected void disableInterface(@NonNull final String iface,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
- mHandler.post(() -> updateInterfaceState(iface, false, listener));
+ @Nullable final EthernetCallback cb) {
+ mHandler.post(() -> updateInterfaceState(iface, false, cb));
}
IpConfiguration getIpConfiguration(String iface) {
@@ -571,8 +578,14 @@
// Bring up the interface so we get link status indications.
try {
PermissionUtils.enforceNetworkStackPermission(mContext);
- NetdUtils.setInterfaceUp(mNetd, iface);
+ // Read the flags before attempting to bring up the interface. If the interface is
+ // already running an UP event is created after adding the interface.
config = NetdUtils.getInterfaceConfigParcel(mNetd, iface);
+ if (NetdUtils.hasFlag(config, INetd.IF_STATE_DOWN)) {
+ // As a side-effect, NetdUtils#setInterfaceUp() also clears the interface's IPv4
+ // address and readds it which *could* lead to unexpected behavior in the future.
+ NetdUtils.setInterfaceUp(mNetd, iface);
+ }
} catch (IllegalStateException e) {
// Either the system is crashing or the interface has disappeared. Just ignore the
// error; we haven't modified any state because we only do that if our calls succeed.
@@ -608,23 +621,31 @@
// Note: if the interface already has link (e.g., if we crashed and got
// restarted while it was running), we need to fake a link up notification so we
// start configuring it.
- if (NetdUtils.hasFlag(config, "running")) {
+ if (NetdUtils.hasFlag(config, INetd.IF_FLAG_RUNNING)) {
updateInterfaceState(iface, true);
}
}
private void updateInterfaceState(String iface, boolean up) {
- updateInterfaceState(iface, up, null /* listener */);
+ // TODO: pull EthernetCallbacks out of EthernetNetworkFactory.
+ updateInterfaceState(iface, up, new EthernetCallback(null /* cb */));
}
private void updateInterfaceState(@NonNull final String iface, final boolean up,
- @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ @Nullable final EthernetCallback cb) {
final int mode = getInterfaceMode(iface);
final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT)
- && mFactory.updateInterfaceLinkState(iface, up, listener);
+ && mFactory.updateInterfaceLinkState(iface, up);
if (factoryLinkStateUpdated) {
broadcastInterfaceStateChange(iface);
+ cb.onResult(iface);
+ } else {
+ // The interface may already be in the correct state. While usually this should not be
+ // an error, since updateInterfaceState is used in setInterfaceEnabled() /
+ // setInterfaceDisabled() it has to be reported as such.
+ // It is also possible that the interface disappeared or is in server mode.
+ cb.onError("Failed to set link state " + (up ? "up" : "down") + " for " + iface);
}
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 96c615b..c4ffdec 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -154,6 +154,7 @@
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.BestClock;
import com.android.net.module.util.BinderUtils;
+import com.android.net.module.util.BpfDump;
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.DeviceConfigUtils;
@@ -2532,6 +2533,7 @@
// usage: dumpsys netstats --full --uid --tag --poll --checkin
final boolean poll = argSet.contains("--poll") || argSet.contains("poll");
final boolean checkin = argSet.contains("--checkin");
+ final boolean bpfRawMap = argSet.contains("--bpfRawMap");
final boolean fullHistory = argSet.contains("--full") || argSet.contains("full");
final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
@@ -2573,6 +2575,11 @@
return;
}
+ if (bpfRawMap) {
+ dumpRawMapLocked(pw, args);
+ return;
+ }
+
pw.println("Directory:");
pw.increaseIndent();
pw.println(mStatsDir);
@@ -2743,6 +2750,38 @@
proto.flush();
}
+ private <K extends Struct, V extends Struct> void dumpRawMap(IBpfMap<K, V> map,
+ IndentingPrintWriter pw) throws ErrnoException {
+ if (map == null) {
+ pw.println("Map is null");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("No entries");
+ return;
+ }
+ // If there is a concurrent entry deletion, value could be null. http://b/220084230.
+ // Also, map.forEach could restart iteration from the beginning and dump could contain
+ // duplicated entries. User of this dump needs to take care of the duplicated entries.
+ map.forEach((k, v) -> {
+ if (v != null) {
+ pw.println(BpfDump.toBase64EncodedString(k, v));
+ }
+ });
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpRawMapLocked(final IndentingPrintWriter pw, final String[] args) {
+ if (CollectionUtils.contains(args, "--cookieTagMap")) {
+ try {
+ dumpRawMap(mCookieTagMap, pw);
+ } catch (ErrnoException e) {
+ pw.println("Error dumping cookieTag map: " + e);
+ }
+ return;
+ }
+ }
+
private static void dumpInterfaces(ProtoOutputStream proto, long tag,
ArrayMap<String, NetworkIdentitySet> ifaces) {
for (int i = 0; i < ifaces.size(); i++) {
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 11ba235..71fa8e4 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -191,6 +191,10 @@
mTc.dump(fd, verbose);
}
+static jint native_synchronizeKernelRCU(JNIEnv* env, jobject self) {
+ return -bpf::synchronizeKernelRCU();
+}
+
/*
* JNI registration.
*/
@@ -225,6 +229,8 @@
(void*)native_setPermissionForUids},
{"native_dump", "(Ljava/io/FileDescriptor;Z)V",
(void*)native_dump},
+ {"native_synchronizeKernelRCU", "()I",
+ (void*)native_synchronizeKernelRCU},
};
// clang-format on
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index a1d0310..bd74d54 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -59,7 +59,8 @@
}
}
-static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, const char* iface) {
+static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, bool setIffMulticast,
+ const char* iface) {
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
ifreq ifr{};
@@ -76,8 +77,8 @@
setTunTapCarrierEnabledImpl(env, iface, tun.get(), hasCarrier);
}
- // Mark TAP interfaces as supporting multicast
- if (!isTun) {
+ // Mark some TAP interfaces as supporting multicast
+ if (setIffMulticast && !isTun) {
base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
ifr.ifr_flags = IFF_MULTICAST;
@@ -122,14 +123,14 @@
}
static jint createTunTap(JNIEnv* env, jclass /* clazz */, jboolean isTun,
- jboolean hasCarrier, jstring jIface) {
+ jboolean hasCarrier, jboolean setIffMulticast, jstring jIface) {
ScopedUtfChars iface(env, jIface);
if (!iface.c_str()) {
jniThrowNullPointerException(env, "iface");
return -1;
}
- return createTunTapImpl(env, isTun, hasCarrier, iface.c_str());
+ return createTunTapImpl(env, isTun, hasCarrier, setIffMulticast, iface.c_str());
}
static void bringUpInterface(JNIEnv* env, jclass /* clazz */, jstring jIface) {
@@ -145,7 +146,7 @@
static const JNINativeMethod gMethods[] = {
{"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
- {"nativeCreateTunTap", "(ZZLjava/lang/String;)I", (void*)createTunTap},
+ {"nativeCreateTunTap", "(ZZZLjava/lang/String;)I", (void*)createTunTap},
{"nativeBringUpInterface", "(Ljava/lang/String;)V", (void*)bringUpInterface},
};
diff --git a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
index 3db1b22..f366363 100644
--- a/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
+++ b/service/mdns/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
@@ -38,7 +38,7 @@
* and the list of the subtypes in the query as a {@link Pair}. If a query is failed to build, or if
* it can not be enqueued, then call to {@link #call()} returns {@code null}.
*/
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<String>>> {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java b/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
index ed28700..0b2066a 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsConstants.java
@@ -27,7 +27,7 @@
import java.nio.charset.StandardCharsets;
/** mDNS-related constants. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
@VisibleForTesting
public final class MdnsConstants {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
index e35743c..bd47414 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsInetAddressRecord.java
@@ -27,7 +27,7 @@
import java.util.Objects;
/** An mDNS "AAAA" or "A" record, which holds an IPv6 or IPv4 address. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
@VisibleForTesting
public class MdnsInetAddressRecord extends MdnsRecord {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
index 2b36a3c..0166815 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsPointerRecord.java
@@ -22,7 +22,7 @@
import java.util.Arrays;
/** An mDNS "PTR" record, which holds a name (the "pointer"). */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
@VisibleForTesting
public class MdnsPointerRecord extends MdnsRecord {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
index 4bfdb2c..24fb09e 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsRecord.java
@@ -30,7 +30,7 @@
* Abstract base class for mDNS records. Stores the header fields and provides methods for reading
* the record from and writing it to a packet.
*/
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public abstract class MdnsRecord {
public static final int TYPE_A = 0x0001;
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
index 1305e07..9f3894f 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsResponse.java
@@ -25,7 +25,7 @@
import java.util.List;
/** An mDNS response. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class MdnsResponse {
private final List<MdnsRecord> records;
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index 72c3156..3e5fc42 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -30,7 +30,7 @@
import java.util.List;
/** A class that decodes mDNS responses from UDP packets. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class MdnsResponseDecoder {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
index 51de3b2..7f54d96 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceRecord.java
@@ -24,7 +24,7 @@
import java.util.Objects;
/** An mDNS "SRV" record, which contains service information. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
@VisibleForTesting
public class MdnsServiceRecord extends MdnsRecord {
@@ -143,7 +143,7 @@
return super.equals(other)
&& (servicePriority == otherRecord.servicePriority)
&& (serviceWeight == otherRecord.serviceWeight)
- && Objects.equals(serviceHost, otherRecord.serviceHost)
+ && Arrays.equals(serviceHost, otherRecord.serviceHost)
&& (servicePort == otherRecord.servicePort);
}
-}
\ No newline at end of file
+}
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index c3a86e3..e335de9 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -39,7 +39,7 @@
* Instance of this class sends and receives mDNS packets of a given service type and invoke
* registered {@link MdnsServiceBrowserListener} instances.
*/
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class MdnsServiceTypeClient {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java b/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
index 241a52a..34db7f0 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsSocket.java
@@ -32,7 +32,7 @@
*
* @see MulticastSocket for javadoc of each public method.
*/
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class MdnsSocket {
private static final InetSocketAddress MULTICAST_IPV4_ADDRESS =
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
index e689d6c..010f761 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -46,7 +46,7 @@
*
* <p>See https://tools.ietf.org/html/rfc6763 (namely sections 4 and 5).
*/
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
public class MdnsSocketClient {
diff --git a/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java b/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
index a5b5595..a364560 100644
--- a/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
+++ b/service/mdns/com/android/server/connectivity/mdns/MdnsTextRecord.java
@@ -25,7 +25,7 @@
import java.util.Objects;
/** An mDNS "TXT" record, which contains a list of text strings. */
-// TODO(b/177655645): Resolve nullness suppression.
+// TODO(b/242631897): Resolve nullness suppression.
@SuppressWarnings("nullness")
@VisibleForTesting
public class MdnsTextRecord extends MdnsRecord {
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 594223c..6bb8115 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -26,6 +26,8 @@
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
+import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
import static android.system.OsConstants.EINVAL;
import static android.system.OsConstants.ENODEV;
import static android.system.OsConstants.ENOENT;
@@ -38,6 +40,7 @@
import android.provider.DeviceConfig;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -45,13 +48,11 @@
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.U8;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* BpfNetMaps is responsible for providing traffic controller relevant functionality.
@@ -81,10 +82,17 @@
// BpfNetMaps acquires this lock while sequence of read, modify, and write.
private static final Object sUidRulesConfigBpfMapLock = new Object();
+ // Lock for sConfigurationMap entry for CURRENT_STATS_MAP_CONFIGURATION_KEY.
+ // BpfNetMaps acquires this lock while sequence of read, modify, and write.
+ // BpfNetMaps is an only writer of this entry.
+ private static final Object sCurrentStatsMapConfigLock = new Object();
+
private static final String CONFIGURATION_MAP_PATH =
"/sys/fs/bpf/netd_shared/map_netd_configuration_map";
private static final String UID_OWNER_MAP_PATH =
"/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
+ private static final String UID_PERMISSION_MAP_PATH =
+ "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
private static final U32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new U32(1);
private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
@@ -94,6 +102,7 @@
private static BpfMap<U32, U32> sConfigurationMap = null;
// BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
+ private static BpfMap<U32, U8> sUidPermissionMap = null;
// LINT.IfChange(match_type)
@VisibleForTesting public static final long NO_MATCH = 0;
@@ -135,6 +144,14 @@
sUidOwnerMap = uidOwnerMap;
}
+ /**
+ * Set uidPermissionMap for test.
+ */
+ @VisibleForTesting
+ public static void setUidPermissionMapForTest(BpfMap<U32, U8> uidPermissionMap) {
+ sUidPermissionMap = uidPermissionMap;
+ }
+
private static BpfMap<U32, U32> getConfigurationMap() {
try {
return new BpfMap<>(
@@ -153,6 +170,15 @@
}
}
+ private static BpfMap<U32, U8> getUidPermissionMap() {
+ try {
+ return new BpfMap<>(
+ UID_PERMISSION_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U8.class);
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Cannot open uid permission map", e);
+ }
+ }
+
private static void initBpfMaps() {
if (sConfigurationMap == null) {
sConfigurationMap = getConfigurationMap();
@@ -178,6 +204,10 @@
} catch (ErrnoException e) {
throw new IllegalStateException("Failed to initialize uid owner map", e);
}
+
+ if (sUidPermissionMap == null) {
+ sUidPermissionMap = getUidPermissionMap();
+ }
}
/**
@@ -209,6 +239,13 @@
public int getIfIndex(final String ifName) {
return Os.if_nametoindex(ifName);
}
+
+ /**
+ * Call synchronize_rcu()
+ */
+ public int synchronizeKernelRCU() {
+ return native_synchronizeKernelRCU();
+ }
}
/** Constructor used after T that doesn't need to use netd anymore. */
@@ -479,6 +516,14 @@
}
}
+ private Set<Integer> asSet(final int[] uids) {
+ final Set<Integer> uidSet = new ArraySet<>();
+ for (final int uid: uids) {
+ uidSet.add(uid);
+ }
+ return uidSet;
+ }
+
/**
* Replaces the contents of the specified UID-based firewall chain.
* Enables the chain for specified uids and disables the chain for non-specified uids.
@@ -500,15 +545,17 @@
// ConnectivityManager#replaceFirewallChain API
throw new IllegalArgumentException("Invalid firewall chain: " + chain);
}
- final Set<Integer> uidSet = Arrays.stream(uids).boxed().collect(Collectors.toSet());
- final Set<Integer> uidSetToRemoveRule = new HashSet<>();
+ final Set<Integer> uidSet = asSet(uids);
+ final Set<Integer> uidSetToRemoveRule = new ArraySet<>();
try {
synchronized (sUidOwnerMap) {
sUidOwnerMap.forEach((uid, config) -> {
// config could be null if there is a concurrent entry deletion.
- // http://b/220084230.
- if (config != null
- && !uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
+ // http://b/220084230. But sUidOwnerMap update must be done while holding a
+ // lock, so this should not happen.
+ if (config == null) {
+ Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock");
+ } else if (!uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
uidSetToRemoveRule.add((int) uid.val);
}
});
@@ -696,12 +743,40 @@
/**
* Request netd to change the current active network stats map.
*
+ * @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public void swapActiveStatsMap() {
- final int err = native_swapActiveStatsMap();
- maybeThrow(err, "Unable to swap active stats map");
+ throwIfPreT("swapActiveStatsMap is not available on pre-T devices");
+
+ if (sEnableJavaBpfMap) {
+ try {
+ synchronized (sCurrentStatsMapConfigLock) {
+ final long config = sConfigurationMap.getValue(
+ CURRENT_STATS_MAP_CONFIGURATION_KEY).val;
+ final long newConfig = (config == STATS_SELECT_MAP_A)
+ ? STATS_SELECT_MAP_B : STATS_SELECT_MAP_A;
+ sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY,
+ new U32(newConfig));
+ }
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno, "Failed to swap active stats map");
+ }
+
+ // After changing the config, it's needed to make sure all the current running eBPF
+ // programs are finished and all the CPUs are aware of this config change before the old
+ // map is modified. So special hack is needed here to wait for the kernel to do a
+ // synchronize_rcu(). Once the kernel called synchronize_rcu(), the updated config will
+ // be available to all cores and the next eBPF programs triggered inside the kernel will
+ // use the new map configuration. So once this function returns it is safe to modify the
+ // old stats map without concerning about race between the kernel and userspace.
+ final int err = mDeps.synchronizeKernelRCU();
+ maybeThrow(err, "synchronizeKernelRCU failed");
+ } else {
+ final int err = native_swapActiveStatsMap();
+ maybeThrow(err, "Unable to swap active stats map");
+ }
}
/**
@@ -719,7 +794,31 @@
mNetd.trafficSetNetPermForUids(permissions, uids);
return;
}
- native_setPermissionForUids(permissions, uids);
+
+ if (sEnableJavaBpfMap) {
+ // Remove the entry if package is uninstalled or uid has only INTERNET permission.
+ if (permissions == PERMISSION_UNINSTALLED || permissions == PERMISSION_INTERNET) {
+ for (final int uid : uids) {
+ try {
+ sUidPermissionMap.deleteEntry(new U32(uid));
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to remove uid " + uid + " from permission map: " + e);
+ }
+ }
+ return;
+ }
+
+ for (final int uid : uids) {
+ try {
+ sUidPermissionMap.updateEntry(new U32(uid), new U8((short) permissions));
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to set permission "
+ + permissions + " to uid " + uid + ": " + e);
+ }
+ }
+ } else {
+ native_setPermissionForUids(permissions, uids);
+ }
}
/**
@@ -753,4 +852,5 @@
private native int native_swapActiveStatsMap();
private native void native_setPermissionForUids(int permissions, int[] uids);
private native void native_dump(FileDescriptor fd, boolean verbose);
+ private static native int native_synchronizeKernelRCU();
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 1ac95a1..218cbde 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -257,6 +257,7 @@
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.net.module.util.LocationPermissionChecker;
import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.net.module.util.PerUidCounter;
import com.android.net.module.util.PermissionUtils;
import com.android.net.module.util.TcUtils;
import com.android.net.module.util.netlink.InetDiagMessage;
@@ -386,9 +387,9 @@
protected final PermissionMonitor mPermissionMonitor;
@VisibleForTesting
- final PerUidCounter mNetworkRequestCounter;
+ final RequestInfoPerUidCounter mNetworkRequestCounter;
@VisibleForTesting
- final PerUidCounter mSystemNetworkRequestCounter;
+ final RequestInfoPerUidCounter mSystemNetworkRequestCounter;
private volatile boolean mLockdownEnabled;
@@ -1186,71 +1187,6 @@
}
/**
- * Keeps track of the number of requests made under different uids.
- */
- // TODO: Remove the hack and use com.android.net.module.util.PerUidCounter instead.
- public static class PerUidCounter {
- private final int mMaxCountPerUid;
-
- // Map from UID to number of NetworkRequests that UID has filed.
- @VisibleForTesting
- @GuardedBy("mUidToNetworkRequestCount")
- final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
- /**
- * Constructor
- *
- * @param maxCountPerUid the maximum count per uid allowed
- */
- public PerUidCounter(final int maxCountPerUid) {
- mMaxCountPerUid = maxCountPerUid;
- }
-
- /**
- * Increments the request count of the given uid. Throws an exception if the number
- * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
- * passed into the constructor. see: {@link #PerUidCounter(int)}.
- *
- * @throws ServiceSpecificException with
- * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
- * the uid exceed the allowed number.
- *
- * @param uid the uid that the request was made under
- */
- public void incrementCountOrThrow(final int uid) {
- synchronized (mUidToNetworkRequestCount) {
- final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) + 1;
- if (newRequestCount >= mMaxCountPerUid) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS,
- "Uid " + uid + " exceeded its allotted requests limit");
- }
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
- }
-
- /**
- * Decrements the request count of the given uid.
- *
- * @param uid the uid that the request was made under
- */
- public void decrementCount(final int uid) {
- synchronized (mUidToNetworkRequestCount) {
- /* numToDecrement */
- final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) - 1;
- if (newRequestCount < 0) {
- logwtf("BUG: too small request count " + newRequestCount + " for UID " + uid);
- } else if (newRequestCount == 0) {
- mUidToNetworkRequestCount.delete(uid);
- } else {
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
- }
- }
-
- }
-
- /**
* Dependencies of ConnectivityService, for injection in tests.
*/
@VisibleForTesting
@@ -1464,8 +1400,13 @@
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
mResources = deps.getResources(mContext);
- mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
- mSystemNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID);
+ // The legacy PerUidCounter is buggy and throwing exception at count == limit.
+ // Pass limit - 1 to maintain backward compatibility.
+ // TODO: Remove the workaround.
+ mNetworkRequestCounter =
+ new RequestInfoPerUidCounter(MAX_NETWORK_REQUESTS_PER_UID - 1);
+ mSystemNetworkRequestCounter =
+ new RequestInfoPerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - 1);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
@@ -4763,7 +4704,7 @@
}
}
}
- nri.decrementRequestCount();
+ nri.mPerUidCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
checkNrisConsistency(nri);
@@ -4866,7 +4807,7 @@
}
}
- private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
+ private RequestInfoPerUidCounter getRequestCounter(NetworkRequestInfo nri) {
return checkAnyPermissionOf(
nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
? mSystemNetworkRequestCounter : mNetworkRequestCounter;
@@ -6236,7 +6177,7 @@
final String mCallingAttributionTag;
// Counter keeping track of this NRI.
- final PerUidCounter mPerUidCounter;
+ final RequestInfoPerUidCounter mPerUidCounter;
// Effective UID of this request. This is different from mUid when a privileged process
// files a request on behalf of another UID. This UID is used to determine blocked status,
@@ -6402,10 +6343,6 @@
return Collections.unmodifiableList(tempRequests);
}
- void decrementRequestCount() {
- mPerUidCounter.decrementCount(mUid);
- }
-
void linkDeathRecipient() {
if (null != mBinder) {
try {
@@ -6467,6 +6404,38 @@
}
}
+ // Keep backward compatibility since the ServiceSpecificException is used by
+ // the API surface, see {@link ConnectivityManager#convertServiceException}.
+ public static class RequestInfoPerUidCounter extends PerUidCounter {
+ RequestInfoPerUidCounter(int maxCountPerUid) {
+ super(maxCountPerUid);
+ }
+
+ @Override
+ public synchronized void incrementCountOrThrow(int uid) {
+ try {
+ super.incrementCountOrThrow(uid);
+ } catch (IllegalStateException e) {
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS,
+ "Uid " + uid + " exceeded its allotted requests limit");
+ }
+ }
+
+ @Override
+ public synchronized void decrementCountOrThrow(int uid) {
+ throw new UnsupportedOperationException("Use decrementCount instead.");
+ }
+
+ public synchronized void decrementCount(int uid) {
+ try {
+ super.decrementCountOrThrow(uid);
+ } catch (IllegalStateException e) {
+ logwtf("Exception when decrement per uid request count: ", e);
+ }
+ }
+ }
+
// This checks that the passed capabilities either do not request a
// specific SSID/SignalStrength, or the calling app has permission to do so.
private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
@@ -9963,7 +9932,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- nri.decrementRequestCount();
+ nri.mPerUidCounter.decrementCount(nri.mUid);
return;
}
@@ -10029,7 +9998,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- nri.decrementRequestCount();
+ nri.mPerUidCounter.decrementCount(nri.mUid);
iCb.unlinkToDeath(cbInfo, 0);
}
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index 15d9f13..5549fbe 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -77,7 +77,7 @@
// Native method stubs
private static native int nativeCreateTunTap(boolean isTun, boolean hasCarrier,
- @NonNull String iface);
+ boolean setIffMulticast, @NonNull String iface);
private static native void nativeSetTunTapCarrierEnabled(@NonNull String iface, int tunFd,
boolean enabled);
@@ -136,8 +136,14 @@
final long token = Binder.clearCallingIdentity();
try {
+ // Note: if the interface is brought up by ethernet, setting IFF_MULTICAST
+ // races NetUtils#setInterfaceUp(). This flag is not necessary for ethernet
+ // tests, so let's not set it when bringUp is false. See also b/242343156.
+ // In the future, we could use RTM_SETLINK with ifi_change set to set the
+ // flags atomically.
+ final boolean setIffMulticast = bringUp;
ParcelFileDescriptor tunIntf = ParcelFileDescriptor.adoptFd(
- nativeCreateTunTap(isTun, hasCarrier, interfaceName));
+ nativeCreateTunTap(isTun, hasCarrier, setIffMulticast, interfaceName));
// Disable DAD and remove router_solicitation_delay before assigning link addresses.
if (disableIpv6ProvisioningDelay) {
diff --git a/service/src/com/android/server/connectivity/QosCallbackTracker.java b/service/src/com/android/server/connectivity/QosCallbackTracker.java
index b6ab47b..336a399 100644
--- a/service/src/com/android/server/connectivity/QosCallbackTracker.java
+++ b/service/src/com/android/server/connectivity/QosCallbackTracker.java
@@ -52,7 +52,7 @@
private final Handler mConnectivityServiceHandler;
@NonNull
- private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
+ private final ConnectivityService.RequestInfoPerUidCounter mNetworkRequestCounter;
/**
* Each agent gets a unique callback id that is used to proxy messages back to the original
@@ -78,7 +78,7 @@
* uid
*/
public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
- final ConnectivityService.PerUidCounter networkRequestCounter) {
+ final ConnectivityService.RequestInfoPerUidCounter networkRequestCounter) {
mConnectivityServiceHandler = connectivityServiceHandler;
mNetworkRequestCounter = networkRequestCounter;
}
diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp
index edfaf9f..db92f5c 100644
--- a/tests/cts/hostside/app2/Android.bp
+++ b/tests/cts/hostside/app2/Android.bp
@@ -21,7 +21,7 @@
android_test_helper_app {
name: "CtsHostsideNetworkTestsApp2",
defaults: ["cts_support_defaults"],
- sdk_version: "test_current",
+ platform_apis: true,
static_libs: [
"androidx.annotation_annotation",
"CtsHostsideNetworkTestsAidl",
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 771b404..825f2c9 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -48,6 +48,7 @@
import android.widget.Toast;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
import java.net.URL;
/**
@@ -182,6 +183,11 @@
checkStatus = false;
checkDetails = "Exception getting " + address + ": " + e;
}
+ // If the app tries to make a network connection in the foreground immediately after
+ // trying to do the same when it's network access was blocked, it could receive a
+ // UnknownHostException due to the cached DNS entry. So, clear the dns cache after
+ // every network access for now until we have a fix on the platform side.
+ InetAddress.clearDnsCache();
Log.d(TAG, checkDetails);
final String state, detailedState;
if (networkInfo != null) {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 6ff2458..cece4df 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -26,6 +26,7 @@
import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.TETHER_PRIVILEGED;
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
@@ -2488,15 +2489,24 @@
ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext);
- TestTetheringEventCallback tetherEventCallback = null;
final CtsTetheringUtils tetherUtils = new CtsTetheringUtils(mContext);
+ final TestTetheringEventCallback tetherEventCallback =
+ tetherUtils.registerTetheringEventCallback();
try {
- tetherEventCallback = tetherUtils.registerTetheringEventCallback();
- // start tethering
tetherEventCallback.assumeWifiTetheringSupported(mContext);
- tetherUtils.startWifiTethering(tetherEventCallback);
+
+ final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
+ mCtsNetUtils.ensureWifiConnected();
+ registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
// Update setting to verify the behavior.
setAirplaneMode(true);
+ // Verify wifi lost to make sure airplane mode takes effect. This could
+ // prevent the race condition between airplane mode enabled and the followed
+ // up wifi tethering enabled.
+ waitForLost(wifiCb);
+ // start wifi tethering
+ tetherUtils.startWifiTethering(tetherEventCallback);
+
ConnectivitySettingsManager.setPrivateDnsMode(mContext,
ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF);
ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
@@ -2504,20 +2514,19 @@
assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
// Verify factoryReset
- runAsShell(NETWORK_SETTINGS, () -> mCm.factoryReset());
+ runAsShell(NETWORK_SETTINGS, TETHER_PRIVILEGED, () -> {
+ mCm.factoryReset();
+ tetherEventCallback.expectNoTetheringActive();
+ });
verifySettings(AIRPLANE_MODE_OFF,
ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT);
-
- tetherEventCallback.expectNoTetheringActive();
} finally {
// Restore settings.
setAirplaneMode(false);
ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi);
ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode);
- if (tetherEventCallback != null) {
- tetherUtils.unregisterTetheringEventCallback(tetherEventCallback);
- }
+ tetherUtils.unregisterTetheringEventCallback(tetherEventCallback);
tetherUtils.stopAllTethering();
}
}
diff --git a/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt b/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
index 3a739f2..9599d4e 100644
--- a/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
+++ b/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
@@ -21,7 +21,7 @@
import android.provider.DeviceConfig
import android.util.Log
import com.android.modules.utils.build.SdkLevel
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
+import com.android.testutils.FunctionalUtils.ThrowingRunnable
import com.android.testutils.runAsShell
import com.android.testutils.tryTest
import org.junit.rules.TestRule
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 1f76773..8940075 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -163,8 +163,7 @@
// Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
// address.
- iface = tnm.createTapInterface(true /* disableIpv6ProvisioningDelay */,
- arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
+ iface = tnm.createTapInterface(arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
assertNotNull(iface)
}
@@ -224,7 +223,7 @@
val onLinkPrefix = raResponder.prefix
val startTime = SystemClock.elapsedRealtime()
while (SystemClock.elapsedRealtime() - startTime < PACKET_TIMEOUT_MS) {
- SystemClock.sleep(1 /* ms */)
+ SystemClock.sleep(50 /* ms */)
val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
try {
network.bindSocket(sock)
@@ -273,7 +272,6 @@
val lp = LinkProperties().apply {
addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
- addRoute(RouteInfo(IpPrefix("::/0"), TEST_ROUTER_IPV6_ADDR))
setInterfaceName(specifier)
}
val config = NetworkAgentConfig.Builder().build()
@@ -318,6 +316,7 @@
fun parseV4PacketDscp(buffer: ByteBuffer): Int {
// Validate checksum before parsing packet.
val calCheck = IpUtils.ipChecksum(buffer, Struct.getSize(EthernetHeader::class.java))
+ assertEquals(0, calCheck, "Invalid IPv4 header checksum")
val ip_ver = buffer.get()
val tos = buffer.get()
@@ -328,7 +327,11 @@
val ipType = buffer.get()
val checksum = buffer.getShort()
- assertEquals(0, calCheck, "Invalid IPv4 header checksum")
+ if (ipType.toInt() == 2 /* IPPROTO_IGMP */ && ip_ver.toInt() == 0x46) {
+ // Need to ignore 'igmp v3 report' with 'router alert' option
+ } else {
+ assertEquals(0x45, ip_ver.toInt(), "Invalid IPv4 version or IPv4 options present")
+ }
return tos.toInt().shr(2)
}
@@ -339,6 +342,9 @@
val length = buffer.getShort()
val proto = buffer.get()
val hop = buffer.get()
+
+ assertEquals(6, ip_ver.toInt().shr(4), "Invalid IPv6 version")
+
// DSCP is bottom 4 bits of ip_ver and top 2 of tc.
val ip_ver_bottom = ip_ver.toInt().and(0xf)
val tc_dscp = tc.toInt().shr(6)
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index ce8584f..b21c5b4 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -77,6 +77,7 @@
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import java.net.Inet6Address
@@ -95,12 +96,11 @@
import kotlin.test.fail
private const val TAG = "EthernetManagerTest"
-// TODO: try to lower this timeout in the future. Currently, ethernet tests are still flaky because
-// the interface is not ready fast enough (mostly due to the up / up / down / up issue).
-private const val TIMEOUT_MS = 2000L
+private const val TIMEOUT_MS = 1000L
// Timeout used to confirm no callbacks matching given criteria are received. Must be long enough to
// process all callbacks including ip provisioning when using the updateConfiguration API.
-private const val NO_CALLBACK_TIMEOUT_MS = 500L
+// Note that increasing this timeout increases the test duration.
+private const val NO_CALLBACK_TIMEOUT_MS = 200L
private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP,
IpConfiguration.ProxySettings.NONE, null, null)
@@ -151,7 +151,9 @@
context.getSystemService(TestNetworkManager::class.java)
}
tapInterface = runAsShell(MANAGE_TEST_NETWORKS) {
- tnm.createTapInterface(hasCarrier, false /* bringUp */)
+ // setting RS delay to 0 and disabling DAD speeds up tests.
+ tnm.createTapInterface(hasCarrier, false /* bringUp */,
+ true /* disableIpv6ProvisioningDelay */)
}
val mtu = tapInterface.mtu
packetReader = TapPacketReader(handler, tapInterface.fileDescriptor.fileDescriptor, mtu)
@@ -193,9 +195,35 @@
val state: Int,
val role: Int,
val configuration: IpConfiguration?
- ) : CallbackEntry()
+ ) : CallbackEntry() {
+ override fun toString(): String {
+ val stateString = when (state) {
+ STATE_ABSENT -> "STATE_ABSENT"
+ STATE_LINK_UP -> "STATE_LINK_UP"
+ STATE_LINK_DOWN -> "STATE_LINK_DOWN"
+ else -> state.toString()
+ }
+ val roleString = when (role) {
+ ROLE_NONE -> "ROLE_NONE"
+ ROLE_CLIENT -> "ROLE_CLIENT"
+ ROLE_SERVER -> "ROLE_SERVER"
+ else -> role.toString()
+ }
+ return ("InterfaceStateChanged(iface=$iface, state=$stateString, " +
+ "role=$roleString, ipConfig=$configuration)")
+ }
+ }
- data class EthernetStateChanged(val state: Int) : CallbackEntry()
+ data class EthernetStateChanged(val state: Int) : CallbackEntry() {
+ override fun toString(): String {
+ val stateString = when (state) {
+ ETHERNET_STATE_ENABLED -> "ETHERNET_STATE_ENABLED"
+ ETHERNET_STATE_DISABLED -> "ETHERNET_STATE_DISABLED"
+ else -> state.toString()
+ }
+ return "EthernetStateChanged(state=$stateString)"
+ }
+ }
}
override fun onInterfaceStateChanged(
@@ -236,11 +264,13 @@
fun eventuallyExpect(expected: CallbackEntry) = events.poll(TIMEOUT_MS) { it == expected }
fun eventuallyExpect(iface: EthernetTestInterface, state: Int, role: Int) {
- assertNotNull(eventuallyExpect(createChangeEvent(iface.name, state, role)))
+ val event = createChangeEvent(iface.name, state, role)
+ assertNotNull(eventuallyExpect(event), "Never received expected $event")
}
fun eventuallyExpect(state: Int) {
- assertNotNull(eventuallyExpect(EthernetStateChanged(state)))
+ val event = EthernetStateChanged(state)
+ assertNotNull(eventuallyExpect(event), "Never received expected $event")
}
fun assertNoCallback() {
@@ -306,14 +336,24 @@
}
}
+ private fun isEthernetSupported() = em != null
+
@Before
fun setUp() {
+ assumeTrue(isEthernetSupported())
setIncludeTestInterfaces(true)
addInterfaceStateListener(ifaceListener)
+ // Handler.post() events may get processed after native fd events, so it is possible that
+ // RTM_NEWLINK (from a subsequent createInterface() call) arrives before the interface state
+ // listener is registered. This affects the callbacks and breaks the tests.
+ // setEthernetEnabled() will always wait on a callback, so it is used as a barrier to ensure
+ // proper listener registration before proceeding.
+ setEthernetEnabled(true)
}
@After
fun tearDown() {
+ if (!isEthernetSupported()) return
// Reenable ethernet, so ABSENT callbacks are received.
setEthernetEnabled(true)
@@ -496,10 +536,7 @@
validateListenerOnRegistration(listener1)
// If an interface appears, existing callbacks see it.
- // TODO: fix the up/up/down/up callbacks and only send down/up.
val iface2 = createInterface()
- listener1.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
- listener1.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
listener1.expectCallback(iface2, STATE_LINK_DOWN, ROLE_CLIENT)
listener1.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
@@ -778,7 +815,7 @@
.Builder(ETH_REQUEST.networkCapabilities)
.addCapability(testCapability)
.build()
- updateConfiguration(iface, STATIC_IP_CONFIGURATION, nc)
+ updateConfiguration(iface, STATIC_IP_CONFIGURATION, nc).expectResult(iface.name)
// UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
// will be expected first before available, as part of the restart.
@@ -796,7 +833,7 @@
val network = cb.expectAvailable()
cb.assertNeverLost()
- updateConfiguration(iface, STATIC_IP_CONFIGURATION)
+ updateConfiguration(iface, STATIC_IP_CONFIGURATION).expectResult(iface.name)
// UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
// will be expected first before available, as part of the restart.
@@ -807,6 +844,9 @@
STATIC_IP_CONFIGURATION.staticIpConfiguration.ipAddress!!)
}
+ // TODO(b/240323229): This test is currently flaky due to a race between IpClient restarting and
+ // NetworkAgent tearing down the routes. This problem is exacerbated by disabling RS delay.
+ @Ignore
@Test
fun testUpdateConfiguration_forOnlyCapabilities() {
val iface: EthernetTestInterface = createInterface()
@@ -819,7 +859,7 @@
.Builder(ETH_REQUEST.networkCapabilities)
.addCapability(testCapability)
.build()
- updateConfiguration(iface, capabilities = nc)
+ updateConfiguration(iface, capabilities = nc).expectResult(iface.name)
// UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
// will be expected first before available, as part of the restart.
diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java
index d8e39b4..0377160 100644
--- a/tests/cts/net/src/android/net/cts/TunUtils.java
+++ b/tests/cts/net/src/android/net/cts/TunUtils.java
@@ -27,12 +27,13 @@
import android.os.ParcelFileDescriptor;
+import com.android.net.module.util.CollectionUtils;
+
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
@@ -170,7 +171,7 @@
*/
private static boolean isEspFailIfSpecifiedPlaintextFound(
byte[] pkt, int spi, boolean encap, byte[] plaintext) {
- if (Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) != -1) {
+ if (CollectionUtils.indexOfSubArray(pkt, plaintext) != -1) {
fail("Banned plaintext packet found");
}
diff --git a/tests/integration/AndroidManifest.xml b/tests/integration/AndroidManifest.xml
index 2e13689..50f02d3 100644
--- a/tests/integration/AndroidManifest.xml
+++ b/tests/integration/AndroidManifest.xml
@@ -60,7 +60,7 @@
<action android:name=".INetworkStackInstrumentation"/>
</intent-filter>
</service>
- <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+ <service android:name="com.android.networkstack.ipmemorystore.RegularMaintenanceJobService"
android:process="com.android.server.net.integrationtests.testnetworkstack"
android:permission="android.permission.BIND_JOB_SERVICE"/>
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
index e3dbb14..8a4932b 100644
--- a/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -38,7 +38,7 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.ExceptionUtils;
+import com.android.testutils.FunctionalUtils.ThrowingConsumer;
import org.junit.Before;
import org.junit.Rule;
@@ -396,7 +396,7 @@
}
}
- int getRequestKey(ExceptionUtils.ThrowingConsumer<ArgumentCaptor<Integer>> verifier)
+ int getRequestKey(ThrowingConsumer<ArgumentCaptor<Integer>> verifier)
throws Exception {
final ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
verifier.accept(captor);
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 2d09bf2..be286ec 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -27,6 +27,10 @@
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NONE;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
+import static android.system.OsConstants.EPERM;
import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH;
@@ -56,6 +60,7 @@
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.U8;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -88,6 +93,7 @@
private static final int NULL_IIF = 0;
private static final String CHAINNAME = "fw_dozable";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
+ private static final U32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new U32(1);
private static final List<Integer> FIREWALL_CHAINS = List.of(
FIREWALL_CHAIN_DOZABLE,
FIREWALL_CHAIN_STANDBY,
@@ -99,6 +105,9 @@
FIREWALL_CHAIN_OEM_DENY_3
);
+ private static final long STATS_SELECT_MAP_A = 0;
+ private static final long STATS_SELECT_MAP_B = 1;
+
private BpfNetMaps mBpfNetMaps;
@Mock INetd mNetd;
@@ -107,14 +116,17 @@
private final BpfMap<U32, U32> mConfigurationMap = new TestBpfMap<>(U32.class, U32.class);
private final BpfMap<U32, UidOwnerValue> mUidOwnerMap =
new TestBpfMap<>(U32.class, UidOwnerValue.class);
+ private final BpfMap<U32, U8> mUidPermissionMap = new TestBpfMap<>(U32.class, U8.class);
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
+ doReturn(0).when(mDeps).synchronizeKernelRCU();
BpfNetMaps.setEnableJavaBpfMapForTest(true /* enable */);
BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap);
+ BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap);
mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
}
@@ -728,4 +740,141 @@
() -> mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS));
}
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsGrantInternetPermission() throws Exception {
+ mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
+
+ assertTrue(mUidPermissionMap.isEmpty());
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsGrantUpdateStatsPermission() throws Exception {
+ mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
+
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid1)).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsGrantMultiplePermissions() throws Exception {
+ final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+ mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsRevokeInternetPermission() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
+ mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsRevokeUpdateDeviceStatsPermission() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
+ mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid1)).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsRevokeMultiplePermissions() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+ mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+ mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsPermissionUninstalled() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+ mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+ mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, new int[]{uid0});
+
+ assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetNetPermForUidsDuplicatedRequestSilentlyIgnored() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+
+ mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+ mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+ mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+ mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+ assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+ mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
+ assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+ assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+
+ mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
+ assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+ assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSwapActiveStatsMap() throws Exception {
+ mConfigurationMap.updateEntry(
+ CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
+
+ mBpfNetMaps.swapActiveStatsMap();
+ assertEquals(STATS_SELECT_MAP_B,
+ mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val);
+
+ mBpfNetMaps.swapActiveStatsMap();
+ assertEquals(STATS_SELECT_MAP_A,
+ mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSwapActiveStatsMapSynchronizeKernelRCUFail() throws Exception {
+ doReturn(EPERM).when(mDeps).synchronizeKernelRCU();
+ mConfigurationMap.updateEntry(
+ CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A));
+
+ assertThrows(ServiceSpecificException.class, () -> mBpfNetMaps.swapActiveStatsMap());
+ }
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 4b832dd..d7440bb 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -35,7 +35,6 @@
import static android.content.Intent.ACTION_PACKAGE_REPLACED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
import static android.content.pm.PackageManager.FEATURE_WIFI;
@@ -159,7 +158,7 @@
import static com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-import static com.android.testutils.ExceptionUtils.ignoreExceptions;
+import static com.android.testutils.FunctionalUtils.ignoreExceptions;
import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
import static com.android.testutils.MiscAsserts.assertContainsAll;
import static com.android.testutils.MiscAsserts.assertContainsExactly;
@@ -375,10 +374,13 @@
import com.android.server.connectivity.UidRangeUtils;
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
+import com.android.server.net.LockdownVpnTracker;
import com.android.server.net.NetworkPinner;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.ExceptionUtils;
+import com.android.testutils.FunctionalUtils.Function3;
+import com.android.testutils.FunctionalUtils.ThrowingConsumer;
+import com.android.testutils.FunctionalUtils.ThrowingRunnable;
import com.android.testutils.HandlerUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.TestableNetworkCallback;
@@ -520,7 +522,6 @@
private MockContext mServiceContext;
private HandlerThread mCsHandlerThread;
- private HandlerThread mVMSHandlerThread;
private ConnectivityServiceDependencies mDeps;
private ConnectivityService mService;
private WrappedConnectivityManager mCm;
@@ -536,7 +537,6 @@
private TestNetIdManager mNetIdManager;
private QosCallbackMockHelper mQosCallbackMockHelper;
private QosCallbackTracker mQosCallbackTracker;
- private VpnManagerService mVpnManagerService;
private TestNetworkCallback mDefaultNetworkCallback;
private TestNetworkCallback mSystemDefaultNetworkCallback;
private TestNetworkCallback mProfileDefaultNetworkCallback;
@@ -744,7 +744,7 @@
}
private int checkMockedPermission(String permission, int pid, int uid,
- Supplier<Integer> ifAbsent) {
+ Function3<String, Integer, Integer, Integer> ifAbsent /* perm, uid, pid -> int */) {
final Integer granted = mMockedPermissions.get(permission + "," + pid + "," + uid);
if (null != granted) {
return granted;
@@ -753,27 +753,27 @@
if (null != allGranted) {
return allGranted;
}
- return ifAbsent.get();
+ return ifAbsent.apply(permission, pid, uid);
}
@Override
public int checkPermission(String permission, int pid, int uid) {
return checkMockedPermission(permission, pid, uid,
- () -> super.checkPermission(permission, pid, uid));
+ (perm, p, u) -> super.checkPermission(perm, p, u));
}
@Override
public int checkCallingOrSelfPermission(String permission) {
return checkMockedPermission(permission, Process.myPid(), Process.myUid(),
- () -> super.checkCallingOrSelfPermission(permission));
+ (perm, p, u) -> super.checkCallingOrSelfPermission(perm));
}
@Override
public void enforceCallingOrSelfPermission(String permission, String message) {
final Integer granted = checkMockedPermission(permission,
Process.myPid(), Process.myUid(),
- () -> {
- super.enforceCallingOrSelfPermission(permission, message);
+ (perm, p, u) -> {
+ super.enforceCallingOrSelfPermission(perm, message);
// enforce will crash if the permission is not granted
return PERMISSION_GRANTED;
});
@@ -786,7 +786,7 @@
/**
* Mock checks for the specified permission, and have them behave as per {@code granted}.
*
- * This will apply across the board no matter what the checked UID and PID are.
+ * This will apply to all calls no matter what the checked UID and PID are.
*
* <p>Passing null reverts to default behavior, which does a real permission check on the
* test package.
@@ -1584,32 +1584,6 @@
return ranges.stream().map(r -> new UidRangeParcel(r, r)).toArray(UidRangeParcel[]::new);
}
- private VpnManagerService makeVpnManagerService() {
- final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
- public int getCallingUid() {
- return mDeps.getCallingUid();
- }
-
- public HandlerThread makeHandlerThread() {
- return mVMSHandlerThread;
- }
-
- @Override
- public VpnProfileStore getVpnProfileStore() {
- return mVpnProfileStore;
- }
-
- public INetd getNetd() {
- return mMockNetd;
- }
-
- public INetworkManagementService getINetworkManagementService() {
- return mNetworkManagementService;
- }
- };
- return new VpnManagerService(mServiceContext, deps);
- }
-
private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
assertNotNull(nc);
final TransportInfo ti = nc.getTransportInfo();
@@ -1621,17 +1595,12 @@
private void processBroadcast(Intent intent) {
mServiceContext.sendBroadcast(intent);
- HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
waitForIdle();
}
private void mockVpn(int uid) {
- synchronized (mVpnManagerService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
- mVpnManagerService.mVpns.put(userId, mMockVpn);
- }
+ int userId = UserHandle.getUserId(uid);
+ mMockVpn = new MockVpn(userId);
}
private void mockUidNetworkingBlocked() {
@@ -1718,11 +1687,7 @@
});
}
- private interface ExceptionalRunnable {
- void run() throws Exception;
- }
-
- private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
+ private void withPermission(String permission, ThrowingRunnable r) throws Exception {
try {
mServiceContext.setPermission(permission, PERMISSION_GRANTED);
r.run();
@@ -1731,7 +1696,7 @@
}
}
- private void withPermission(String permission, int pid, int uid, ExceptionalRunnable r)
+ private void withPermission(String permission, int pid, int uid, ThrowingRunnable r)
throws Exception {
try {
mServiceContext.setPermission(permission, pid, uid, PERMISSION_GRANTED);
@@ -1812,7 +1777,6 @@
initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
mCsHandlerThread = new HandlerThread("TestConnectivityService");
- mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
mProxyTracker = new ProxyTracker(mServiceContext, mock(Handler.class),
16 /* EVENT_PROXY_HAS_CHANGED */);
@@ -1841,8 +1805,7 @@
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReadyInternal();
verify(mMockDnsResolver).registerUnsolicitedEventListener(any());
- mVpnManagerService = makeVpnManagerService();
- mVpnManagerService.systemReady();
+
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
mQosCallbackTracker = mock(QosCallbackTracker.class);
@@ -3058,6 +3021,43 @@
}
@Test
+ public void testNetworkDoesntMatchRequestsUntilConnected() throws Exception {
+ final TestNetworkCallback cb = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.requestNetwork(wifiRequest, cb);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ // Updating the score triggers a rematch.
+ mWiFiNetworkAgent.setScore(new NetworkScore.Builder().build());
+ cb.assertNoCallback();
+ mWiFiNetworkAgent.connect(false);
+ cb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ cb.assertNoCallback();
+ mCm.unregisterNetworkCallback(cb);
+ }
+
+ @Test
+ public void testNetworkNotVisibleUntilConnected() throws Exception {
+ final TestNetworkCallback cb = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, cb);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ final NetworkCapabilities nc = mWiFiNetworkAgent.getNetworkCapabilities();
+ nc.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ mWiFiNetworkAgent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
+ cb.assertNoCallback();
+ mWiFiNetworkAgent.connect(false);
+ cb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ final CallbackEntry found = CollectionUtils.findLast(cb.getHistory(),
+ it -> it instanceof CallbackEntry.CapabilitiesChanged);
+ assertTrue(((CallbackEntry.CapabilitiesChanged) found).getCaps()
+ .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ cb.assertNoCallback();
+ mCm.unregisterNetworkCallback(cb);
+ }
+
+ @Test
public void testStateChangeNetworkCallbacks() throws Exception {
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
@@ -6200,7 +6200,7 @@
}
// Helper method to prepare the executor and run test
- private void runTestWithSerialExecutors(ExceptionUtils.ThrowingConsumer<Executor> functor)
+ private void runTestWithSerialExecutors(ThrowingConsumer<Executor> functor)
throws Exception {
final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
final Executor executorInline = (Runnable r) -> r.run();
@@ -8465,12 +8465,8 @@
doReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)).when(mPackageManager)
.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER);
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-
- // Send a USER_ADDED broadcast for it.
- processBroadcast(addedIntent);
+ // New user added
+ mMockVpn.onUserAdded(RESTRICTED_USER);
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user.
@@ -8494,11 +8490,8 @@
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
- // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(removedIntent);
+ // User removed and expect to lose the UID range for the restricted user.
+ mMockVpn.onUserRemoved(RESTRICTED_USER);
// Expect that the VPN gains the UID range for the restricted user, and that the capability
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
@@ -8551,6 +8544,7 @@
doReturn(asList(PRIMARY_USER_INFO, RESTRICTED_USER_INFO)).when(mUserManager)
.getAliveUsers();
// TODO: check that VPN app within restricted profile still has access, etc.
+ mMockVpn.onUserAdded(RESTRICTED_USER);
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
@@ -8562,6 +8556,7 @@
doReturn(asList(PRIMARY_USER_INFO)).when(mUserManager).getAliveUsers();
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+ mMockVpn.onUserRemoved(RESTRICTED_USER);
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
@@ -9257,7 +9252,7 @@
doAsUid(Process.SYSTEM_UID, () -> mCm.unregisterNetworkCallback(perUidCb));
}
- private void setupLegacyLockdownVpn() {
+ private VpnProfile setupLegacyLockdownVpn() {
final String profileName = "testVpnProfile";
final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
doReturn(profileTag).when(mVpnProfileStore).get(Credentials.LOCKDOWN_VPN);
@@ -9269,6 +9264,8 @@
profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
final byte[] encodedProfile = profile.encode();
doReturn(encodedProfile).when(mVpnProfileStore).get(Credentials.VPN + profileName);
+
+ return profile;
}
private void establishLegacyLockdownVpn(Network underlying) throws Exception {
@@ -9301,21 +9298,28 @@
new Handler(ConnectivityThread.getInstanceLooper()));
// Pretend lockdown VPN was configured.
- setupLegacyLockdownVpn();
+ final VpnProfile profile = setupLegacyLockdownVpn();
// LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
// Check the VPN's state before it does so.
assertTrue(mMockVpn.getEnableTeardown());
assertFalse(mMockVpn.getLockdown());
- // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
- final int userId = UserHandle.getUserId(Process.myUid());
- final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- processBroadcast(addedIntent);
+ // VMSHandlerThread was used inside VpnManagerService and taken into LockDownVpnTracker.
+ // VpnManagerService was decoupled from this test but this handlerThread is still required
+ // in LockDownVpnTracker. Keep it until LockDownVpnTracker related verification is moved to
+ // its own test.
+ final HandlerThread VMSHandlerThread = new HandlerThread("TestVpnManagerService");
+ VMSHandlerThread.start();
+ // LockdownVpnTracker is created from VpnManagerService but VpnManagerService is decoupled
+ // from ConnectivityServiceTest. Create it directly to simulate LockdownVpnTracker is
+ // created.
+ // TODO: move LockdownVpnTracker related tests to its own test.
// Lockdown VPN disables teardown and enables lockdown.
+ final LockdownVpnTracker lockdownVpnTracker = new LockdownVpnTracker(mServiceContext,
+ VMSHandlerThread.getThreadHandler(), mMockVpn, profile);
+ lockdownVpnTracker.init();
assertFalse(mMockVpn.getEnableTeardown());
assertTrue(mMockVpn.getLockdown());
@@ -9485,6 +9489,8 @@
mMockVpn.expectStopVpnRunnerPrivileged();
callback.expectCallback(CallbackEntry.LOST, mMockVpn);
b2.expectBroadcast();
+
+ VMSHandlerThread.quitSafely();
}
@Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -15752,7 +15758,7 @@
final UserHandle testHandle = setupEnterpriseNetwork();
final TestOnCompleteListener listener = new TestOnCompleteListener();
// Leave one request available so the profile preference can be set.
- testRequestCountLimits(1 /* countToLeaveAvailable */, () -> {
+ withRequestCountersAcquired(1 /* countToLeaveAvailable */, () -> {
withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
Process.myPid(), Process.myUid(), () -> {
// Set initially to test the limit prior to having existing requests.
@@ -15766,7 +15772,7 @@
final int otherAppUid = UserHandle.getUid(TEST_WORK_PROFILE_USER_ID,
UserHandle.getAppId(Process.myUid() + 1));
final int remainingCount = ConnectivityService.MAX_NETWORK_REQUESTS_PER_UID
- - mService.mNetworkRequestCounter.mUidToNetworkRequestCount.get(otherAppUid)
+ - mService.mNetworkRequestCounter.get(otherAppUid)
- 1;
final NetworkCallback[] callbacks = new NetworkCallback[remainingCount];
doAsUid(otherAppUid, () -> {
@@ -15801,7 +15807,7 @@
@OemNetworkPreferences.OemNetworkPreference final int networkPref =
OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
// Leave one request available so the OEM preference can be set.
- testRequestCountLimits(1 /* countToLeaveAvailable */, () ->
+ withRequestCountersAcquired(1 /* countToLeaveAvailable */, () ->
withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
// Set initially to test the limit prior to having existing requests.
final TestOemListenerCallback listener = new TestOemListenerCallback();
@@ -15816,12 +15822,11 @@
}));
}
- private void testRequestCountLimits(final int countToLeaveAvailable,
- @NonNull final ExceptionalRunnable r) throws Exception {
+ private void withRequestCountersAcquired(final int countToLeaveAvailable,
+ @NonNull final ThrowingRunnable r) throws Exception {
final ArraySet<TestNetworkCallback> callbacks = new ArraySet<>();
try {
- final int requestCount = mService.mSystemNetworkRequestCounter
- .mUidToNetworkRequestCount.get(Process.myUid());
+ final int requestCount = mService.mSystemNetworkRequestCounter.get(Process.myUid());
// The limit is hit when total requests = limit - 1, and exceeded with a crash when
// total requests >= limit.
final int countToFile =
@@ -15834,8 +15839,7 @@
callbacks.add(cb);
}
assertEquals(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - 1 - countToLeaveAvailable,
- mService.mSystemNetworkRequestCounter
- .mUidToNetworkRequestCount.get(Process.myUid()));
+ mService.mSystemNetworkRequestCounter.get(Process.myUid()));
});
// Code to run to check if it triggers a max request count limit error.
r.run();
@@ -16084,7 +16088,7 @@
ConnectivitySettingsManager.setMobileDataPreferredUids(mServiceContext,
Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
// Leave one request available so MDO preference set up above can be set.
- testRequestCountLimits(1 /* countToLeaveAvailable */, () ->
+ withRequestCountersAcquired(1 /* countToLeaveAvailable */, () ->
withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
Process.myPid(), Process.myUid(), () -> {
// Set initially to test the limit prior to having existing requests.
diff --git a/tests/unit/java/com/android/server/NetIdManagerTest.kt b/tests/unit/java/com/android/server/NetIdManagerTest.kt
index 811134e..f2b14a1 100644
--- a/tests/unit/java/com/android/server/NetIdManagerTest.kt
+++ b/tests/unit/java/com/android/server/NetIdManagerTest.kt
@@ -21,7 +21,7 @@
import com.android.server.NetIdManager.MIN_NET_ID
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
+import com.android.testutils.FunctionalUtils.ThrowingRunnable
import com.android.testutils.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 1813393..5808beb 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -536,6 +536,25 @@
.onResolveFailed(any(), eq(FAILURE_INTERNAL_ERROR));
}
+ @Test
+ public void testNoCrashWhenProcessResolutionAfterBinderDied() throws Exception {
+ final NsdManager client = connectClient(mService);
+ final INsdManagerCallback cb = getCallback();
+ final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb);
+ deathRecipient.binderDied();
+
+ final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE);
+ final ResolveListener resolveListener = mock(ResolveListener.class);
+ client.resolveService(request, resolveListener);
+ waitForIdle();
+
+ verify(mMockMDnsM, never()).registerEventListener(any());
+ verify(mMockMDnsM, never()).startDaemon();
+ verify(mMockMDnsM, never()).resolve(anyInt() /* id */, anyString() /* serviceName */,
+ anyString() /* registrationType */, anyString() /* domain */,
+ anyInt()/* interfaceIdx */);
+ }
+
private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
}
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 041e4ea..1fda04e 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -92,6 +92,7 @@
import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.Network;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
@@ -264,6 +265,7 @@
final Ikev2VpnProfile.Builder builder =
new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
builder.setAuthPsk(TEST_VPN_PSK);
+ builder.setBypassable(true /* isBypassable */);
mVpnProfile = builder.build().toVpnProfile();
}
@@ -968,31 +970,6 @@
AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
- private void setAppOpsPermission() {
- doAnswer(invocation -> {
- when(mAppOps.noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN,
- Process.myUid(), TEST_VPN_PKG,
- null /* attributionTag */, null /* message */))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- return null;
- }).when(mAppOps).setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
- }
-
- @Test
- public void testProvisionVpnProfileNotPreconsented_withControlVpnPermission() throws Exception {
- setAppOpsPermission();
- doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- // ACTIVATE_PLATFORM_VPN will be granted if VPN app has CONTROL_VPN permission.
- checkProvisionVpnProfile(vpn, true /* expectedResult */,
- AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
- }
-
@Test
public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
@@ -1787,9 +1764,11 @@
ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
+ ArgumentCaptor<NetworkAgentConfig> nacCaptor =
+ ArgumentCaptor.forClass(NetworkAgentConfig.class);
verify(mTestDeps).newNetworkAgent(
any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
- any(), any(), any());
+ any(), nacCaptor.capture(), any());
// Check LinkProperties
final LinkProperties lp = lpCaptor.getValue();
@@ -1811,6 +1790,9 @@
// Check NetworkCapabilities
assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
+ // Check if allowBypass is set or not.
+ assertTrue(nacCaptor.getValue().isBypassableVpn());
+
return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
}
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
index 503d920..aad80d5 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
@@ -38,9 +37,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
-import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkSpecifier;
-import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.IpConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -55,7 +52,6 @@
import android.net.ip.IpClientManager;
import android.os.Build;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.test.TestLooper;
@@ -74,9 +70,6 @@
import org.mockito.MockitoAnnotations;
import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(DevSdkIgnoreRunner.class)
@@ -84,7 +77,6 @@
public class EthernetNetworkFactoryTest {
private static final int TIMEOUT_MS = 2_000;
private static final String TEST_IFACE = "test123";
- private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
private static final String IP_ADDR = "192.0.2.2/25";
private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR);
private static final String HW_ADDR = "01:02:03:04:05:06";
@@ -241,7 +233,7 @@
final IpConfiguration ipConfig = createDefaultIpConfig();
mNetFactory.addInterface(iface, HW_ADDR, ipConfig,
createInterfaceCapsBuilder(transportType).build());
- assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
+ assertTrue(mNetFactory.updateInterfaceLinkState(iface, true));
ArgumentCaptor<NetworkOfferCallback> captor = ArgumentCaptor.forClass(
NetworkOfferCallback.class);
@@ -295,7 +287,7 @@
// then calling onNetworkUnwanted.
mNetFactory.addInterface(iface, HW_ADDR, createDefaultIpConfig(),
createInterfaceCapsBuilder(NetworkCapabilities.TRANSPORT_ETHERNET).build());
- assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
+ assertTrue(mNetFactory.updateInterfaceLinkState(iface, true));
clearInvocations(mIpClient);
clearInvocations(mNetworkAgent);
@@ -305,81 +297,63 @@
public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception {
initEthernetNetworkFactory();
createInterfaceUndergoingProvisioning(TEST_IFACE);
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
// verify that the IpClient gets shut down when interface state changes to down.
- final boolean ret =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
+ final boolean ret = mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */);
assertTrue(ret);
verify(mIpClient).shutdown();
- assertEquals(TEST_IFACE, listener.expectOnResult());
}
@Test
public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception {
initEthernetNetworkFactory();
createAndVerifyProvisionedInterface(TEST_IFACE);
- final TestNetworkManagementListener listenerDown = new TestNetworkManagementListener();
- final TestNetworkManagementListener listenerUp = new TestNetworkManagementListener();
- final boolean retDown =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listenerDown);
+ final boolean retDown = mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */);
assertTrue(retDown);
verifyStop();
- assertEquals(TEST_IFACE, listenerDown.expectOnResult());
- final boolean retUp =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listenerUp);
+ final boolean retUp = mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */);
assertTrue(retUp);
- assertEquals(TEST_IFACE, listenerUp.expectOnResult());
}
@Test
public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception {
initEthernetNetworkFactory();
createUnprovisionedInterface(TEST_IFACE);
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
- final boolean ret =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
+ final boolean ret = mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */);
assertTrue(ret);
// There should not be an active IPClient or NetworkAgent.
verify(mDeps, never()).makeIpClient(any(), any(), any());
verify(mDeps, never())
.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
- assertEquals(TEST_IFACE, listener.expectOnResult());
}
@Test
public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception {
initEthernetNetworkFactory();
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
// if interface was never added, link state cannot be updated.
- final boolean ret =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
+ final boolean ret = mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */);
assertFalse(ret);
verifyNoStopOrStart();
- listener.expectOnError();
}
@Test
public void testUpdateInterfaceLinkStateWithNoChanges() throws Exception {
initEthernetNetworkFactory();
createAndVerifyProvisionedInterface(TEST_IFACE);
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
- final boolean ret =
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
+ final boolean ret = mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */);
assertFalse(ret);
verifyNoStopOrStart();
- listener.expectOnError();
}
@Test
@@ -571,127 +545,16 @@
verify(mNetworkAgent).markConnected();
}
- private static final class TestNetworkManagementListener
- implements INetworkInterfaceOutcomeReceiver {
- private final CompletableFuture<String> mResult = new CompletableFuture<>();
-
- @Override
- public void onResult(@NonNull String iface) {
- mResult.complete(iface);
- }
-
- @Override
- public void onError(@NonNull EthernetNetworkManagementException exception) {
- mResult.completeExceptionally(exception);
- }
-
- String expectOnResult() throws Exception {
- return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- void expectOnError() throws Exception {
- assertThrows(EthernetNetworkManagementException.class, () -> {
- try {
- mResult.get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
- });
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
- }
-
- @Test
- public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception {
- initEthernetNetworkFactory();
- createAndVerifyProvisionedInterface(TEST_IFACE);
- final NetworkCapabilities capabilities = createDefaultFilterCaps();
- final IpConfiguration ipConfiguration = createStaticIpConfig();
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
-
- mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
- triggerOnProvisioningSuccess();
-
- assertEquals(TEST_IFACE, listener.expectOnResult());
- }
-
- @Test
- public void testUpdateInterfaceAbortsOnConcurrentRemoveInterface() throws Exception {
- initEthernetNetworkFactory();
- verifyNetworkManagementCallIsAbortedWhenInterrupted(
- TEST_IFACE,
- () -> mNetFactory.removeInterface(TEST_IFACE));
- }
-
- @Test
- public void testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState() throws Exception {
- initEthernetNetworkFactory();
- verifyNetworkManagementCallIsAbortedWhenInterrupted(
- TEST_IFACE,
- () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER));
- }
-
- @Test
- public void testUpdateInterfaceAbortsOnNetworkUneededRemovesAllRequests() throws Exception {
- initEthernetNetworkFactory();
- verifyNetworkManagementCallIsAbortedWhenInterrupted(
- TEST_IFACE,
- () -> mNetworkOfferCallback.onNetworkUnneeded(mRequestToKeepNetworkUp));
- }
-
- @Test
- public void testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests() throws Exception {
- initEthernetNetworkFactory();
- final NetworkCapabilities capabilities = createDefaultFilterCaps();
- final IpConfiguration ipConfiguration = createStaticIpConfig();
- final TestNetworkManagementListener successfulListener =
- new TestNetworkManagementListener();
-
- // If two calls come in before the first one completes, the first listener will be aborted
- // and the second one will be successful.
- verifyNetworkManagementCallIsAbortedWhenInterrupted(
- TEST_IFACE,
- () -> {
- mNetFactory.updateInterface(
- TEST_IFACE, ipConfiguration, capabilities, successfulListener);
- triggerOnProvisioningSuccess();
- });
-
- assertEquals(successfulListener.expectOnResult(), TEST_IFACE);
- assertEquals(TEST_IFACE, successfulListener.expectOnResult());
- }
-
- private void verifyNetworkManagementCallIsAbortedWhenInterrupted(
- @NonNull final String iface,
- @NonNull final Runnable interruptingRunnable) throws Exception {
- createAndVerifyProvisionedInterface(iface);
- final NetworkCapabilities capabilities = createDefaultFilterCaps();
- final IpConfiguration ipConfiguration = createStaticIpConfig();
- final TestNetworkManagementListener failedListener = new TestNetworkManagementListener();
-
- // An active update request will be aborted on interrupt prior to provisioning completion.
- mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener);
- interruptingRunnable.run();
-
- failedListener.expectOnError();
- }
-
@Test
public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception {
initEthernetNetworkFactory();
createAndVerifyProvisionedInterface(TEST_IFACE);
final NetworkCapabilities capabilities = createDefaultFilterCaps();
final IpConfiguration ipConfiguration = createStaticIpConfig();
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
- mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
+ mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities);
triggerOnProvisioningSuccess();
- assertEquals(TEST_IFACE, listener.expectOnResult());
verify(mDeps).makeEthernetNetworkAgent(any(), any(),
eq(capabilities), any(), any(), any(), any());
verifyRestart(ipConfiguration);
@@ -703,12 +566,10 @@
// No interface exists due to not calling createAndVerifyProvisionedInterface(...).
final NetworkCapabilities capabilities = createDefaultFilterCaps();
final IpConfiguration ipConfiguration = createStaticIpConfig();
- final TestNetworkManagementListener listener = new TestNetworkManagementListener();
- mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
+ mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities);
verifyNoStopOrStart();
- listener.expectOnError();
}
@Test
@@ -717,8 +578,8 @@
createAndVerifyProvisionedInterface(TEST_IFACE);
final IpConfiguration initialIpConfig = createStaticIpConfig();
- mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/,
- null /*listener*/);
+ mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/);
+
triggerOnProvisioningSuccess();
verifyRestart(initialIpConfig);
@@ -729,8 +590,7 @@
// verify that sending a null ipConfig does not update the current ipConfig.
- mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/,
- null /*listener*/);
+ mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/);
triggerOnProvisioningSuccess();
verifyRestart(initialIpConfig);
}
@@ -739,7 +599,7 @@
public void testOnNetworkNeededOnStaleNetworkOffer() throws Exception {
initEthernetNetworkFactory();
createAndVerifyProvisionedInterface(TEST_IFACE);
- mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, null);
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, false);
verify(mNetworkProvider).unregisterNetworkOffer(mNetworkOfferCallback);
// It is possible that even after a network offer is unregistered, CS still sends it
// onNetworkNeeded() callbacks.
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
index a1d93a0..9bf893a 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -209,7 +210,8 @@
NULL_LISTENER);
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getIpConfiguration()),
- eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()), isNull());
+ eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()),
+ any(EthernetCallback.class));
}
private void denyManageEthPermission() {
@@ -285,7 +287,8 @@
verify(mEthernetTracker).updateConfiguration(
eq(TEST_IFACE),
eq(UPDATE_REQUEST.getIpConfiguration()),
- eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER));
+ eq(UPDATE_REQUEST.getNetworkCapabilities()),
+ any(EthernetCallback.class));
}
@Test
@@ -303,19 +306,20 @@
verify(mEthernetTracker).updateConfiguration(
eq(TEST_IFACE),
isNull(),
- eq(ncWithSpecifier), eq(NULL_LISTENER));
+ eq(ncWithSpecifier), any(EthernetCallback.class));
}
@Test
public void testEnableInterface() {
mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
- verify(mEthernetTracker).enableInterface(eq(TEST_IFACE), eq(NULL_LISTENER));
+ verify(mEthernetTracker).enableInterface(eq(TEST_IFACE),
+ any(EthernetCallback.class));
}
@Test
public void testDisableInterface() {
mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
- verify(mEthernetTracker).disableInterface(eq(TEST_IFACE), eq(NULL_LISTENER));
+ verify(mEthernetTracker).disableInterface(eq(TEST_IFACE), any(EthernetCallback.class));
}
@Test
@@ -328,7 +332,7 @@
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
eq(request.getIpConfiguration()),
- eq(request.getNetworkCapabilities()), isNull());
+ eq(request.getNetworkCapabilities()), any(EthernetCallback.class));
}
@Test
@@ -337,7 +341,8 @@
NULL_LISTENER);
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getIpConfiguration()),
- eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()), isNull());
+ eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()),
+ any(EthernetCallback.class));
}
@Test
@@ -369,7 +374,7 @@
verify(mEthernetTracker).updateConfiguration(
eq(TEST_IFACE),
eq(request.getIpConfiguration()),
- eq(request.getNetworkCapabilities()), eq(NULL_LISTENER));
+ eq(request.getNetworkCapabilities()), any(EthernetCallback.class));
}
@Test
@@ -379,7 +384,8 @@
denyManageEthPermission();
mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
- verify(mEthernetTracker).enableInterface(eq(TEST_IFACE), eq(NULL_LISTENER));
+ verify(mEthernetTracker).enableInterface(eq(TEST_IFACE),
+ any(EthernetCallback.class));
}
@Test
@@ -389,7 +395,8 @@
denyManageEthPermission();
mEthernetServiceImpl.disableInterface(TEST_IFACE, NULL_LISTENER);
- verify(mEthernetTracker).disableInterface(eq(TEST_IFACE), eq(NULL_LISTENER));
+ verify(mEthernetTracker).disableInterface(eq(TEST_IFACE),
+ any(EthernetCallback.class));
}
private void denyPermissions(String... permissions) {
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
index 0376a2a..082a016 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -39,7 +39,6 @@
import android.net.EthernetManager;
import android.net.IEthernetServiceListener;
import android.net.INetd;
-import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
import android.net.IpConfiguration;
@@ -76,7 +75,7 @@
private static final String TEST_IFACE = "test123";
private static final int TIMEOUT_MS = 1_000;
private static final String THREAD_NAME = "EthernetServiceThread";
- private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
+ private static final EthernetCallback NULL_CB = new EthernetCallback(null);
private EthernetTracker tracker;
private HandlerThread mHandlerThread;
@Mock private Context mContext;
@@ -88,7 +87,7 @@
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
initMockResources();
- when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean(), any())).thenReturn(false);
+ when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean())).thenReturn(false);
when(mNetd.interfaceGetList()).thenReturn(new String[0]);
mHandlerThread = new HandlerThread(THREAD_NAME);
mHandlerThread.start();
@@ -344,31 +343,29 @@
new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build();
final IpConfiguration ipConfig =
new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build();
- final INetworkInterfaceOutcomeReceiver listener = null;
+ final EthernetCallback listener = new EthernetCallback(null);
tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener);
waitForIdle();
verify(mFactory).updateInterface(
- eq(TEST_IFACE), eq(ipConfig), eq(capabilities), eq(listener));
+ eq(TEST_IFACE), eq(ipConfig), eq(capabilities));
}
@Test
public void testEnableInterfaceCorrectlyCallsFactory() {
- tracker.enableInterface(TEST_IFACE, NULL_LISTENER);
+ tracker.enableInterface(TEST_IFACE, NULL_CB);
waitForIdle();
- verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(true /* up */),
- eq(NULL_LISTENER));
+ verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(true /* up */));
}
@Test
public void testDisableInterfaceCorrectlyCallsFactory() {
- tracker.disableInterface(TEST_IFACE, NULL_LISTENER);
+ tracker.disableInterface(TEST_IFACE, NULL_CB);
waitForIdle();
- verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */),
- eq(NULL_LISTENER));
+ verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */));
}
@Test
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index f64e35b..be44946 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -122,6 +122,7 @@
import android.system.ErrnoException;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -130,8 +131,10 @@
import com.android.connectivity.resources.R;
import com.android.internal.util.FileRotator;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.net.module.util.BpfDump;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.LocationPermissionChecker;
+import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.U32;
import com.android.net.module.util.Struct.U8;
import com.android.net.module.util.bpf.CookieTagMapKey;
@@ -168,6 +171,7 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -212,6 +216,11 @@
private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
private static final int INVALID_TYPE = -1;
+ private static final String DUMPSYS_BPF_RAW_MAP = "--bpfRawMap";
+ private static final String DUMPSYS_COOKIE_TAG_MAP = "--cookieTagMap";
+ private static final String LINE_DELIMITER = "\\n";
+
+
private long mElapsedRealtime;
private File mStatsDir;
@@ -346,9 +355,9 @@
mElapsedRealtime = 0L;
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
// Verify that system ready fetches realtime stats
verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
@@ -505,10 +514,10 @@
private void initWifiStats(NetworkStateSnapshot snapshot) throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {snapshot};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
@@ -517,10 +526,10 @@
private void incrementWifiStats(long durationMillis, String iface,
long rxb, long rxp, long txb, long txp) throws Exception {
incrementCurrentTime(durationMillis);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(iface, rxb, rxp, txb, txp));
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
}
@@ -586,10 +595,10 @@
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
@@ -600,10 +609,10 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
@@ -631,14 +640,14 @@
// graceful shutdown system, which should trigger persist of stats, and
// clear any values in memory.
- expectDefaultSettings();
+ mockDefaultSettings();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
assertStatsFilesExist(true);
// boot through serviceReady() again
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
@@ -663,20 +672,20 @@
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+ mockSettings(HOUR_IN_MILLIS, WEEK_IN_MILLIS);
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockSettings(HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 512L, 4L, 512L, 4L));
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
// verify service recorded history
@@ -688,9 +697,9 @@
// now change bucket duration setting and trigger another poll with
// exact same values, which should resize existing buckets.
- expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockSettings(30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
// verify identical stats, but spread across 4 buckets now
@@ -704,20 +713,20 @@
@Test
public void testUidStatsAcrossNetworks() throws Exception {
// pretend first mobile network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobileState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
@@ -735,11 +744,11 @@
// now switch networks; this also tests that we're okay with interfaces
// disappearing, to verify we don't count backwards.
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
+ mockDefaultSettings();
states = new NetworkStateSnapshot[] {buildMobileState(IMSI_2)};
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
@@ -751,10 +760,10 @@
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 2176L, 17L, 1536L, 12L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
@@ -779,20 +788,20 @@
@Test
public void testUidRemovedIsMoved() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
@@ -811,10 +820,10 @@
// now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket.
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
@@ -851,8 +860,8 @@
new NetworkStateSnapshot[]{buildMobileState(IMSI_1)};
// 3G network comes online.
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
@@ -860,7 +869,7 @@
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L, 18L, 14L, 1L, 0L)));
forcePollAndWaitForIdle();
@@ -874,7 +883,7 @@
// 4G network comes online.
incrementCurrentTime(MINUTE_IN_MILLIS);
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
// Append more traffic on existing 3g stats entry.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16L, 22L, 17L, 2L, 0L))
@@ -894,7 +903,7 @@
// 5g network comes online.
incrementCurrentTime(MINUTE_IN_MILLIS);
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
// Existing stats remains.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16L, 22L, 17L, 2L, 0L))
@@ -925,9 +934,9 @@
.setRatType(TelephonyManager.NETWORK_TYPE_NR)
.setMeteredness(METERED_NO).build();
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
// Pretend that 5g mobile network comes online
final NetworkStateSnapshot[] mobileStates =
@@ -942,7 +951,7 @@
// and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
// They are layered on top by inspecting the iface properties.
incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
.insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
@@ -975,14 +984,14 @@
NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
buildOemManagedMobileState(IMSI_1, false,
new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 36L, 41L, 24L, 96L, 0L)));
forcePollAndWaitForIdle();
@@ -990,14 +999,14 @@
// OEM_PRIVATE network comes online.
states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 49L, 71L, 72L, 48L, 0L)));
forcePollAndWaitForIdle();
@@ -1006,28 +1015,28 @@
states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 57L, 86L, 83L, 93L, 0L)));
forcePollAndWaitForIdle();
// OEM_NONE network comes online.
states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 29L, 73L, 34L, 31L, 0L)));
forcePollAndWaitForIdle();
@@ -1070,19 +1079,19 @@
@Test
public void testSummaryForAllUid() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
@@ -1097,9 +1106,9 @@
// now create more traffic in next hour, but only for one app
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
@@ -1129,10 +1138,10 @@
@Test
public void testGetLatestSummary() throws Exception {
// Pretend that network comes online.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
@@ -1142,8 +1151,8 @@
NetworkStats.Entry entry = new NetworkStats.Entry(
TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 50L, 5L, 51L, 1L, 3L);
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1).insertEntry(entry));
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1).insertEntry(entry));
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
// Verify the mocked stats is returned by querying with the range of the latest bucket.
@@ -1166,10 +1175,10 @@
@Test
public void testUidStatsForTransport() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
@@ -1185,9 +1194,9 @@
DEFAULT_NETWORK_NO, 1024L, 8L, 512L, 4L, 0L);
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
.insertEntry(entry1)
.insertEntry(entry2)
.insertEntry(entry3));
@@ -1209,19 +1218,19 @@
@Test
public void testForegroundBackground() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
@@ -1234,9 +1243,9 @@
// now switch to foreground
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
@@ -1268,23 +1277,23 @@
@Test
public void testMetered() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states =
new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
// and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
// We layer them on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
@@ -1308,24 +1317,24 @@
@Test
public void testRoaming() throws Exception {
// pretend that network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states =
new NetworkStateSnapshot[] {buildMobileState(TEST_IFACE, IMSI_1,
false /* isTemporarilyNotMetered */, true /* isRoaming */)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO and
// ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
// on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
@@ -1348,18 +1357,18 @@
@Test
public void testTethering() throws Exception {
// pretend first mobile network comes online
- expectDefaultSettings();
+ mockDefaultSettings();
final NetworkStateSnapshot[] states =
new NetworkStateSnapshot[]{buildMobileState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
+ mockDefaultSettings();
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1391,8 +1400,8 @@
final TetherStatsParcel[] tetherStatsParcels =
{buildTetherStatsParcel(TEST_IFACE, 1408L, 10L, 256L, 1L, 0)};
- expectNetworkStatsSummary(swIfaceStats);
- expectNetworkStatsUidDetail(localUidStats, tetherStatsParcels);
+ mockNetworkStatsSummary(swIfaceStats);
+ mockNetworkStatsUidDetail(localUidStats, tetherStatsParcels);
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1405,10 +1414,10 @@
public void testRegisterUsageCallback() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
@@ -1420,9 +1429,9 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
// Force poll
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockDefaultSettings();
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
// Register and verify request and that binder was called
DataUsageRequest request = mService.registerUsageCallback(
@@ -1440,10 +1449,10 @@
// modify some number on wifi, and trigger poll event
// not enough traffic to call data usage callback
incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L));
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1455,10 +1464,10 @@
// and bump forward again, with counters going higher. this is
// important, since it will trigger the data usage callback
incrementCurrentTime(DAY_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockDefaultSettings();
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1495,11 +1504,11 @@
@Test
public void testStatsProviderUpdateStats() throws Exception {
// Pretend that network comes online.
- expectDefaultSettings();
+ mockDefaultSettings();
final NetworkStateSnapshot[] states =
new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1528,7 +1537,7 @@
// Make another empty mutable stats object. This is necessary since the new NetworkStats
// object will be used to compare with the old one in NetworkStatsRecoder, two of them
// cannot be the same object.
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
@@ -1557,14 +1566,14 @@
@Test
public void testDualVilteProviderStats() throws Exception {
// Pretend that network comes online.
- expectDefaultSettings();
+ mockDefaultSettings();
final int subId1 = 1;
final int subId2 = 2;
final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
buildImsState(IMSI_1, subId1, TEST_IFACE),
buildImsState(IMSI_2, subId2, TEST_IFACE2)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1595,7 +1604,7 @@
// Make another empty mutable stats object. This is necessary since the new NetworkStats
// object will be used to compare with the old one in NetworkStatsRecoder, two of them
// cannot be the same object.
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
@@ -1628,7 +1637,7 @@
@Test
public void testStatsProviderSetAlert() throws Exception {
// Pretend that network comes online.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states =
new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
@@ -1678,8 +1687,8 @@
final NetworkStateSnapshot[] states =
new NetworkStateSnapshot[]{buildMobileState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsSummary(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
// 3G network comes online.
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
@@ -1688,7 +1697,7 @@
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L, 18L, 14L, 1L, 0L)));
forcePollAndWaitForIdle();
@@ -1712,7 +1721,7 @@
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
// Append more traffic on existing snapshot.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L + 4L, 18L + 4L, 14L + 3L,
1L + 1L, 0L))
@@ -1735,7 +1744,7 @@
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
// Append more traffic on existing snapshot.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 22L, 26L, 19L, 5L, 0L))
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
@@ -1752,16 +1761,16 @@
@Test
public void testOperationCount_nonDefault_traffic() throws Exception {
// Pretend mobile network comes online, but wifi is the default network.
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobileState(IMSI_1)};
- expectNetworkStatsUidDetail(buildEmptyStats());
+ mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic on mobile network.
incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 2L, 1L, 3L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
@@ -1834,7 +1843,7 @@
@Test
public void testDataMigration() throws Exception {
assertStatsFilesExist(false);
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
@@ -1843,10 +1852,9 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- // expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
@@ -1883,9 +1891,9 @@
getLegacyCollection(PREFIX_UID_TAG, true /* includeTags */));
// Mock zero usage and boot through serviceReady(), verify there is no imported data.
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
assertStatsFilesExist(false);
@@ -1896,9 +1904,9 @@
assertStatsFilesExist(false);
// Boot through systemReady() again.
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
// After systemReady(), the service should have historical stats loaded again.
@@ -1919,7 +1927,7 @@
@Test
public void testDataMigration_differentFromFallback() throws Exception {
assertStatsFilesExist(false);
- expectDefaultSettings();
+ mockDefaultSettings();
NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{buildWifiState()};
@@ -1928,9 +1936,9 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
forcePollAndWaitForIdle();
// Simulate shutdown to force persisting data
@@ -1971,9 +1979,9 @@
getLegacyCollection(PREFIX_UID_TAG, true /* includeTags */));
// Mock zero usage and boot through serviceReady(), verify there is no imported data.
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
assertStatsFilesExist(false);
@@ -1984,9 +1992,9 @@
assertStatsFilesExist(false);
// Boot through systemReady() again.
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
+ mockDefaultSettings();
+ mockNetworkStatsUidDetail(buildEmptyStats());
+ prepareForSystemReady();
mService.systemReady();
// Verify the result read from public API matches the result returned from the importer.
@@ -2081,8 +2089,8 @@
rxBytes, rxPackets, txBytes, txPackets, operations);
}
- private void expectSystemReady() throws Exception {
- expectNetworkStatsSummary(buildEmptyStats());
+ private void prepareForSystemReady() throws Exception {
+ mockNetworkStatsSummary(buildEmptyStats());
}
private String getActiveIface(NetworkStateSnapshot... states) throws Exception {
@@ -2092,27 +2100,25 @@
return states[0].getLinkProperties().getInterfaceName();
}
- // TODO: These expect* methods are used to have NetworkStatsService returns the given stats
- // instead of expecting anything. Therefore, these methods should be renamed properly.
- private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expectNetworkStatsSummaryDev(summary.clone());
- expectNetworkStatsSummaryXt(summary.clone());
+ private void mockNetworkStatsSummary(NetworkStats summary) throws Exception {
+ mockNetworkStatsSummaryDev(summary.clone());
+ mockNetworkStatsSummaryXt(summary.clone());
}
- private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
+ private void mockNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
when(mStatsFactory.readNetworkStatsSummaryDev()).thenReturn(summary);
}
- private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
+ private void mockNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
}
- private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
+ private void mockNetworkStatsUidDetail(NetworkStats detail) throws Exception {
final TetherStatsParcel[] tetherStatsParcels = {};
- expectNetworkStatsUidDetail(detail, tetherStatsParcels);
+ mockNetworkStatsUidDetail(detail, tetherStatsParcels);
}
- private void expectNetworkStatsUidDetail(NetworkStats detail,
+ private void mockNetworkStatsUidDetail(NetworkStats detail,
TetherStatsParcel[] tetherStatsParcels) throws Exception {
when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
.thenReturn(detail);
@@ -2121,12 +2127,11 @@
when(mNetd.tetherGetStats()).thenReturn(tetherStatsParcels);
}
- private void expectDefaultSettings() throws Exception {
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+ private void mockDefaultSettings() throws Exception {
+ mockSettings(HOUR_IN_MILLIS, WEEK_IN_MILLIS);
}
- private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
- throws Exception {
+ private void mockSettings(long bucketDuration, long deleteAge) throws Exception {
when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
when(mSettings.getPollDelay()).thenReturn(0L);
when(mSettings.getSampleEnabled()).thenReturn(true);
@@ -2333,12 +2338,27 @@
dump.contains(message));
}
- private String getDump() {
+ private String getDump(final String[] args) {
final StringWriter sw = new StringWriter();
- mService.dump(new FileDescriptor(), new PrintWriter(sw), new String[]{});
+ mService.dump(new FileDescriptor(), new PrintWriter(sw), args);
return sw.toString();
}
+ private String getDump() {
+ return getDump(new String[]{});
+ }
+
+ private <K extends Struct, V extends Struct> Map<K, V> parseBpfRawMap(
+ Class<K> keyClass, Class<V> valueClass, String dumpStr) {
+ final HashMap<K, V> map = new HashMap<>();
+ for (final String line : dumpStr.split(LINE_DELIMITER)) {
+ final Pair<K, V> keyValue =
+ BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
+ map.put(keyValue.first, keyValue.second);
+ }
+ return map;
+ }
+
@Test
public void testDumpCookieTagMap() throws ErrnoException {
initBpfMapsWithTagData(UID_BLUE);
@@ -2350,6 +2370,23 @@
}
@Test
+ public void testDumpCookieTagMapBpfRawMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump(new String[]{DUMPSYS_BPF_RAW_MAP, DUMPSYS_COOKIE_TAG_MAP});
+ Map<CookieTagMapKey, CookieTagMapValue> cookieTagMap = parseBpfRawMap(
+ CookieTagMapKey.class, CookieTagMapValue.class, dump);
+
+ final CookieTagMapValue val1 = cookieTagMap.get(new CookieTagMapKey(2002));
+ assertEquals(1, val1.tag);
+ assertEquals(1002, val1.uid);
+
+ final CookieTagMapValue val2 = cookieTagMap.get(new CookieTagMapKey(3002));
+ assertEquals(2, val2.tag);
+ assertEquals(1002, val2.uid);
+ }
+
+ @Test
public void testDumpUidCounterSetMap() throws ErrnoException {
initBpfMapsWithTagData(UID_BLUE);
diff --git a/tools/gen_jarjar.py b/tools/gen_jarjar.py
index 4c2cf54..2ff53fa 100755
--- a/tools/gen_jarjar.py
+++ b/tools/gen_jarjar.py
@@ -115,7 +115,8 @@
jar_classes = _list_jar_classes(jar)
jar_classes.sort()
for clazz in jar_classes:
- if (_get_toplevel_class(clazz) not in excluded_classes and
+ if (not clazz.startswith(args.prefix + '.') and
+ _get_toplevel_class(clazz) not in excluded_classes and
not any(r.fullmatch(clazz) for r in exclude_regexes)):
outfile.write(f'rule {clazz} {args.prefix}.@0\n')
# Also include jarjar rules for unit tests of the class, so the package matches
diff --git a/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java b/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java
new file mode 100644
index 0000000..6859020
--- /dev/null
+++ b/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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 jarjar.prefix;
+
+/**
+ * Sample class to test jarjar rules, already in the "jarjar.prefix" package.
+ */
+public class AlreadyInTargetPackageClass {
+ /** Test inner class that should not be jarjared either */
+ public static class TestInnerClass {}
+}