Merge "Improve count of openSession callers in dumpsys"
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index e73b7d5..3699f7a 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -59,6 +59,7 @@
import android.os.HandlerThread;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.VintfRuntimeInfo;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -84,6 +85,7 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DeviceInfoUtils;
import com.android.testutils.DumpTestUtils;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TapPacketReader;
@@ -1058,19 +1060,33 @@
}
@Test
- @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testTetherUdpV4WithoutBpf() throws Exception {
+ @IgnoreAfter(Build.VERSION_CODES.R)
+ public void testTetherUdpV4UpToR() throws Exception {
initializeTethering();
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
false /* usingBpf */);
}
+ private static boolean isUdpOffloadSupportedByKernel() {
+ final String kVersionString = VintfRuntimeInfo.getKernelVersion();
+ // Kernel version which is older than 4.14 doesn't support UDP offload absolutely. Kernel
+ // version which is between 4.14 and 5.8 support UDP offload probably. Simply apply kernel
+ // 4.14 to be threshold first and monitor on what devices tests fail for improving the
+ // offload support checking.
+ return DeviceInfoUtils.compareMajorMinorVersion(kVersionString, "4.14") >= 0;
+ }
+
@Test
@IgnoreUpTo(Build.VERSION_CODES.R)
- public void testTetherUdpV4WithBpf() throws Exception {
+ public void testTetherUdpV4AfterR() throws Exception {
initializeTethering();
+ boolean usingBpf = isUdpOffloadSupportedByKernel();
+ if (!usingBpf) {
+ Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
+ + VintfRuntimeInfo.getKernelVersion());
+ }
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
- true /* usingBpf */);
+ usingBpf);
}
@Nullable
diff --git a/bpf_progs/Android.bp b/bpf_progs/Android.bp
index 0e7b22d..6c78244 100644
--- a/bpf_progs/Android.bp
+++ b/bpf_progs/Android.bp
@@ -61,6 +61,7 @@
bpf {
name: "block.o",
srcs: ["block.c"],
+ btf: true,
cflags: [
"-Wall",
"-Werror",
@@ -71,6 +72,7 @@
bpf {
name: "dscp_policy.o",
srcs: ["dscp_policy.c"],
+ btf: true,
cflags: [
"-Wall",
"-Werror",
@@ -99,6 +101,7 @@
bpf {
name: "clatd.o",
srcs: ["clatd.c"],
+ btf: true,
cflags: [
"-Wall",
"-Werror",
@@ -112,6 +115,7 @@
bpf {
name: "netd.o",
srcs: ["netd.c"],
+ btf: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 92a774c..896bc09 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -355,88 +355,10 @@
DEFINE_BPF_MAP_GRW(tether_upstream4_map, HASH, Tether4Key, Tether4Value, 1024, AID_NETWORK_STACK)
-static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet,
- const bool downstream, const bool updatetime) {
- // Require ethernet dst mac address to be our unicast address.
- if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
-
- // Must be meta-ethernet IPv4 frame
- if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_PIPE;
-
- const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
-
- // Since the program never writes via DPA (direct packet access) auto-pull/unclone logic does
- // not trigger and thus we need to manually make sure we can read packet headers via DPA.
- // Note: this is a blind best effort pull, which may fail or pull less - this doesn't matter.
- // It has to be done early cause it will invalidate any skb->data/data_end derived pointers.
- try_make_writable(skb, l2_header_size + IP4_HLEN + TCP_HLEN);
-
- void* data = (void*)(long)skb->data;
- const void* data_end = (void*)(long)skb->data_end;
- struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
- struct iphdr* ip = is_ethernet ? (void*)(eth + 1) : data;
-
- // Must have (ethernet and) ipv4 header
- if (data + l2_header_size + sizeof(*ip) > data_end) return TC_ACT_PIPE;
-
- // Ethertype - if present - must be IPv4
- if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
-
- // IP version must be 4
- if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
-
- // We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
- if (ip->ihl != 5) TC_PUNT(HAS_IP_OPTIONS);
-
- // Calculate the IPv4 one's complement checksum of the IPv4 header.
- __wsum sum4 = 0;
- for (int i = 0; i < sizeof(*ip) / sizeof(__u16); ++i) {
- sum4 += ((__u16*)ip)[i];
- }
- // Note that sum4 is guaranteed to be non-zero by virtue of ip4->version == 4
- sum4 = (sum4 & 0xFFFF) + (sum4 >> 16); // collapse u32 into range 1 .. 0x1FFFE
- sum4 = (sum4 & 0xFFFF) + (sum4 >> 16); // collapse any potential carry into u16
- // for a correct checksum we should get *a* zero, but sum4 must be positive, ie 0xFFFF
- if (sum4 != 0xFFFF) TC_PUNT(CHECKSUM);
-
- // Minimum IPv4 total length is the size of the header
- if (ntohs(ip->tot_len) < sizeof(*ip)) TC_PUNT(TRUNCATED_IPV4);
-
- // We are incapable of dealing with IPv4 fragments
- if (ip->frag_off & ~htons(IP_DF)) TC_PUNT(IS_IP_FRAG);
-
- // Cannot decrement during forward if already zero or would be zero,
- // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
- if (ip->ttl <= 1) TC_PUNT(LOW_TTL);
-
- // If we cannot update the 'last_used' field due to lack of bpf_ktime_get_boot_ns() helper,
- // then it is not safe to offload UDP due to the small conntrack timeouts, as such,
- // in such a situation we can only support TCP. This also has the added nice benefit of
- // using a separate error counter, and thus making it obvious which version of the program
- // is loaded.
- if (!updatetime && ip->protocol != IPPROTO_TCP) TC_PUNT(NON_TCP);
-
- // We do not support offloading anything besides IPv4 TCP and UDP, due to need for NAT,
- // but no need to check this if !updatetime due to check immediately above.
- if (updatetime && (ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP))
- TC_PUNT(NON_TCP_UDP);
-
- // We want to make sure that the compiler will, in the !updatetime case, entirely optimize
- // out all the non-tcp logic. Also note that at this point is_udp === !is_tcp.
- const bool is_tcp = !updatetime || (ip->protocol == IPPROTO_TCP);
-
- // This is a bit of a hack to make things easier on the bpf verifier.
- // (In particular I believe the Linux 4.14 kernel's verifier can get confused later on about
- // what offsets into the packet are valid and can spuriously reject the program, this is
- // because it fails to realize that is_tcp && !is_tcp is impossible)
- //
- // For both TCP & UDP we'll need to read and modify the src/dst ports, which so happen to
- // always be in the first 4 bytes of the L4 header. Additionally for UDP we'll need access
- // to the checksum field which is in bytes 7 and 8. While for TCP we'll need to read the
- // TCP flags (at offset 13) and access to the checksum field (2 bytes at offset 16).
- // As such we *always* need access to at least 8 bytes.
- if (data + l2_header_size + sizeof(*ip) + 8 > data_end) TC_PUNT(SHORT_L4_HEADER);
-
+static inline __always_inline int do_forward4_bottom(struct __sk_buff* skb,
+ const int l2_header_size, void* data, const void* data_end,
+ struct ethhdr* eth, struct iphdr* ip, const bool is_ethernet,
+ const bool downstream, const bool updatetime, const bool is_tcp) {
struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL;
struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1);
@@ -625,6 +547,102 @@
return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
}
+static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet,
+ const bool downstream, const bool updatetime) {
+ // Require ethernet dst mac address to be our unicast address.
+ if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
+
+ // Must be meta-ethernet IPv4 frame
+ if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_PIPE;
+
+ const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
+
+ // Since the program never writes via DPA (direct packet access) auto-pull/unclone logic does
+ // not trigger and thus we need to manually make sure we can read packet headers via DPA.
+ // Note: this is a blind best effort pull, which may fail or pull less - this doesn't matter.
+ // It has to be done early cause it will invalidate any skb->data/data_end derived pointers.
+ try_make_writable(skb, l2_header_size + IP4_HLEN + TCP_HLEN);
+
+ void* data = (void*)(long)skb->data;
+ const void* data_end = (void*)(long)skb->data_end;
+ struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
+ struct iphdr* ip = is_ethernet ? (void*)(eth + 1) : data;
+
+ // Must have (ethernet and) ipv4 header
+ if (data + l2_header_size + sizeof(*ip) > data_end) return TC_ACT_PIPE;
+
+ // Ethertype - if present - must be IPv4
+ if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
+
+ // IP version must be 4
+ if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
+
+ // We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
+ if (ip->ihl != 5) TC_PUNT(HAS_IP_OPTIONS);
+
+ // Calculate the IPv4 one's complement checksum of the IPv4 header.
+ __wsum sum4 = 0;
+ for (int i = 0; i < sizeof(*ip) / sizeof(__u16); ++i) {
+ sum4 += ((__u16*)ip)[i];
+ }
+ // Note that sum4 is guaranteed to be non-zero by virtue of ip4->version == 4
+ sum4 = (sum4 & 0xFFFF) + (sum4 >> 16); // collapse u32 into range 1 .. 0x1FFFE
+ sum4 = (sum4 & 0xFFFF) + (sum4 >> 16); // collapse any potential carry into u16
+ // for a correct checksum we should get *a* zero, but sum4 must be positive, ie 0xFFFF
+ if (sum4 != 0xFFFF) TC_PUNT(CHECKSUM);
+
+ // Minimum IPv4 total length is the size of the header
+ if (ntohs(ip->tot_len) < sizeof(*ip)) TC_PUNT(TRUNCATED_IPV4);
+
+ // We are incapable of dealing with IPv4 fragments
+ if (ip->frag_off & ~htons(IP_DF)) TC_PUNT(IS_IP_FRAG);
+
+ // Cannot decrement during forward if already zero or would be zero,
+ // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
+ if (ip->ttl <= 1) TC_PUNT(LOW_TTL);
+
+ // If we cannot update the 'last_used' field due to lack of bpf_ktime_get_boot_ns() helper,
+ // then it is not safe to offload UDP due to the small conntrack timeouts, as such,
+ // in such a situation we can only support TCP. This also has the added nice benefit of
+ // using a separate error counter, and thus making it obvious which version of the program
+ // is loaded.
+ if (!updatetime && ip->protocol != IPPROTO_TCP) TC_PUNT(NON_TCP);
+
+ // We do not support offloading anything besides IPv4 TCP and UDP, due to need for NAT,
+ // but no need to check this if !updatetime due to check immediately above.
+ if (updatetime && (ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP))
+ TC_PUNT(NON_TCP_UDP);
+
+ // We want to make sure that the compiler will, in the !updatetime case, entirely optimize
+ // out all the non-tcp logic. Also note that at this point is_udp === !is_tcp.
+ const bool is_tcp = !updatetime || (ip->protocol == IPPROTO_TCP);
+
+ // This is a bit of a hack to make things easier on the bpf verifier.
+ // (In particular I believe the Linux 4.14 kernel's verifier can get confused later on about
+ // what offsets into the packet are valid and can spuriously reject the program, this is
+ // because it fails to realize that is_tcp && !is_tcp is impossible)
+ //
+ // For both TCP & UDP we'll need to read and modify the src/dst ports, which so happen to
+ // always be in the first 4 bytes of the L4 header. Additionally for UDP we'll need access
+ // to the checksum field which is in bytes 7 and 8. While for TCP we'll need to read the
+ // TCP flags (at offset 13) and access to the checksum field (2 bytes at offset 16).
+ // As such we *always* need access to at least 8 bytes.
+ if (data + l2_header_size + sizeof(*ip) + 8 > data_end) TC_PUNT(SHORT_L4_HEADER);
+
+ // We're forcing the compiler to emit two copies of the following code, optimized
+ // separately for is_tcp being true or false. This simplifies the resulting bpf
+ // byte code sufficiently that the 4.14 bpf verifier is able to keep track of things.
+ // Without this (updatetime == true) case would fail to bpf verify on 4.14 even
+ // if the underlying requisite kernel support (bpf_ktime_get_boot_ns) was backported.
+ if (is_tcp) {
+ return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
+ is_ethernet, downstream, updatetime, /* is_tcp */ true);
+ } else {
+ return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
+ is_ethernet, downstream, updatetime, /* is_tcp */ false);
+ }
+}
+
// Full featured (required) implementations for 5.8+ kernels (these are S+ by definition)
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_rawip$5_8", AID_ROOT, AID_NETWORK_STACK,
diff --git a/framework/src/android/net/LinkProperties.java b/framework/src/android/net/LinkProperties.java
index 126a5ff..a8f707e 100644
--- a/framework/src/android/net/LinkProperties.java
+++ b/framework/src/android/net/LinkProperties.java
@@ -1366,6 +1366,21 @@
}
/**
+ * Returns true if this link has a throw route.
+ *
+ * @return {@code true} if there is an exclude route, {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasExcludeRoute() {
+ for (RouteInfo r : mRoutes) {
+ if (r.getType() == RouteInfo.RTN_THROW) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Compares this {@code LinkProperties} interface name against the target
*
* @param target LinkProperties to compare.
diff --git a/framework/src/android/net/QosCallbackException.java b/framework/src/android/net/QosCallbackException.java
index ed6eb15..b80cff4 100644
--- a/framework/src/android/net/QosCallbackException.java
+++ b/framework/src/android/net/QosCallbackException.java
@@ -46,8 +46,10 @@
EX_TYPE_FILTER_NONE,
EX_TYPE_FILTER_NETWORK_RELEASED,
EX_TYPE_FILTER_SOCKET_NOT_BOUND,
+ EX_TYPE_FILTER_SOCKET_NOT_CONNECTED,
EX_TYPE_FILTER_NOT_SUPPORTED,
EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
+ EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ExceptionType {}
@@ -65,10 +67,16 @@
public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
/** {@hide} */
- public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
+ public static final int EX_TYPE_FILTER_SOCKET_NOT_CONNECTED = 3;
/** {@hide} */
- public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
+ public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 4;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 5;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED = 6;
/**
* Creates exception based off of a type and message. Not all types of exceptions accept a
@@ -83,12 +91,17 @@
return new QosCallbackException(new NetworkReleasedException());
case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
return new QosCallbackException(new SocketNotBoundException());
+ case EX_TYPE_FILTER_SOCKET_NOT_CONNECTED:
+ return new QosCallbackException(new SocketNotConnectedException());
case EX_TYPE_FILTER_NOT_SUPPORTED:
return new QosCallbackException(new UnsupportedOperationException(
"This device does not support the specified filter"));
case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
return new QosCallbackException(
new SocketLocalAddressChangedException());
+ case EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED:
+ return new QosCallbackException(
+ new SocketRemoteAddressChangedException());
default:
Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
return new QosCallbackException(
diff --git a/framework/src/android/net/QosFilter.java b/framework/src/android/net/QosFilter.java
index 5c1c3cc..b432644 100644
--- a/framework/src/android/net/QosFilter.java
+++ b/framework/src/android/net/QosFilter.java
@@ -90,5 +90,15 @@
*/
public abstract boolean matchesRemoteAddress(@NonNull InetAddress address,
int startPort, int endPort);
+
+ /**
+ * Determines whether or not the parameter will be matched with this filter.
+ *
+ * @param protocol the protocol such as TCP or UDP included in IP packet filter set of a QoS
+ * flow assigned on {@link Network}.
+ * @return whether the parameters match the socket type of the filter
+ * @hide
+ */
+ public abstract boolean matchesProtocol(int protocol);
}
diff --git a/framework/src/android/net/QosFilterParcelable.java b/framework/src/android/net/QosFilterParcelable.java
index da3b2cf..6e71fa3 100644
--- a/framework/src/android/net/QosFilterParcelable.java
+++ b/framework/src/android/net/QosFilterParcelable.java
@@ -104,7 +104,7 @@
if (mQosFilter instanceof QosSocketFilter) {
dest.writeInt(QOS_SOCKET_FILTER);
final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
- qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
+ qosSocketFilter.getQosSocketInfo().writeToParcelWithoutFd(dest, 0);
return;
}
dest.writeInt(NO_FILTER_PRESENT);
diff --git a/framework/src/android/net/QosSocketFilter.java b/framework/src/android/net/QosSocketFilter.java
index 69da7f4..5ceeb67 100644
--- a/framework/src/android/net/QosSocketFilter.java
+++ b/framework/src/android/net/QosSocketFilter.java
@@ -18,6 +18,13 @@
import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_CONNECTED;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -74,19 +81,34 @@
* 2. In the scenario that the socket is now bound to a different local address, which can
* happen in the case of UDP, then
* {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
+ * 3. In the scenario that the UDP socket changed remote address, then
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED} is returned.
+ *
* @return validation error code
*/
@Override
public int validate() {
- final InetSocketAddress sa = getAddressFromFileDescriptor();
- if (sa == null) {
- return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+ final InetSocketAddress sa = getLocalAddressFromFileDescriptor();
+
+ if (sa == null || (sa.getAddress().isAnyLocalAddress() && sa.getPort() == 0)) {
+ return EX_TYPE_FILTER_SOCKET_NOT_BOUND;
}
if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
}
+ if (mQosSocketInfo.getRemoteSocketAddress() != null) {
+ final InetSocketAddress da = getRemoteAddressFromFileDescriptor();
+ if (da == null) {
+ return EX_TYPE_FILTER_SOCKET_NOT_CONNECTED;
+ }
+
+ if (!da.equals(mQosSocketInfo.getRemoteSocketAddress())) {
+ return EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED;
+ }
+ }
+
return EX_TYPE_FILTER_NONE;
}
@@ -98,17 +120,14 @@
* @return the local address
*/
@Nullable
- private InetSocketAddress getAddressFromFileDescriptor() {
+ private InetSocketAddress getLocalAddressFromFileDescriptor() {
final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
- if (parcelFileDescriptor == null) return null;
-
final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
- if (fd == null) return null;
final SocketAddress address;
try {
address = Os.getsockname(fd);
- } catch (final ErrnoException e) {
+ } catch (ErrnoException e) {
Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
return null;
}
@@ -119,6 +138,31 @@
}
/**
+ * The remote address of the socket's connected.
+ *
+ * <p>Note: If the socket is no longer connected, null is returned.
+ *
+ * @return the remote address
+ */
+ @Nullable
+ private InetSocketAddress getRemoteAddressFromFileDescriptor() {
+ final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
+ final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
+
+ final SocketAddress address;
+ try {
+ address = Os.getpeername(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "getAddressFromFileDescriptor: getRemoteAddress exception", e);
+ return null;
+ }
+ if (address instanceof InetSocketAddress) {
+ return (InetSocketAddress) address;
+ }
+ return null;
+ }
+
+ /**
* The network used with this filter.
*
* @return the registered {@link Network}
@@ -156,6 +200,18 @@
}
/**
+ * @inheritDoc
+ */
+ @Override
+ public boolean matchesProtocol(final int protocol) {
+ if ((mQosSocketInfo.getSocketType() == SOCK_STREAM && protocol == IPPROTO_TCP)
+ || (mQosSocketInfo.getSocketType() == SOCK_DGRAM && protocol == IPPROTO_UDP)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)}
* and {@link QosSocketFilter#matchesRemoteAddress(InetAddress, int, int)} with the
* filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
@@ -174,6 +230,7 @@
final int startPort, final int endPort) {
return startPort <= filterSocketAddress.getPort()
&& endPort >= filterSocketAddress.getPort()
- && filterSocketAddress.getAddress().equals(address);
+ && (address.isAnyLocalAddress()
+ || filterSocketAddress.getAddress().equals(address));
}
}
diff --git a/framework/src/android/net/QosSocketInfo.java b/framework/src/android/net/QosSocketInfo.java
index 39c2f33..49ac22b 100644
--- a/framework/src/android/net/QosSocketInfo.java
+++ b/framework/src/android/net/QosSocketInfo.java
@@ -165,25 +165,28 @@
/* Parcelable methods */
private QosSocketInfo(final Parcel in) {
mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
- mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+ final boolean withFd = in.readBoolean();
+ if (withFd) {
+ mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+ } else {
+ mParcelFileDescriptor = null;
+ }
- final int localAddressLength = in.readInt();
- mLocalSocketAddress = readSocketAddress(in, localAddressLength);
-
- final int remoteAddressLength = in.readInt();
- mRemoteSocketAddress = remoteAddressLength == 0 ? null
- : readSocketAddress(in, remoteAddressLength);
+ mLocalSocketAddress = readSocketAddress(in);
+ mRemoteSocketAddress = readSocketAddress(in);
mSocketType = in.readInt();
}
- private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
- final byte[] address = new byte[addressLength];
- in.readByteArray(address);
+ private InetSocketAddress readSocketAddress(final Parcel in) {
+ final byte[] addrBytes = in.createByteArray();
+ if (addrBytes == null) {
+ return null;
+ }
final int port = in.readInt();
try {
- return new InetSocketAddress(InetAddress.getByAddress(address), port);
+ return new InetSocketAddress(InetAddress.getByAddress(addrBytes), port);
} catch (final UnknownHostException e) {
/* This can never happen. UnknownHostException will never be thrown
since the address provided is numeric and non-null. */
@@ -198,20 +201,35 @@
@Override
public void writeToParcel(@NonNull final Parcel dest, final int flags) {
- mNetwork.writeToParcel(dest, 0);
- mParcelFileDescriptor.writeToParcel(dest, 0);
+ writeToParcelInternal(dest, flags, /*includeFd=*/ true);
+ }
- final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress();
- dest.writeInt(localAddress.length);
- dest.writeByteArray(localAddress);
+ /**
+ * Used when sending QosSocketInfo to telephony, which does not need access to the socket FD.
+ * @hide
+ */
+ public void writeToParcelWithoutFd(@NonNull final Parcel dest, final int flags) {
+ writeToParcelInternal(dest, flags, /*includeFd=*/ false);
+ }
+
+ private void writeToParcelInternal(
+ @NonNull final Parcel dest, final int flags, boolean includeFd) {
+ mNetwork.writeToParcel(dest, 0);
+
+ if (includeFd) {
+ dest.writeBoolean(true);
+ mParcelFileDescriptor.writeToParcel(dest, 0);
+ } else {
+ dest.writeBoolean(false);
+ }
+
+ dest.writeByteArray(mLocalSocketAddress.getAddress().getAddress());
dest.writeInt(mLocalSocketAddress.getPort());
if (mRemoteSocketAddress == null) {
- dest.writeInt(0);
+ dest.writeByteArray(null);
} else {
- final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress();
- dest.writeInt(remoteAddress.length);
- dest.writeByteArray(remoteAddress);
+ dest.writeByteArray(mRemoteSocketAddress.getAddress().getAddress());
dest.writeInt(mRemoteSocketAddress.getPort());
}
dest.writeInt(mSocketType);
diff --git a/framework/src/android/net/SocketNotConnectedException.java b/framework/src/android/net/SocketNotConnectedException.java
new file mode 100644
index 0000000..fa2a615
--- /dev/null
+++ b/framework/src/android/net/SocketNotConnectedException.java
@@ -0,0 +1,29 @@
+/*
+ * 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 android.net;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+public class SocketNotConnectedException extends Exception {
+ /** @hide */
+ public SocketNotConnectedException() {
+ super("The socket is not connected");
+ }
+}
diff --git a/framework/src/android/net/SocketRemoteAddressChangedException.java b/framework/src/android/net/SocketRemoteAddressChangedException.java
new file mode 100644
index 0000000..ecaeebc
--- /dev/null
+++ b/framework/src/android/net/SocketRemoteAddressChangedException.java
@@ -0,0 +1,29 @@
+/*
+ * 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 android.net;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+public class SocketRemoteAddressChangedException extends Exception {
+ /** @hide */
+ public SocketRemoteAddressChangedException() {
+ super("The remote address of the socket changed");
+ }
+}
diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java
index fdfc893..d974a3b 100644
--- a/service-t/src/com/android/server/net/NetworkStatsObservers.java
+++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java
@@ -18,6 +18,7 @@
import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
+import android.annotation.NonNull;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -38,6 +39,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseArray;
@@ -52,6 +54,7 @@
*/
class NetworkStatsObservers {
private static final String TAG = "NetworkStatsObservers";
+ private static final boolean LOG = true;
private static final boolean LOGV = false;
private static final int MSG_REGISTER = 1;
@@ -77,13 +80,15 @@
*
* @return the normalized request wrapped within {@link RequestInfo}.
*/
- public DataUsageRequest register(Context context, DataUsageRequest inputRequest,
- IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+ public DataUsageRequest register(@NonNull Context context,
+ @NonNull DataUsageRequest inputRequest, @NonNull IUsageCallback callback,
+ int callingPid, int callingUid, @NonNull String callingPackage,
+ @NetworkStatsAccess.Level int accessLevel) {
DataUsageRequest request = buildRequest(context, inputRequest, callingUid);
- RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid,
- accessLevel);
+ RequestInfo requestInfo = buildRequestInfo(request, callback, callingPid, callingUid,
+ callingPackage, accessLevel);
- if (LOGV) Log.v(TAG, "Registering observer for " + request);
+ if (LOG) Log.d(TAG, "Registering observer for " + requestInfo);
getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
return request;
}
@@ -172,7 +177,7 @@
RequestInfo requestInfo;
requestInfo = mDataUsageRequests.get(request.requestId);
if (requestInfo == null) {
- if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request);
+ if (LOG) Log.d(TAG, "Trying to unregister unknown request " + request);
return;
}
if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
@@ -180,7 +185,7 @@
return;
}
- if (LOGV) Log.v(TAG, "Unregistering " + request);
+ if (LOG) Log.d(TAG, "Unregistering " + requestInfo);
mDataUsageRequests.remove(request.requestId);
requestInfo.unlinkDeathRecipient();
requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
@@ -214,18 +219,19 @@
}
private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback,
- int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+ int callingPid, int callingUid, @NonNull String callingPackage,
+ @NetworkStatsAccess.Level int accessLevel) {
if (accessLevel <= NetworkStatsAccess.Level.USER) {
- return new UserUsageRequestInfo(this, request, callback, callingUid,
- accessLevel);
+ return new UserUsageRequestInfo(this, request, callback, callingPid,
+ callingUid, callingPackage, accessLevel);
} else {
// Safety check in case a new access level is added and we forgot to update this
if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
throw new IllegalArgumentException(
"accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
}
- return new NetworkUsageRequestInfo(this, request, callback, callingUid,
- accessLevel);
+ return new NetworkUsageRequestInfo(this, request, callback, callingPid,
+ callingUid, callingPackage, accessLevel);
}
}
@@ -237,18 +243,22 @@
private final NetworkStatsObservers mStatsObserver;
protected final DataUsageRequest mRequest;
private final IUsageCallback mCallback;
+ protected final int mCallingPid;
protected final int mCallingUid;
+ protected final String mCallingPackage;
protected final @NetworkStatsAccess.Level int mAccessLevel;
protected NetworkStatsRecorder mRecorder;
protected NetworkStatsCollection mCollection;
RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
- IUsageCallback callback, int callingUid,
- @NetworkStatsAccess.Level int accessLevel) {
+ IUsageCallback callback, int callingPid, int callingUid,
+ @NonNull String callingPackage, @NetworkStatsAccess.Level int accessLevel) {
mStatsObserver = statsObserver;
mRequest = request;
mCallback = callback;
+ mCallingPid = callingPid;
mCallingUid = callingUid;
+ mCallingPackage = callingPackage;
mAccessLevel = accessLevel;
try {
@@ -269,7 +279,8 @@
@Override
public String toString() {
- return "RequestInfo from uid:" + mCallingUid
+ return "RequestInfo from pid/uid:" + mCallingPid + "/" + mCallingUid
+ + "(" + mCallingPackage + ")"
+ " for " + mRequest + " accessLevel:" + mAccessLevel;
}
@@ -338,9 +349,10 @@
private static class NetworkUsageRequestInfo extends RequestInfo {
NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
- IUsageCallback callback, int callingUid,
- @NetworkStatsAccess.Level int accessLevel) {
- super(statsObserver, request, callback, callingUid, accessLevel);
+ IUsageCallback callback, int callingPid, int callingUid,
+ @NonNull String callingPackage, @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, callback, callingPid, callingUid, callingPackage,
+ accessLevel);
}
@Override
@@ -380,9 +392,10 @@
private static class UserUsageRequestInfo extends RequestInfo {
UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
- IUsageCallback callback, int callingUid,
- @NetworkStatsAccess.Level int accessLevel) {
- super(statsObserver, request, callback, callingUid, accessLevel);
+ IUsageCallback callback, int callingPid, int callingUid,
+ @NonNull String callingPackage, @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, callback, callingPid, callingUid,
+ callingPackage, accessLevel);
}
@Override
@@ -448,4 +461,10 @@
mCurrentTime = currentTime;
}
}
+
+ public void dump(IndentingPrintWriter pw) {
+ for (int i = 0; i < mDataUsageRequests.size(); i++) {
+ pw.println(mDataUsageRequests.valueAt(i));
+ }
+ }
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 391356c..7c167ed 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -1331,13 +1331,14 @@
Objects.requireNonNull(request.template, "NetworkTemplate is null");
Objects.requireNonNull(callback, "callback is null");
- int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
@NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
DataUsageRequest normalizedRequest;
final long token = Binder.clearCallingIdentity();
try {
normalizedRequest = mStatsObservers.register(mContext,
- request, callback, callingUid, accessLevel);
+ request, callback, callingPid, callingUid, callingPackage, accessLevel);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2146,6 +2147,13 @@
}
});
pw.decreaseIndent();
+ pw.println();
+
+ pw.println("Stats Observers:");
+ pw.increaseIndent();
+ mStatsObservers.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
pw.println("Dev stats:");
pw.increaseIndent();
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 4183ac6..1bd5a1d 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -8087,7 +8087,8 @@
&& nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
&& (lp.hasIpv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
- && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
+ && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute())
+ && !lp.hasExcludeRoute();
}
private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 4a7c77a..3b0b3fd 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -116,10 +116,12 @@
private final INetd mNetd;
@NonNull
private final Dependencies mDeps;
+ // IBpfMap objects {mIngressMap, mEgressMap} are initialized in #maybeStartBpf and closed in
+ // #maybeStopBpf.
@Nullable
- private final IBpfMap<ClatIngress6Key, ClatIngress6Value> mIngressMap;
+ private IBpfMap<ClatIngress6Key, ClatIngress6Value> mIngressMap = null;
@Nullable
- private final IBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap;
+ private IBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap = null;
@Nullable
private ClatdTracker mClatdTracker = null;
@@ -373,12 +375,35 @@
public ClatCoordinator(@NonNull Dependencies deps) {
mDeps = deps;
mNetd = mDeps.getNetd();
- mIngressMap = mDeps.getBpfIngress6Map();
- mEgressMap = mDeps.getBpfEgress4Map();
+ }
+
+ private void closeEgressMap() {
+ try {
+ mEgressMap.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Cannot close egress4 map: " + e);
+ }
+ mEgressMap = null;
+ }
+
+ private void closeIngressMap() {
+ try {
+ mIngressMap.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Cannot close ingress6 map: " + e);
+ }
+ mIngressMap = null;
}
private void maybeStartBpf(final ClatdTracker tracker) {
- if (mIngressMap == null || mEgressMap == null) return;
+ mEgressMap = mDeps.getBpfEgress4Map();
+ if (mEgressMap == null) return;
+
+ mIngressMap = mDeps.getBpfIngress6Map();
+ if (mIngressMap == null) {
+ closeEgressMap();
+ return;
+ }
final boolean isEthernet;
try {
@@ -722,6 +747,13 @@
} catch (ErrnoException | IllegalStateException e) {
Log.e(TAG, "Could not delete entry (" + rxKey + "): " + e);
}
+
+ // Manual close BPF map file descriptors. Just don't rely on that GC releasing to close
+ // the file descriptors even if class BpfMap supports close file descriptor in
+ // finalize(). If the interfaces are added and removed quickly, too many unclosed file
+ // descriptors may cause unexpected problem.
+ closeEgressMap();
+ closeIngressMap();
}
/**
@@ -790,7 +822,7 @@
}
/**
- * Dump the cordinator information.
+ * Dump the cordinator information. Only called when clat is started. See Nat464Xlat#dump.
*
* @param pw print writer.
*/
diff --git a/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java b/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
index 534dbe7..e682026 100644
--- a/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -30,6 +30,8 @@
import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
+import com.android.modules.utils.build.SdkLevel;
+
import java.util.Objects;
/**
@@ -149,6 +151,7 @@
void sendEventEpsQosSessionAvailable(final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
+ if (!validateOrSendErrorAndUnregister()) return;
try {
if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
mCallback.onQosEpsBearerSessionAvailable(session, attributes);
@@ -159,6 +162,7 @@
void sendEventNrQosSessionAvailable(final QosSession session,
final NrQosSessionAttributes attributes) {
+ if (!validateOrSendErrorAndUnregister()) return;
try {
if (DBG) log("sendEventNrQosSessionAvailable: sending...");
mCallback.onNrQosSessionAvailable(session, attributes);
@@ -168,6 +172,7 @@
}
void sendEventQosSessionLost(@NonNull final QosSession session) {
+ if (!validateOrSendErrorAndUnregister()) return;
try {
if (DBG) log("sendEventQosSessionLost: sending...");
mCallback.onQosSessionLost(session);
@@ -185,6 +190,21 @@
}
}
+ private boolean validateOrSendErrorAndUnregister() {
+ final int exceptionType = mFilter.validate();
+ if (exceptionType != EX_TYPE_FILTER_NONE) {
+ log("validation fail before sending QosCallback.");
+ // Error callback is returned from Android T to prevent any disruption of application
+ // running on Android S.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventQosCallbackError(exceptionType);
+ mQosCallbackTracker.unregisterCallback(mCallback);
+ }
+ return false;
+ }
+ return true;
+ }
+
private static void log(@NonNull final String msg) {
Log.d(TAG, msg);
}
diff --git a/tests/common/java/android/net/EthernetNetworkManagementExceptionTest.java b/tests/common/java/android/net/EthernetNetworkManagementExceptionTest.java
new file mode 100644
index 0000000..84b6e54
--- /dev/null
+++ b/tests/common/java/android/net/EthernetNetworkManagementExceptionTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 android.net;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+@RunWith(DevSdkIgnoreRunner.class)
+@SmallTest
+public class EthernetNetworkManagementExceptionTest {
+ private static final String ERROR_MESSAGE = "Test error message";
+
+ @Test
+ public void testEthernetNetworkManagementExceptionParcelable() {
+ final EthernetNetworkManagementException e =
+ new EthernetNetworkManagementException(ERROR_MESSAGE);
+
+ assertParcelingIsLossless(e);
+ }
+
+ @Test
+ public void testEthernetNetworkManagementExceptionHasExpectedErrorMessage() {
+ final EthernetNetworkManagementException e =
+ new EthernetNetworkManagementException(ERROR_MESSAGE);
+
+ assertEquals(ERROR_MESSAGE, e.getMessage());
+ }
+}
diff --git a/tests/common/java/android/net/LinkPropertiesTest.java b/tests/common/java/android/net/LinkPropertiesTest.java
index 8fc636a..345a78d 100644
--- a/tests/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/common/java/android/net/LinkPropertiesTest.java
@@ -1261,6 +1261,17 @@
assertFalse(lp.hasIpv4UnreachableDefaultRoute());
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testHasExcludeRoute() {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("VPN");
+ lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 2), RTN_UNICAST));
+ lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 0), RTN_UNICAST));
+ assertFalse(lp.hasExcludeRoute());
+ lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 2), RTN_THROW));
+ assertTrue(lp.hasExcludeRoute());
+ }
+
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@EnableCompatChanges({LinkProperties.EXCLUDED_ROUTES})
public void testRouteAddWithSameKey() throws Exception {
diff --git a/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt b/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt
index ca0e5ed..368a519 100644
--- a/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt
+++ b/tests/common/java/android/net/netstats/NetworkStatsCollectionTest.kt
@@ -16,7 +16,7 @@
package android.net.netstats
-import android.net.NetworkIdentitySet
+import android.net.NetworkIdentity
import android.net.NetworkStatsCollection
import android.net.NetworkStatsHistory
import androidx.test.filters.SmallTest
@@ -40,7 +40,7 @@
@Test
fun testBuilder() {
- val ident = NetworkIdentitySet()
+ val ident = setOf<NetworkIdentity>()
val key1 = NetworkStatsCollection.Key(ident, /* uid */ 0, /* set */ 0, /* tag */ 0)
val key2 = NetworkStatsCollection.Key(ident, /* uid */ 1, /* set */ 0, /* tag */ 0)
val bucketDuration = 10L
@@ -63,4 +63,4 @@
val actualHistory = actualEntries[key1] ?: fail("There should be an entry for $key1")
assertEquals(history1.entries, actualHistory.entries)
}
-}
\ No newline at end of file
+}
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index 47ea53e..ac84e57 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -26,6 +26,7 @@
"tradefed",
],
static_libs: [
+ "CompatChangeGatingTestBase",
"modules-utils-build-testing",
],
// Tag this module as a cts test artifact
@@ -37,6 +38,8 @@
data: [
":CtsHostsideNetworkTestsApp",
":CtsHostsideNetworkTestsApp2",
+ ":CtsHostsideNetworkTestsApp3",
+ ":CtsHostsideNetworkTestsApp3PreT",
":CtsHostsideNetworkTestsAppNext",
],
per_testcase_directory: true,
diff --git a/tests/cts/hostside/app2/Android.bp b/tests/cts/hostside/app2/Android.bp
index 01c8cd2..edfaf9f 100644
--- a/tests/cts/hostside/app2/Android.bp
+++ b/tests/cts/hostside/app2/Android.bp
@@ -23,6 +23,7 @@
defaults: ["cts_support_defaults"],
sdk_version: "test_current",
static_libs: [
+ "androidx.annotation_annotation",
"CtsHostsideNetworkTestsAidl",
"NetworkStackApiStableShims",
],
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index 08cdea7..51acfdf 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -30,6 +30,8 @@
import android.os.RemoteException;
import android.util.Log;
+import androidx.annotation.GuardedBy;
+
import com.android.cts.net.hostside.INetworkStateObserver;
/**
@@ -37,6 +39,7 @@
*/
public class MyActivity extends Activity {
+ @GuardedBy("this")
private BroadcastReceiver finishCommandReceiver = null;
@Override
@@ -47,8 +50,11 @@
@Override
public void finish() {
- if (finishCommandReceiver != null) {
- unregisterReceiver(finishCommandReceiver);
+ synchronized (this) {
+ if (finishCommandReceiver != null) {
+ unregisterReceiver(finishCommandReceiver);
+ finishCommandReceiver = null;
+ }
}
super.finish();
}
@@ -71,14 +77,17 @@
super.onResume();
Log.d(TAG, "MyActivity.onResume(): " + getIntent());
Common.notifyNetworkStateObserver(this, getIntent(), TYPE_COMPONENT_ACTIVTY);
- finishCommandReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "Finishing MyActivity");
- MyActivity.this.finish();
- }
- };
- registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
+ synchronized (this) {
+ finishCommandReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Finishing MyActivity");
+ MyActivity.this.finish();
+ }
+ };
+ registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY),
+ Context.RECEIVER_EXPORTED);
+ }
}
@Override
diff --git a/tests/cts/hostside/app3/Android.bp b/tests/cts/hostside/app3/Android.bp
new file mode 100644
index 0000000..141cf03
--- /dev/null
+++ b/tests/cts/hostside/app3/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_defaults {
+ name: "CtsHostsideNetworkTestsApp3Defaults",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "junit",
+ ],
+ static_libs: [
+ "ctstestrunner-axt",
+ "truth-prebuilt",
+ ],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsHostsideNetworkTestsApp3",
+ defaults: [
+ "cts_support_defaults",
+ "CtsHostsideNetworkTestsApp3Defaults",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsHostsideNetworkTestsApp3PreT",
+ target_sdk_version: "31",
+ defaults: [
+ "cts_support_defaults",
+ "CtsHostsideNetworkTestsApp3Defaults",
+ ],
+}
diff --git a/tests/cts/hostside/app3/AndroidManifest.xml b/tests/cts/hostside/app3/AndroidManifest.xml
new file mode 100644
index 0000000..eabcacb
--- /dev/null
+++ b/tests/cts/hostside/app3/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.net.hostside.app3">
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.net.hostside.app3" />
+
+</manifest>
diff --git a/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java b/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java
new file mode 100644
index 0000000..a1a8209
--- /dev/null
+++ b/tests/cts/hostside/app3/src/com/android/cts/net/hostside/app3/ExcludedRoutesGatingTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.cts.net.hostside.app3;
+
+import static org.junit.Assert.assertEquals;
+
+import android.Manifest;
+import android.net.IpPrefix;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests to verify {@link LinkProperties#getRoutes} behavior, depending on
+ * {@LinkProperties#EXCLUDED_ROUTES} change state.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExcludedRoutesGatingTest {
+ @Before
+ public void setUp() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ }
+
+ @After
+ public void tearDown() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testExcludedRoutesChangeEnabled() {
+ final LinkProperties lp = makeLinkPropertiesWithExcludedRoutes();
+
+ // Excluded routes change is enabled: non-RTN_UNICAST routes are visible.
+ assertEquals(2, lp.getRoutes().size());
+ assertEquals(2, lp.getAllRoutes().size());
+ }
+
+ @Test
+ public void testExcludedRoutesChangeDisabled() {
+ final LinkProperties lp = makeLinkPropertiesWithExcludedRoutes();
+
+ // Excluded routes change is disabled: non-RTN_UNICAST routes are filtered out.
+ assertEquals(0, lp.getRoutes().size());
+ assertEquals(0, lp.getAllRoutes().size());
+ }
+
+ private LinkProperties makeLinkPropertiesWithExcludedRoutes() {
+ final LinkProperties lp = new LinkProperties();
+
+ lp.addRoute(new RouteInfo(new IpPrefix("10.0.0.0/8"), null, null, RouteInfo.RTN_THROW));
+ lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"), null, null,
+ RouteInfo.RTN_UNREACHABLE));
+
+ return lp;
+ }
+}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java
new file mode 100644
index 0000000..b65fb6b
--- /dev/null
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideLinkPropertiesGatingTests.java
@@ -0,0 +1,71 @@
+/*
+ * 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.cts.net;
+
+import android.compat.cts.CompatChangeGatingTestCase;
+
+import java.util.Set;
+
+/**
+ * Tests for the {@link android.net.LinkProperties#EXCLUDED_ROUTES} compatibility change.
+ */
+public class HostsideLinkPropertiesGatingTests extends CompatChangeGatingTestCase {
+ private static final String TEST_APK = "CtsHostsideNetworkTestsApp3.apk";
+ private static final String TEST_APK_PRE_T = "CtsHostsideNetworkTestsApp3PreT.apk";
+ private static final String TEST_PKG = "com.android.cts.net.hostside.app3";
+ private static final String TEST_CLASS = ".ExcludedRoutesGatingTest";
+
+ private static final long EXCLUDED_ROUTES_CHANGE_ID = 186082280;
+
+ protected void tearDown() throws Exception {
+ uninstallPackage(TEST_PKG, true);
+ }
+
+ public void testExcludedRoutesChangeEnabled() throws Exception {
+ installPackage(TEST_APK, true);
+ runDeviceCompatTest("testExcludedRoutesChangeEnabled");
+ }
+
+ public void testExcludedRoutesChangeDisabledPreT() throws Exception {
+ installPackage(TEST_APK_PRE_T, true);
+ runDeviceCompatTest("testExcludedRoutesChangeDisabled");
+ }
+
+ public void testExcludedRoutesChangeDisabledByOverride() throws Exception {
+ installPackage(TEST_APK, true);
+ runDeviceCompatTestWithChangeDisabled("testExcludedRoutesChangeDisabled");
+ }
+
+ public void testExcludedRoutesChangeEnabledByOverridePreT() throws Exception {
+ installPackage(TEST_APK_PRE_T, true);
+ runDeviceCompatTestWithChangeEnabled("testExcludedRoutesChangeEnabled");
+ }
+
+ private void runDeviceCompatTest(String methodName) throws Exception {
+ runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(), Set.of());
+ }
+
+ private void runDeviceCompatTestWithChangeEnabled(String methodName) throws Exception {
+ runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(EXCLUDED_ROUTES_CHANGE_ID),
+ Set.of());
+ }
+
+ private void runDeviceCompatTestWithChangeDisabled(String methodName) throws Exception {
+ runDeviceCompatTest(TEST_PKG, TEST_CLASS, methodName, Set.of(),
+ Set.of(EXCLUDED_ROUTES_CHANGE_ID));
+ }
+}
diff --git a/tests/unit/java/android/net/QosSocketFilterTest.java b/tests/unit/java/android/net/QosSocketFilterTest.java
index 91f2cdd..6820b40 100644
--- a/tests/unit/java/android/net/QosSocketFilterTest.java
+++ b/tests/unit/java/android/net/QosSocketFilterTest.java
@@ -16,8 +16,17 @@
package android.net;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_CONNECTED;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.os.Build;
@@ -29,6 +38,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -36,14 +46,14 @@
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class QosSocketFilterTest {
-
+ private static final int TEST_NET_ID = 1777;
+ private final Network mNetwork = new Network(TEST_NET_ID);
@Test
public void testPortExactMatch() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
assertTrue(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
-
}
@Test
@@ -77,5 +87,90 @@
assertFalse(QosSocketFilter.matchesAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
}
+
+ @Test
+ public void testAddressMatchWithAnyLocalAddresses() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("0.0.0.0");
+ assertTrue(QosSocketFilter.matchesAddress(
+ new InetSocketAddress(addressA, 10), addressB, 10, 10));
+ assertFalse(QosSocketFilter.matchesAddress(
+ new InetSocketAddress(addressB, 10), addressA, 10, 10));
+ }
+
+ @Test
+ public void testProtocolMatch() throws Exception {
+ DatagramSocket socket = new DatagramSocket(new InetSocketAddress("127.0.0.1", 0));
+ socket.connect(new InetSocketAddress("127.0.0.1", socket.getLocalPort() + 10));
+ DatagramSocket socketV6 = new DatagramSocket(new InetSocketAddress("::1", 0));
+ socketV6.connect(new InetSocketAddress("::1", socketV6.getLocalPort() + 10));
+ QosSocketInfo socketInfo = new QosSocketInfo(mNetwork, socket);
+ QosSocketFilter socketFilter = new QosSocketFilter(socketInfo);
+ QosSocketInfo socketInfo6 = new QosSocketInfo(mNetwork, socketV6);
+ QosSocketFilter socketFilter6 = new QosSocketFilter(socketInfo6);
+ assertTrue(socketFilter.matchesProtocol(IPPROTO_UDP));
+ assertTrue(socketFilter6.matchesProtocol(IPPROTO_UDP));
+ assertFalse(socketFilter.matchesProtocol(IPPROTO_TCP));
+ assertFalse(socketFilter6.matchesProtocol(IPPROTO_TCP));
+ socket.close();
+ socketV6.close();
+ }
+
+ @Test
+ public void testValidate() throws Exception {
+ DatagramSocket socket = new DatagramSocket(new InetSocketAddress("127.0.0.1", 0));
+ socket.connect(new InetSocketAddress("127.0.0.1", socket.getLocalPort() + 7));
+ DatagramSocket socketV6 = new DatagramSocket(new InetSocketAddress("::1", 0));
+
+ QosSocketInfo socketInfo = new QosSocketInfo(mNetwork, socket);
+ QosSocketFilter socketFilter = new QosSocketFilter(socketInfo);
+ QosSocketInfo socketInfo6 = new QosSocketInfo(mNetwork, socketV6);
+ QosSocketFilter socketFilter6 = new QosSocketFilter(socketInfo6);
+ assertEquals(EX_TYPE_FILTER_NONE, socketFilter.validate());
+ assertEquals(EX_TYPE_FILTER_NONE, socketFilter6.validate());
+ socket.close();
+ socketV6.close();
+ }
+
+ @Test
+ public void testValidateUnbind() throws Exception {
+ DatagramSocket socket;
+ socket = new DatagramSocket(null);
+ QosSocketInfo socketInfo = new QosSocketInfo(mNetwork, socket);
+ QosSocketFilter socketFilter = new QosSocketFilter(socketInfo);
+ assertEquals(EX_TYPE_FILTER_SOCKET_NOT_BOUND, socketFilter.validate());
+ socket.close();
+ }
+
+ @Test
+ public void testValidateLocalAddressChanged() throws Exception {
+ DatagramSocket socket = new DatagramSocket(null);
+ DatagramSocket socket6 = new DatagramSocket(null);
+ QosSocketInfo socketInfo = new QosSocketInfo(mNetwork, socket);
+ QosSocketFilter socketFilter = new QosSocketFilter(socketInfo);
+ QosSocketInfo socketInfo6 = new QosSocketInfo(mNetwork, socket6);
+ QosSocketFilter socketFilter6 = new QosSocketFilter(socketInfo6);
+ socket.bind(new InetSocketAddress("127.0.0.1", 0));
+ socket6.bind(new InetSocketAddress("::1", 0));
+ assertEquals(EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED, socketFilter.validate());
+ assertEquals(EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED, socketFilter6.validate());
+ socket.close();
+ socket6.close();
+ }
+
+ @Test
+ public void testValidateRemoteAddressChanged() throws Exception {
+ DatagramSocket socket;
+ socket = new DatagramSocket(new InetSocketAddress("127.0.0.1", 53137));
+ socket.connect(new InetSocketAddress("127.0.0.1", socket.getLocalPort() + 11));
+ QosSocketInfo socketInfo = new QosSocketInfo(mNetwork, socket);
+ QosSocketFilter socketFilter = new QosSocketFilter(socketInfo);
+ assertEquals(EX_TYPE_FILTER_NONE, socketFilter.validate());
+ socket.disconnect();
+ assertEquals(EX_TYPE_FILTER_SOCKET_NOT_CONNECTED, socketFilter.validate());
+ socket.connect(new InetSocketAddress("127.0.0.1", socket.getLocalPort() + 13));
+ assertEquals(EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED, socketFilter.validate());
+ socket.close();
+ }
}
diff --git a/tests/unit/java/android/net/QosSocketInfoTest.java b/tests/unit/java/android/net/QosSocketInfoTest.java
new file mode 100644
index 0000000..749c182
--- /dev/null
+++ b/tests/unit/java/android/net/QosSocketInfoTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 android.net;
+
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.net.DatagramSocket;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+@RunWith(DevSdkIgnoreRunner.class)
+@SmallTest
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+public class QosSocketInfoTest {
+ @Mock
+ private Network mMockNetwork = mock(Network.class);
+
+ @Test
+ public void testConstructWithSock() throws Exception {
+ ServerSocket server = new ServerSocket();
+ ServerSocket server6 = new ServerSocket();
+
+ InetSocketAddress clientAddr = new InetSocketAddress("127.0.0.1", 0);
+ InetSocketAddress serverAddr = new InetSocketAddress("127.0.0.1", 0);
+ InetSocketAddress clientAddr6 = new InetSocketAddress("::1", 0);
+ InetSocketAddress serverAddr6 = new InetSocketAddress("::1", 0);
+ server.bind(serverAddr);
+ server6.bind(serverAddr6);
+ Socket socket = new Socket(serverAddr.getAddress(), server.getLocalPort(),
+ clientAddr.getAddress(), clientAddr.getPort());
+ Socket socket6 = new Socket(serverAddr6.getAddress(), server6.getLocalPort(),
+ clientAddr6.getAddress(), clientAddr6.getPort());
+ QosSocketInfo sockInfo = new QosSocketInfo(mMockNetwork, socket);
+ QosSocketInfo sockInfo6 = new QosSocketInfo(mMockNetwork, socket6);
+ assertTrue(sockInfo.getLocalSocketAddress()
+ .equals(new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort())));
+ assertTrue(sockInfo.getRemoteSocketAddress()
+ .equals((InetSocketAddress) socket.getRemoteSocketAddress()));
+ assertEquals(SOCK_STREAM, sockInfo.getSocketType());
+ assertTrue(sockInfo6.getLocalSocketAddress()
+ .equals(new InetSocketAddress(socket6.getLocalAddress(), socket6.getLocalPort())));
+ assertTrue(sockInfo6.getRemoteSocketAddress()
+ .equals((InetSocketAddress) socket6.getRemoteSocketAddress()));
+ assertEquals(SOCK_STREAM, sockInfo6.getSocketType());
+ socket.close();
+ socket6.close();
+ server.close();
+ server6.close();
+ }
+
+ @Test
+ public void testConstructWithDatagramSock() throws Exception {
+ InetSocketAddress clientAddr = new InetSocketAddress("127.0.0.1", 0);
+ InetSocketAddress serverAddr = new InetSocketAddress("127.0.0.1", 0);
+ InetSocketAddress clientAddr6 = new InetSocketAddress("::1", 0);
+ InetSocketAddress serverAddr6 = new InetSocketAddress("::1", 0);
+ DatagramSocket socket = new DatagramSocket(null);
+ socket.setReuseAddress(true);
+ socket.bind(clientAddr);
+ socket.connect(serverAddr);
+ DatagramSocket socket6 = new DatagramSocket(null);
+ socket6.setReuseAddress(true);
+ socket6.bind(clientAddr);
+ socket6.connect(serverAddr);
+ QosSocketInfo sockInfo = new QosSocketInfo(mMockNetwork, socket);
+ QosSocketInfo sockInfo6 = new QosSocketInfo(mMockNetwork, socket6);
+ assertTrue(sockInfo.getLocalSocketAddress()
+ .equals((InetSocketAddress) socket.getLocalSocketAddress()));
+ assertTrue(sockInfo.getRemoteSocketAddress()
+ .equals((InetSocketAddress) socket.getRemoteSocketAddress()));
+ assertEquals(SOCK_DGRAM, sockInfo.getSocketType());
+ assertTrue(sockInfo6.getLocalSocketAddress()
+ .equals((InetSocketAddress) socket6.getLocalSocketAddress()));
+ assertTrue(sockInfo6.getRemoteSocketAddress()
+ .equals((InetSocketAddress) socket6.getRemoteSocketAddress()));
+ assertEquals(SOCK_DGRAM, sockInfo6.getSocketType());
+ socket.close();
+ }
+}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 32ea9c3..06243ea 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -136,6 +136,8 @@
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_PROFILE;
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_VPN;
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
+import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister;
+import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister;
import static com.android.testutils.ConcurrentUtils.await;
import static com.android.testutils.ConcurrentUtils.durationOf;
import static com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
@@ -11937,16 +11939,14 @@
mQosCallbackMockHelper.registerQosCallback(
mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
- (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
+ final OnQosCallbackRegister cbRegister1 =
+ (OnQosCallbackRegister) wrapper.getCallbackHistory().poll(1000, x -> true);
assertNotNull(cbRegister1);
final int registerCallbackId = cbRegister1.mQosCallbackId;
mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
- final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
- cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
+ final OnQosCallbackUnregister cbUnregister =
+ (OnQosCallbackUnregister) wrapper.getCallbackHistory().poll(1000, x -> true);
assertNotNull(cbUnregister);
assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
@@ -12025,6 +12025,86 @@
&& session.getSessionType() == QosSession.TYPE_NR_BEARER));
}
+ @Test @IgnoreUpTo(SC_V2)
+ public void testQosCallbackAvailableOnValidationError() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ doReturn(QosCallbackException.EX_TYPE_FILTER_NONE)
+ .when(mQosCallbackMockHelper.mFilter).validate();
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ OnQosCallbackRegister cbRegister1 =
+ (OnQosCallbackRegister) wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbRegister1);
+ final int registerCallbackId = cbRegister1.mQosCallbackId;
+
+ waitForIdle();
+
+ doReturn(QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED)
+ .when(mQosCallbackMockHelper.mFilter).validate();
+ final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+ 1, 2, 3, 4, 5, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
+ cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbUnregister);
+ assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback)
+ .onError(eq(QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED));
+ }
+
+ @Test @IgnoreUpTo(SC_V2)
+ public void testQosCallbackLostOnValidationError() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ doReturn(QosCallbackException.EX_TYPE_FILTER_NONE)
+ .when(mQosCallbackMockHelper.mFilter).validate();
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+ EpsBearerQosSessionAttributes attributes =
+ sendQosSessionEvent(qosCallbackId, sessionId, true);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
+
+ doReturn(QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED)
+ .when(mQosCallbackMockHelper.mFilter).validate();
+
+ sendQosSessionEvent(qosCallbackId, sessionId, false);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback)
+ .onError(eq(QosCallbackException.EX_TYPE_FILTER_SOCKET_REMOTE_ADDRESS_CHANGED));
+ }
+
+ private EpsBearerQosSessionAttributes sendQosSessionEvent(
+ int qosCallbackId, int sessionId, boolean available) {
+ if (available) {
+ final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+ 1, 2, 3, 4, 5, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ return attributes;
+ } else {
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
+ return null;
+ }
+
+ }
+
@Test
public void testQosCallbackTooManyRequests() throws Exception {
mQosCallbackMockHelper = new QosCallbackMockHelper();
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index f84d10f..a1eeaf4 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -447,6 +447,8 @@
argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)),
eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING));
+ inOrder.verify(mDeps).getBpfEgress4Map();
+ inOrder.verify(mDeps).getBpfIngress6Map();
inOrder.verify(mEgressMap).insertEntry(eq(EGRESS_KEY), eq(EGRESS_VALUE));
inOrder.verify(mIngressMap).insertEntry(eq(INGRESS_KEY), eq(INGRESS_VALUE));
inOrder.verify(mDeps).tcQdiscAddDevClsact(eq(STACKED_IFINDEX));
@@ -469,6 +471,8 @@
eq((short) PRIO_CLAT), eq((short) ETH_P_IP));
inOrder.verify(mEgressMap).deleteEntry(eq(EGRESS_KEY));
inOrder.verify(mIngressMap).deleteEntry(eq(INGRESS_KEY));
+ inOrder.verify(mEgressMap).close();
+ inOrder.verify(mIngressMap).close();
inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
inOrder.verify(mDeps).untagSocket(eq(RAW_SOCK_COOKIE));
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 6da4f07..9e79162 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -86,8 +86,11 @@
import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.UidRangeParcel;
import android.net.VpnManager;
@@ -104,6 +107,7 @@
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
@@ -121,6 +125,7 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.internal.util.HexDump;
import com.android.modules.utils.build.SdkLevel;
import com.android.server.IpSecService;
import com.android.testutils.DevSdkIgnoreRule;
@@ -198,6 +203,20 @@
* - One pair of packages have consecutive UIDs.
*/
static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
+ static final String PKGS_BYTES =
+ "3C62756E646C653E0A3C696E74206E616D653D22434F4C4C454354494F4E5F4C454E4754482220"
+ + "76616C75653D223422202F3E0A3C7062756E646C655F61735F6D6170206E616D653D224C4953"
+ + "545F4954454D5F30223E0A3C737472696E67206E616D653D22535452494E475F4B4559223E63"
+ + "6F6D2E6578616D706C653C2F737472696E673E0A3C2F7062756E646C655F61735F6D61703E0A"
+ + "3C7062756E646C655F61735F6D6170206E616D653D224C4953545F4954454D5F31223E0A3C73"
+ + "7472696E67206E616D653D22535452494E475F4B4559223E6F72672E6578616D706C653C2F73"
+ + "7472696E673E0A3C2F7062756E646C655F61735F6D61703E0A3C7062756E646C655F61735F6D"
+ + "6170206E616D653D224C4953545F4954454D5F32223E0A3C737472696E67206E616D653D2253"
+ + "5452494E475F4B4559223E6E65742E6578616D706C653C2F737472696E673E0A3C2F7062756E"
+ + "646C655F61735F6D61703E0A3C7062756E646C655F61735F6D6170206E616D653D224C495354"
+ + "5F4954454D5F33223E0A3C737472696E67206E616D653D22535452494E475F4B4559223E7765"
+ + "622E76706E3C2F737472696E673E0A3C2F7062756E646C655F61735F6D61703E0A3C2F62756E"
+ + "646C653E0A";
static final int[] PKG_UIDS = {66, 77, 78, 400};
// Mock packages
@@ -711,6 +730,47 @@
}
}
+ private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
+ assumeTrue(isAtLeastT());
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+ .thenReturn(mVpnProfile.encode());
+ when(mVpnProfileStore.get(vpn.getVpnAppExcludedForPackage(TEST_VPN_PKG)))
+ .thenReturn(HexDump.hexStringToByteArray(PKGS_BYTES));
+
+ vpn.startVpnProfile(TEST_VPN_PKG);
+ verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+ vpn.mNetworkAgent = new NetworkAgent(mContext, Looper.getMainLooper(), TAG,
+ new NetworkCapabilities.Builder().build(), new LinkProperties(), 10 /* score */,
+ new NetworkAgentConfig.Builder().build(),
+ new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {};
+ return vpn;
+ }
+
+ @Test
+ public void testSetAndGetAppExclusionList() throws Exception {
+ final Vpn vpn = prepareVpnForVerifyAppExclusionList();
+ vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
+ verify(mVpnProfileStore)
+ .put(eq(vpn.getVpnAppExcludedForPackage(TEST_VPN_PKG)),
+ eq(HexDump.hexStringToByteArray(PKGS_BYTES)));
+ assertEquals(vpn.createUserAndRestrictedProfilesRanges(
+ primaryUser.id, null, Arrays.asList(PKGS)),
+ vpn.mNetworkCapabilities.getUids());
+ assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+ }
+
+ @Test
+ public void testSetAndGetAppExclusionListRestrictedUser() throws Exception {
+ final Vpn vpn = prepareVpnForVerifyAppExclusionList();
+ // Mock it to restricted profile
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(restrictedProfileA);
+ // Restricted users cannot configure VPNs
+ assertThrows(SecurityException.class,
+ () -> vpn.setAppExclusionList(TEST_VPN_PKG, new ArrayList<>()));
+ assertThrows(SecurityException.class, () -> vpn.getAppExclusionList(TEST_VPN_PKG));
+ }
+
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
index 5f9d1ff..13a85e8 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -86,11 +86,19 @@
private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
+ private static final int PID_SYSTEM = 1234;
+ private static final int PID_RED = 1235;
+ private static final int PID_BLUE = 1236;
+
private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
+ private static final String PACKAGE_SYSTEM = "android";
+ private static final String PACKAGE_RED = "RED";
+ private static final String PACKAGE_BLUE = "BLUE";
+
private static final long WAIT_TIMEOUT_MS = 500;
private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
private static final long BASE_BYTES = 7 * MB_IN_BYTES;
@@ -131,14 +139,15 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
final DataUsageRequest requestByApp = mStatsObservers.register(mContext, inputRequest,
- mUsageCallback, UID_RED, NetworkStatsAccess.Level.DEVICE);
+ mUsageCallback, PID_RED , UID_RED, PACKAGE_RED, NetworkStatsAccess.Level.DEVICE);
assertTrue(requestByApp.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, requestByApp.template));
assertEquals(thresholdTooLowBytes, requestByApp.thresholdInBytes);
// Verify the threshold requested by system uid won't be overridden.
final DataUsageRequest requestBySystem = mStatsObservers.register(mContext, inputRequest,
- mUsageCallback, Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ mUsageCallback, PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM,
+ NetworkStatsAccess.Level.DEVICE);
assertTrue(requestBySystem.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, requestBySystem.template));
assertEquals(1, requestBySystem.thresholdInBytes);
@@ -151,7 +160,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, request.template));
assertEquals(highThresholdBytes, request.thresholdInBytes);
@@ -163,13 +172,13 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
DataUsageRequest request1 = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request1.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, request1.template));
assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
DataUsageRequest request2 = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request2.requestId > request1.requestId);
assertTrue(Objects.equals(sTemplateWifi, request2.template));
assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
@@ -189,7 +198,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -209,7 +218,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- UID_RED, NetworkStatsAccess.Level.DEVICE);
+ PID_RED, UID_RED, PACKAGE_RED, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -237,7 +246,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -261,7 +270,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -291,7 +300,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ PID_SYSTEM, Process.SYSTEM_UID, PACKAGE_SYSTEM, NetworkStatsAccess.Level.DEVICE);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -322,7 +331,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- UID_RED, NetworkStatsAccess.Level.DEFAULT);
+ PID_RED, UID_RED, PACKAGE_SYSTEM , NetworkStatsAccess.Level.DEFAULT);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -355,7 +364,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
+ PID_BLUE, UID_BLUE, PACKAGE_BLUE, NetworkStatsAccess.Level.DEFAULT);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -387,7 +396,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- UID_BLUE, NetworkStatsAccess.Level.USER);
+ PID_BLUE, UID_BLUE, PACKAGE_BLUE, NetworkStatsAccess.Level.USER);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
@@ -420,7 +429,7 @@
DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
DataUsageRequest request = mStatsObservers.register(mContext, inputRequest, mUsageCallback,
- UID_RED, NetworkStatsAccess.Level.USER);
+ PID_RED, UID_RED, PACKAGE_RED, NetworkStatsAccess.Level.USER);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);