Merge "Add PACKAGE_USAGE_STATS permission to ConnectivityServiceIntegrationTest" into main
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index ed33cc9..bb5e330 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -87,6 +87,14 @@
if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
}
+// constants for passing in to 'bool shared' (for maps)
+static const bool PRIVATE = false;
+static const bool SHARED = true;
+
+// constants for passing in to 'bool optional' (for programs)
+static const bool MANDATORY = false;
+static const bool OPTIONAL = true;
+
// constants for passing in to 'bool egress'
static const bool INGRESS = false;
static const bool EGRESS = true;
@@ -104,12 +112,11 @@
static const bool UPDATETIME = true;
// constants for passing in to ignore_on_eng / ignore_on_user / ignore_on_userdebug
-// define's instead of static const due to tm-mainline-prod compiler static_assert limitations
-#define LOAD_ON_ENG false
-#define LOAD_ON_USER false
-#define LOAD_ON_USERDEBUG false
-#define IGNORE_ON_ENG true
-#define IGNORE_ON_USER true
-#define IGNORE_ON_USERDEBUG true
+static const bool LOAD_ON_ENG = false;
+static const bool LOAD_ON_USER = false;
+static const bool LOAD_ON_USERDEBUG = false;
+static const bool IGNORE_ON_ENG = true;
+static const bool IGNORE_ON_USER = true;
+static const bool IGNORE_ON_USERDEBUG = true;
#define KVER_4_14 KVER(4, 14, 0)
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 256dd6a..7a48e8c 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -59,18 +59,18 @@
#define TCP_FLAG8_OFF (TCP_FLAG32_OFF + 1)
// For maps netd does not need to access
-#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
- AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
- LOAD_ON_USER, LOAD_ON_USERDEBUG)
+#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
+ AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", \
+ PRIVATE, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \
+ LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd only needs read only access to
-#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
- AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
- LOAD_ON_USER, LOAD_ON_USERDEBUG)
+#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
+ AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", \
+ PRIVATE, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \
+ LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd needs to be able to read and write
#define DEFINE_BPF_MAP_RW_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
@@ -102,13 +102,13 @@
// A single-element configuration array, packet tracing is enabled when 'true'.
DEFINE_BPF_MAP_EXT(packet_trace_enabled_map, ARRAY, uint32_t, bool, 1,
- AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
+ AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
LOAD_ON_USER, LOAD_ON_USERDEBUG)
// A ring buffer on which packet information is pushed.
DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE,
- AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
+ AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
LOAD_ON_USER, LOAD_ON_USERDEBUG);
@@ -127,8 +127,8 @@
// which is loaded into netd and thus runs as netd uid/gid/selinux context)
#define DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, maxKV) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
- minKV, maxKV, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, \
- "fs_bpf_netd_readonly", "", false, false, false)
+ minKV, maxKV, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
+ "fs_bpf_netd_readonly", "", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
#define DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF)
@@ -139,8 +139,8 @@
// programs that only need to be usable by the system server
#define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, false, "fs_bpf_net_shared", \
- "", false, false, false)
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
+ "fs_bpf_net_shared", "", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
static __always_inline int is_system_uid(uint32_t uid) {
// MIN_SYSTEM_UID is AID_ROOT == 0, so uint32_t is *always* >= 0
@@ -506,8 +506,9 @@
// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace_user", AID_ROOT, AID_SYSTEM,
bpf_cgroup_ingress_trace_user, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, true,
- "fs_bpf_netd_readonly", "", true, false, true)
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ "fs_bpf_netd_readonly", "",
+ IGNORE_ON_ENG, LOAD_ON_USER, IGNORE_ON_USERDEBUG)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER(5, 8, 0));
}
@@ -515,8 +516,9 @@
// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace", AID_ROOT, AID_SYSTEM,
bpf_cgroup_ingress_trace, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false,
- "fs_bpf_netd_readonly", "", false, true, false)
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, INGRESS, TRACE_ON, KVER(5, 8, 0));
}
@@ -536,8 +538,9 @@
// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace_user", AID_ROOT, AID_SYSTEM,
bpf_cgroup_egress_trace_user, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, true,
- "fs_bpf_netd_readonly", "", true, false, true)
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER(5, 8, 0));
}
@@ -545,8 +548,9 @@
// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace", AID_ROOT, AID_SYSTEM,
bpf_cgroup_egress_trace, KVER(5, 8, 0), KVER_INF,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, false,
- "fs_bpf_netd_readonly", "", false, true, false)
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ "fs_bpf_netd_readonly", "",
+ LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
return bpf_traffic_account(skb, EGRESS, TRACE_ON, KVER(5, 8, 0));
}
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index 99a2ab4..8e47ea8 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017-2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
#ifndef LOG_TAG
-#define LOG_TAG "bpfloader"
+#define LOG_TAG "NetBpfLoad"
#endif
#include <arpa/inet.h>
@@ -93,26 +93,6 @@
BPF_PROG_TYPE_XDP,
};
-// Networking-related program types are limited to the Tethering Apex
-// to prevent things from breaking due to conflicts on mainline updates
-// (exception made for socket filters, ie. xt_bpf for potential use in iptables,
-// or for attaching to sockets directly)
-constexpr bpf_prog_type kPlatformAllowedProgTypes[] = {
- BPF_PROG_TYPE_KPROBE,
- BPF_PROG_TYPE_PERF_EVENT,
- BPF_PROG_TYPE_SOCKET_FILTER,
- BPF_PROG_TYPE_TRACEPOINT,
- BPF_PROG_TYPE_UNSPEC, // Will be replaced with fuse bpf program type
-};
-
-// see b/162057235. For arbitrary program types, the concern is that due to the lack of
-// SELinux access controls over BPF program attachpoints, we have no way to control the
-// attachment of programs to shared resources (or to detect when a shared resource
-// has one BPF program replace another that is attached there)
-constexpr bpf_prog_type kVendorAllowedProgTypes[] = {
- BPF_PROG_TYPE_SOCKET_FILTER,
-};
-
const android::bpf::Location locations[] = {
// S+ Tethering mainline module (network_stack): tether offload
@@ -157,22 +137,6 @@
.allowedProgTypes = kTetheringApexAllowedProgTypes,
.allowedProgTypesLength = arraysize(kTetheringApexAllowedProgTypes),
},
- // Core operating system
- {
- .dir = "/system/etc/bpf/",
- .prefix = "",
- .allowedDomainBitmask = domainToBitmask(domain::platform),
- .allowedProgTypes = kPlatformAllowedProgTypes,
- .allowedProgTypesLength = arraysize(kPlatformAllowedProgTypes),
- },
- // Vendor operating system
- {
- .dir = "/vendor/etc/bpf/",
- .prefix = "vendor/",
- .allowedDomainBitmask = domainToBitmask(domain::vendor),
- .allowedProgTypes = kVendorAllowedProgTypes,
- .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes),
- },
};
int loadAllElfObjects(const android::bpf::Location& location) {
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
index d817614..3bb758b 100644
--- a/netbpfload/loader.cpp
+++ b/netbpfload/loader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2018-2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "LibBpfLoader"
+#define LOG_TAG "NetBpfLoader"
#include <errno.h>
#include <fcntl.h>
@@ -98,14 +98,11 @@
constexpr const char* lookupSelinuxContext(const domain d, const char* const unspecified = "") {
switch (d) {
case domain::unspecified: return unspecified;
- case domain::platform: return "fs_bpf";
case domain::tethering: return "fs_bpf_tethering";
case domain::net_private: return "fs_bpf_net_private";
case domain::net_shared: return "fs_bpf_net_shared";
case domain::netd_readonly: return "fs_bpf_netd_readonly";
case domain::netd_shared: return "fs_bpf_netd_shared";
- case domain::vendor: return "fs_bpf_vendor";
- case domain::loader: return "fs_bpf_loader";
default: return "(unrecognized)";
}
}
@@ -130,14 +127,11 @@
constexpr const char* lookupPinSubdir(const domain d, const char* const unspecified = "") {
switch (d) {
case domain::unspecified: return unspecified;
- case domain::platform: return "/";
case domain::tethering: return "tethering/";
case domain::net_private: return "net_private/";
case domain::net_shared: return "net_shared/";
case domain::netd_readonly: return "netd_readonly/";
case domain::netd_shared: return "netd_shared/";
- case domain::vendor: return "vendor/";
- case domain::loader: return "loader/";
default: return "(unrecognized)";
}
};
diff --git a/netbpfload/loader.h b/netbpfload/loader.h
index cc8a942..a47e4da 100644
--- a/netbpfload/loader.h
+++ b/netbpfload/loader.h
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- * Android BPF library - public API
+ * Copyright (C) 2018-2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,27 +38,21 @@
enum class domain : int {
unrecognized = -1, // invalid for this version of the bpfloader
unspecified = 0, // means just use the default for that specific pin location
- platform, // fs_bpf /sys/fs/bpf
tethering, // (S+) fs_bpf_tethering /sys/fs/bpf/tethering
net_private, // (T+) fs_bpf_net_private /sys/fs/bpf/net_private
net_shared, // (T+) fs_bpf_net_shared /sys/fs/bpf/net_shared
netd_readonly, // (T+) fs_bpf_netd_readonly /sys/fs/bpf/netd_readonly
netd_shared, // (T+) fs_bpf_netd_shared /sys/fs/bpf/netd_shared
- vendor, // (T+) fs_bpf_vendor /sys/fs/bpf/vendor
- loader, // (U+) fs_bpf_loader /sys/fs/bpf/loader
};
// Note: this does not include domain::unrecognized, but does include domain::unspecified
static constexpr domain AllDomains[] = {
domain::unspecified,
- domain::platform,
domain::tethering,
domain::net_private,
domain::net_shared,
domain::netd_readonly,
domain::netd_shared,
- domain::vendor,
- domain::loader,
};
static constexpr bool unrecognized(domain d) {
diff --git a/netbpfload/netbpfload.rc b/netbpfload/netbpfload.rc
index fd6eaea..20fbb9f 100644
--- a/netbpfload/netbpfload.rc
+++ b/netbpfload/netbpfload.rc
@@ -3,7 +3,7 @@
# a tad earlier. There's no benefit to that though, since on 4.9+ P+ devices netd
# will just block until bpfloader finishes and sets the bpf.progs_loaded property.
#
-# It is important that we start bpfloader after:
+# It is important that we start netbpfload after:
# - /sys/fs/bpf is already mounted,
# - apex (incl. rollback) is initialized (so that in the future we can load bpf
# programs shipped as part of apex mainline modules)
@@ -15,9 +15,9 @@
# considered to have booted successfully.
#
on load_bpf_programs
- exec_start bpfloader
+ exec_start netbpfload
-service bpfloader /system/bin/bpfloader
+service netbpfload /system/bin/netbpfload
capabilities CHOWN SYS_ADMIN NET_ADMIN
# The following group memberships are a workaround for lack of DAC_OVERRIDE
# and allow us to open (among other things) files that we created and are
@@ -27,28 +27,28 @@
group root graphics network_stack net_admin net_bw_acct net_bw_stats net_raw system
user root
#
- # Set RLIMIT_MEMLOCK to 1GiB for bpfloader
+ # Set RLIMIT_MEMLOCK to 1GiB for netbpfload
#
- # Actually only 8MiB would be needed if bpfloader ran as its own uid.
+ # Actually only 8MiB would be needed if netbpfload ran as its own uid.
#
# However, while the rlimit is per-thread, the accounting is system wide.
# So, for example, if the graphics stack has already allocated 10MiB of
- # memlock data before bpfloader even gets a chance to run, it would fail
+ # memlock data before netbpfload even gets a chance to run, it would fail
# if its memlock rlimit is only 8MiB - since there would be none left for it.
#
- # bpfloader succeeding is critical to system health, since a failure will
+ # netbpfload succeeding is critical to system health, since a failure will
# cause netd crashloop and thus system server crashloop... and the only
# recovery is a full kernel reboot.
#
# We've had issues where devices would sometimes (rarely) boot into
- # a crashloop because bpfloader would occasionally lose a boot time
+ # a crashloop because netbpfload would occasionally lose a boot time
# race against the graphics stack's boot time locked memory allocation.
#
- # Thus bpfloader's memlock has to be 8MB higher then the locked memory
+ # Thus netbpfload's memlock has to be 8MB higher then the locked memory
# consumption of the root uid anywhere else in the system...
# But we don't know what that is for all possible devices...
#
- # Ideally, we'd simply grant bpfloader the IPC_LOCK capability and it
+ # Ideally, we'd simply grant netbpfload the IPC_LOCK capability and it
# would simply ignore it's memlock rlimit... but it turns that this
# capability is not even checked by the kernel's bpf system call.
#
@@ -57,29 +57,29 @@
rlimit memlock 1073741824 1073741824
oneshot
#
- # How to debug bootloops caused by 'bpfloader-failed'.
+ # How to debug bootloops caused by 'netbpfload-failed'.
#
# 1. On some lower RAM devices (like wembley) you may need to first enable developer mode
# (from the Settings app UI), and change the developer option "Logger buffer sizes"
# from the default (wembley: 64kB) to the maximum (1M) per log buffer.
# Otherwise buffer will overflow before you manage to dump it and you'll get useless logs.
#
- # 2. comment out 'reboot_on_failure reboot,bpfloader-failed' below
+ # 2. comment out 'reboot_on_failure reboot,netbpfload-failed' below
# 3. rebuild/reflash/reboot
- # 4. as the device is booting up capture bpfloader logs via:
- # adb logcat -s 'bpfloader:*' 'LibBpfLoader:*'
+ # 4. as the device is booting up capture netbpfload logs via:
+ # adb logcat -s 'NetBpfLoad:*' 'NetBpfLoader:*'
#
# something like:
- # $ adb reboot; sleep 1; adb wait-for-device; adb root; sleep 1; adb wait-for-device; adb logcat -s 'bpfloader:*' 'LibBpfLoader:*'
+ # $ adb reboot; sleep 1; adb wait-for-device; adb root; sleep 1; adb wait-for-device; adb logcat -s 'NetBpfLoad:*' 'NetBpfLoader:*'
# will take care of capturing logs as early as possible
#
- # 5. look through the logs from the kernel's bpf verifier that bpfloader dumps out,
+ # 5. look through the logs from the kernel's bpf verifier that netbpfload dumps out,
# it usually makes sense to search back from the end and find the particular
- # bpf verifier failure that caused bpfloader to terminate early with an error code.
+ # bpf verifier failure that caused netbpfload to terminate early with an error code.
# This will probably be something along the lines of 'too many jumps' or
# 'cannot prove return value is 0 or 1' or 'unsupported / unknown operation / helper',
# 'invalid bpf_context access', etc.
#
- reboot_on_failure reboot,bpfloader-failed
+ reboot_on_failure reboot,netbpfload-failed
# we're not really updatable, but want to be able to load bpf programs shipped in apexes
updatable
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index a090a54..fa92f10 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -129,6 +129,15 @@
RETURN_IF_NOT_OK(
attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
}
+
+ // This should trivially pass, since we just attached up above,
+ // but BPF_PROG_QUERY is only implemented on 4.19+ kernels.
+ if (bpf::isAtLeastKernelVersion(4, 19, 0)) {
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_EGRESS) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_INGRESS) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_CREATE) <= 0) abort();
+ }
+
return netdutils::status::ok;
}
diff --git a/service/src/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
index d94c8dc..c473444 100644
--- a/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -17,6 +17,8 @@
package com.android.server.connectivity;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -221,6 +223,19 @@
}
/**
+ * Returns whether the scorable has any of the PRIORITIZE_* capabilities.
+ *
+ * These capabilities code for customer slices, and a network that has one is a customer slice.
+ */
+ private boolean hasPrioritizedCapability(@NonNull final Scoreable nai) {
+ final NetworkCapabilities caps = nai.getCapsNoCopy();
+ final long anyPrioritizeCapability =
+ (1L << NET_CAPABILITY_PRIORITIZE_LATENCY)
+ | (1L << NET_CAPABILITY_PRIORITIZE_BANDWIDTH);
+ return 0 != (caps.getCapabilitiesInternal() & anyPrioritizeCapability);
+ }
+
+ /**
* Get the best network among a list of candidates according to policy.
* @param candidates the candidates
* @param currentSatisfier the current satisfier, or null if none
@@ -324,6 +339,12 @@
// change from the previous result. If there were, it's guaranteed candidates.size() > 0
// because accepted.size() > 0 above.
+ // If any network is not a slice with prioritized bandwidth or latency, don't choose one
+ // that is.
+ partitionInto(candidates, nai -> !hasPrioritizedCapability(nai), accepted, rejected);
+ if (accepted.size() == 1) return accepted.get(0);
+ if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
+
// If some of the networks have a better transport than others, keep only the ones with
// the best transports.
for (final int transport : PREFERRED_TRANSPORTS_ORDER) {
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 59a63f2..621759e 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -74,7 +74,10 @@
"framework-configinfrastructure",
"framework-connectivity.stubs.module_lib",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_defaults {
@@ -141,7 +144,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -169,7 +175,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -194,7 +203,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -223,7 +235,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -258,7 +273,10 @@
"//packages/modules/Wifi/framework/tests:__subpackages__",
"//packages/apps/Settings",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
errorprone: {
enabled: true,
// Error-prone checking only warns of problems when building. To make the build fail with
@@ -301,7 +319,10 @@
"//packages/modules/Bluetooth/android/app",
"//packages/modules/Wifi/service:__subpackages__",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -323,7 +344,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
java_library {
@@ -346,7 +370,10 @@
"com.android.tethering",
"//apex_available:platform",
],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
// Limited set of utilities for use by service-connectivity-mdns-standalone-build-test, to make sure
diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java
index 94af11b..f1546c0 100644
--- a/staticlibs/device/com/android/net/module/util/BpfUtils.java
+++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java
@@ -66,4 +66,6 @@
throws IOException;
private static native boolean native_detachSingleProgramFromCgroup(int type,
String programPath, String cgroupPath) throws IOException;
+ private static native int native_getProgramIdFromCgroup(int type, String cgroupPath)
+ throws IOException;
}
diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
index 27ca7b7..42f26f4 100644
--- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
+++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
@@ -168,32 +168,18 @@
*
* This is useful to ensure that if a module install is rolled back, flags are not left fully
* rolled out on a version where they have not been well tested.
+ *
+ * If the feature is disabled by default and enabled by flag push, this method should be used.
+ * If the feature is enabled by default and disabled by flag push (kill switch),
+ * {@link #isNetworkStackFeatureNotChickenedOut(Context, String)} should be used.
+ *
* @param context The global context information about an app environment.
* @param name The name of the property to look up.
* @return true if this feature is enabled, or false if disabled.
*/
public static boolean isNetworkStackFeatureEnabled(@NonNull Context context,
@NonNull String name) {
- return isNetworkStackFeatureEnabled(context, name, false /* defaultEnabled */);
- }
-
- /**
- * Check whether or not one specific experimental feature for a particular namespace from
- * {@link DeviceConfig} is enabled by comparing module package version
- * with current version of property. If this property version is valid, the corresponding
- * experimental feature would be enabled, otherwise disabled.
- *
- * This is useful to ensure that if a module install is rolled back, flags are not left fully
- * rolled out on a version where they have not been well tested.
- * @param context The global context information about an app environment.
- * @param name The name of the property to look up.
- * @param defaultEnabled The value to return if the property does not exist or its value is
- * null.
- * @return true if this feature is enabled, or false if disabled.
- */
- public static boolean isNetworkStackFeatureEnabled(@NonNull Context context,
- @NonNull String name, boolean defaultEnabled) {
- return isFeatureEnabled(NAMESPACE_CONNECTIVITY, name, defaultEnabled,
+ return isFeatureEnabled(NAMESPACE_CONNECTIVITY, name, false /* defaultEnabled */,
() -> getPackageVersion(context));
}
diff --git a/staticlibs/device/com/android/net/module/util/SocketUtils.java b/staticlibs/device/com/android/net/module/util/SocketUtils.java
index 9878ea5..5e6a6c6 100644
--- a/staticlibs/device/com/android/net/module/util/SocketUtils.java
+++ b/staticlibs/device/com/android/net/module/util/SocketUtils.java
@@ -19,6 +19,8 @@
import static android.net.util.SocketUtils.closeSocket;
import android.annotation.NonNull;
+import android.annotation.RequiresApi;
+import android.os.Build;
import android.system.NetlinkSocketAddress;
import java.io.FileDescriptor;
@@ -39,7 +41,7 @@
/**
* Make a socket address to communicate with netlink.
*/
- @NonNull
+ @NonNull @RequiresApi(Build.VERSION_CODES.S)
public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
return new NetlinkSocketAddress(portId, groupsMask);
}
diff --git a/staticlibs/lint-baseline.xml b/staticlibs/lint-baseline.xml
deleted file mode 100644
index d413b2a..0000000
--- a/staticlibs/lint-baseline.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.LinkProperties#getAddresses`"
- errorLine1=" final Collection<InetAddress> leftAddresses = left.getAddresses();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/LinkPropertiesUtils.java"
- line="158"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.LinkProperties#getAddresses`"
- errorLine1=" final Collection<InetAddress> rightAddresses = right.getAddresses();"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/LinkPropertiesUtils.java"
- line="159"
- column="62"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `android.net.NetworkStats#addEntry`"
- errorLine1=" stats = stats.addEntry(entry);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="113"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `new android.net.NetworkStats.Entry`"
- errorLine1=" return new android.net.NetworkStats.Entry("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="120"
- column="16"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 29): `new android.net.NetworkStats`"
- errorLine1=" android.net.NetworkStats stats = new android.net.NetworkStats(0L, 0);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/framework/com/android/net/module/util/NetworkStatsUtils.java"
- line="108"
- column="42"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `new android.system.NetlinkSocketAddress`"
- errorLine1=" return new NetlinkSocketAddress(portId, groupsMask);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/libs/net/common/device/com/android/net/module/util/SocketUtils.java"
- line="44"
- column="16"/>
- </issue>
-
-</issues>
\ No newline at end of file
diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
index 13f7cb3..9995cb9 100644
--- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
+++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
@@ -44,6 +44,11 @@
return syscall(__NR_bpf, cmd, &attr, sizeof(attr));
}
+// this version is meant for use with cmd's which mutate the argument
+inline int bpf(enum bpf_cmd cmd, bpf_attr *attr) {
+ return syscall(__NR_bpf, cmd, attr, sizeof(*attr));
+}
+
inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
uint32_t max_entries, uint32_t map_flags) {
return bpf(BPF_MAP_CREATE, {
@@ -160,6 +165,27 @@
});
}
+inline int queryProgram(const BPF_FD_TYPE cg_fd,
+ enum bpf_attach_type attach_type,
+ __u32 query_flags = 0,
+ __u32 attach_flags = 0) {
+ int prog_id = -1; // equivalent to an array of one integer.
+ bpf_attr arg = {
+ .query = {
+ .target_fd = BPF_FD_TO_U32(cg_fd),
+ .attach_type = attach_type,
+ .query_flags = query_flags,
+ .attach_flags = attach_flags,
+ .prog_ids = ptr_to_u64(&prog_id), // pointer to output array
+ .prog_cnt = 1, // in: space - nr of ints in the array, out: used
+ }
+ };
+ int v = bpf(BPF_PROG_QUERY, &arg);
+ if (v) return v; // error case
+ if (!arg.query.prog_cnt) return 0; // no program, kernel never returns zero id
+ return prog_id; // return actual id
+}
+
inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd,
const BPF_FD_TYPE cg_fd) {
return bpf(BPF_PROG_DETACH, {
diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
index cb06afb..ab83da6 100644
--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
+++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp
@@ -27,7 +27,7 @@
}
static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env,
- jobject clazz,
+ jclass clazz,
jstring iface) {
ScopedUtfChars interface(env, iface);
bool result = false;
@@ -43,7 +43,7 @@
// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
// /sys/fs/bpf/... direct-action
static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf(
- JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio,
+ JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
jshort proto, jstring bpfProgPath) {
ScopedUtfChars pathname(env, bpfProgPath);
int error = tcAddBpfFilter(ifIndex, ingress, prio, proto, pathname.c_str());
@@ -59,7 +59,7 @@
// action bpf object-pinned .. \
// drop
static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice(
- JNIEnv *env, jobject clazz, jint ifIndex, jshort prio, jshort proto,
+ JNIEnv *env, jclass clazz, jint ifIndex, jshort prio, jshort proto,
jint rateInBytesPerSec, jstring bpfProgPath) {
ScopedUtfChars pathname(env, bpfProgPath);
int error = tcAddIngressPoliceFilter(ifIndex, prio, proto, rateInBytesPerSec,
@@ -74,7 +74,7 @@
// tc filter del dev .. in/egress prio .. protocol ..
static void com_android_net_module_util_TcUtils_tcFilterDelDev(
- JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio,
+ JNIEnv *env, jclass clazz, jint ifIndex, jboolean ingress, jshort prio,
jshort proto) {
int error = tcDeleteFilter(ifIndex, ingress, prio, proto);
if (error) {
@@ -86,7 +86,7 @@
// tc qdisc add dev .. clsact
static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env,
- jobject clazz,
+ jclass clazz,
jint ifIndex) {
int error = tcAddQdiscClsact(ifIndex);
if (error) {
diff --git a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
index 0f2ebbd..cf09379 100644
--- a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
+++ b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp
@@ -32,7 +32,7 @@
// If attach fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_attachProgramToCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) {
+ jclass clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -62,7 +62,7 @@
// If detach fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_detachProgramFromCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring cgroupPath) {
+ jclass clazz, jint type, jstring cgroupPath) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -83,7 +83,7 @@
// If detach single program fails throw error and return false.
static jboolean com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup(JNIEnv *env,
- jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath) {
+ jclass clazz, jint type, jstring bpfProgPath, jstring cgroupPath) {
ScopedUtfChars dirPath(env, cgroupPath);
unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
@@ -110,6 +110,29 @@
return true;
}
+static jint com_android_net_module_util_BpfUtil_getProgramIdFromCgroup(JNIEnv *env,
+ jclass clazz, jint type, jstring cgroupPath) {
+
+ ScopedUtfChars dirPath(env, cgroupPath);
+ unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+ if (cg_fd == -1) {
+ jniThrowExceptionFmt(env, "java/io/IOException",
+ "Failed to open the cgroup directory %s: %s",
+ dirPath.c_str(), strerror(errno));
+ return -1;
+ }
+
+ int id = bpf::queryProgram(cg_fd, (bpf_attach_type) type);
+ if (id < 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException",
+ "Failed to query bpf program %d at %s: %s",
+ type, dirPath.c_str(), strerror(errno));
+ return -1;
+ }
+ return id; // may return 0 meaning none
+}
+
+
/*
* JNI registration.
*/
@@ -121,6 +144,8 @@
(void*) com_android_net_module_util_BpfUtil_detachProgramFromCgroup },
{ "native_detachSingleProgramFromCgroup", "(ILjava/lang/String;Ljava/lang/String;)Z",
(void*) com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup },
+ { "native_getProgramIdFromCgroup", "(ILjava/lang/String;)I",
+ (void*) com_android_net_module_util_BpfUtil_getProgramIdFromCgroup },
};
int register_com_android_net_module_util_BpfUtils(JNIEnv* env, char const* class_name) {
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
index 75b6250..06b3e2f 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java
@@ -305,15 +305,12 @@
assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
- // Follow defaultEnabled if the flag is not set
+ // If the flag is not set feature is disabled
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY,
TEST_EXPERIMENT_FLAG));
doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING,
TEST_EXPERIMENT_FLAG));
- assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG,
- false /* defaultEnabled */));
- assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG,
- true /* defaultEnabled */));
+ assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG));
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 89a55a7..b9ed56a 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -198,7 +198,8 @@
protected void tearDown() throws Exception {
executeShellCommand("cmd netpolicy stop-watching");
mServiceClient.unbind();
- if (mLock.isHeld()) mLock.release();
+ final PowerManager.WakeLock lock = mLock;
+ if (null != lock && lock.isHeld()) lock.release();
}
protected int getUid(String packageName) throws Exception {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index d2c9481..62614c1 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -47,6 +47,7 @@
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
@@ -3591,6 +3592,15 @@
}
}
+ private void setUidFirewallRule(final int chain, final int uid, final int rule) {
+ try {
+ mCm.setUidFirewallRule(chain, uid, rule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ }
+
private static final boolean EXPECT_OPEN = false;
private static final boolean EXPECT_CLOSE = true;
@@ -3599,6 +3609,8 @@
runWithShellPermissionIdentity(() -> {
// Firewall chain status will be restored after the test.
final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain);
+ final int myUid = Process.myUid();
+ final int previousMyUidFirewallRule = mCm.getUidFirewallRule(chain, myUid);
final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, targetUid);
final Socket socket = new Socket(TEST_HOST, HTTP_PORT);
socket.setSoTimeout(NETWORK_REQUEST_TIMEOUT_MS);
@@ -3606,12 +3618,12 @@
mCm.setFirewallChainEnabled(chain, false /* enable */);
assertSocketOpen(socket);
- try {
- mCm.setUidFirewallRule(chain, targetUid, rule);
- } catch (IllegalStateException ignored) {
- // Removing match causes an exception when the rule entry for the uid does
- // not exist. But this is fine and can be ignored.
+ setUidFirewallRule(chain, targetUid, rule);
+ if (targetUid != myUid) {
+ // If this test does not set rule on myUid, remove existing rule on myUid
+ setUidFirewallRule(chain, myUid, FIREWALL_RULE_DEFAULT);
}
+
mCm.setFirewallChainEnabled(chain, true /* enable */);
if (expectClose) {
@@ -3624,11 +3636,9 @@
mCm.setFirewallChainEnabled(chain, wasChainEnabled);
}, /* cleanup */ () -> {
// Restore the uid firewall rule status
- try {
- mCm.setUidFirewallRule(chain, targetUid, previousUidFirewallRule);
- } catch (IllegalStateException ignored) {
- // Removing match causes an exception when the rule entry for the uid does
- // not exist. But this is fine and can be ignored.
+ setUidFirewallRule(chain, targetUid, previousUidFirewallRule);
+ if (targetUid != myUid) {
+ setUidFirewallRule(chain, myUid, previousMyUidFirewallRule);
}
}, /* cleanup */ () -> {
socket.close();
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index 805dd65..6b7954a 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -22,6 +22,7 @@
import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
@@ -34,12 +35,14 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Ikev2VpnProfile;
import android.net.IpSecAlgorithm;
@@ -60,11 +63,7 @@
import com.android.internal.util.HexDump;
import com.android.networkstack.apishim.ConstantsShim;
-import com.android.networkstack.apishim.Ikev2VpnProfileBuilderShimImpl;
-import com.android.networkstack.apishim.Ikev2VpnProfileShimImpl;
import com.android.networkstack.apishim.VpnManagerShimImpl;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileBuilderShim;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileShim;
import com.android.networkstack.apishim.common.VpnManagerShim;
import com.android.networkstack.apishim.common.VpnProfileStateShim;
import com.android.testutils.DevSdkIgnoreRule;
@@ -75,6 +74,7 @@
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -203,6 +203,12 @@
mUserCertKey = generateRandomCertAndKeyPair();
}
+ @Before
+ public void setUp() {
+ assumeFalse("Skipping test because watches don't support VPN",
+ sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+ }
+
@After
public void tearDown() {
for (TestableNetworkCallback callback : mCallbacksToUnregister) {
@@ -210,6 +216,15 @@
}
setAppop(AppOpsManager.OP_ACTIVATE_VPN, false);
setAppop(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, false);
+
+ // Make sure the VpnProfile is not provisioned already.
+ sVpnMgr.stopProvisionedVpnProfile();
+
+ try {
+ sVpnMgr.startProvisionedVpnProfile();
+ fail("Expected SecurityException for missing consent");
+ } catch (SecurityException expected) {
+ }
}
/**
@@ -227,28 +242,25 @@
}
private Ikev2VpnProfile buildIkev2VpnProfileCommon(
- @NonNull Ikev2VpnProfileBuilderShim builderShim, boolean isRestrictedToTestNetworks,
+ @NonNull Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks,
boolean requiresValidation, boolean automaticIpVersionSelectionEnabled,
boolean automaticNattKeepaliveTimerEnabled) throws Exception {
- builderShim.setBypassable(true)
+ builder.setBypassable(true)
.setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
- if (TestUtils.shouldTestTApis()) {
- builderShim.setRequiresInternetValidation(requiresValidation);
+ if (isAtLeastT()) {
+ builder.setRequiresInternetValidation(requiresValidation);
}
- if (TestUtils.shouldTestUApis()) {
- builderShim.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled);
- builderShim.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled);
+ if (isAtLeastU()) {
+ builder.setAutomaticIpVersionSelectionEnabled(automaticIpVersionSelectionEnabled);
+ builder.setAutomaticNattKeepaliveTimerEnabled(automaticNattKeepaliveTimerEnabled);
}
- // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
- // method and is not defined in shims.
// TODO: replace it in alternative way to remove the hidden method usage
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -264,16 +276,14 @@
? IkeSessionTestUtils.IKE_PARAMS_V6 : IkeSessionTestUtils.IKE_PARAMS_V4,
IkeSessionTestUtils.CHILD_PARAMS);
- final Ikev2VpnProfileBuilderShim builderShim =
- Ikev2VpnProfileBuilderShimImpl.newInstance(params)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(params)
.setRequiresInternetValidation(requiresValidation)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
- // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
- // method and is not defined in shims.
+
// TODO: replace it in alternative way to remove the hidden method usage
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -283,8 +293,8 @@
private Ikev2VpnProfile buildIkev2VpnProfilePsk(@NonNull String remote,
boolean isRestrictedToTestNetworks, boolean requiresValidation)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(remote, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
requiresValidation, false /* automaticIpVersionSelectionEnabled */,
@@ -293,8 +303,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
false /* requiresValidation */, false /* automaticIpVersionSelectionEnabled */,
@@ -303,8 +313,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthDigitalSignature(
mUserCertKey.cert, mUserCertKey.key, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
@@ -347,7 +357,6 @@
@Test
public void testBuildIkev2VpnProfileWithIkeTunnelConnectionParams() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
- assumeTrue(TestUtils.shouldTestTApis());
final IkeTunnelConnectionParams expectedParams = new IkeTunnelConnectionParams(
IkeSessionTestUtils.IKE_PARAMS_V6, IkeSessionTestUtils.CHILD_PARAMS);
@@ -567,7 +576,7 @@
// regardless of its value. However, there is a race in Vpn(see b/228574221) that VPN may
// misuse VPN network itself as the underlying network. The fix is not available without
// SDK > T platform. Thus, verify this only on T+ platform.
- if (!requiresValidation && TestUtils.shouldTestTApis()) {
+ if (!requiresValidation && isAtLeastT()) {
cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, TIMEOUT_MS,
entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
.hasCapability(NET_CAPABILITY_VALIDATED));
@@ -647,7 +656,6 @@
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileV4WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
}
@@ -660,35 +668,30 @@
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileV6WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, false /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV4() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV4WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV6() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, false /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@Test @IgnoreUpTo(SC_V2)
public void testStartStopVpnProfileIkeTunConnParamsV6WithValidation() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, true /* requiresValidation */,
false /* testSessionKey */, true /* testIkeTunConnParams */);
}
@@ -696,7 +699,6 @@
@IgnoreUpTo(SC_V2)
@Test
public void testStartProvisionedVpnV4ProfileSession() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(false /* testIpv6Only */, false /* requiresValidation */,
true /* testSessionKey */, false /* testIkeTunConnParams */);
}
@@ -704,59 +706,44 @@
@IgnoreUpTo(SC_V2)
@Test
public void testStartProvisionedVpnV6ProfileSession() throws Exception {
- assumeTrue(TestUtils.shouldTestTApis());
doTestStartStopVpnProfile(true /* testIpv6Only */, false /* requiresValidation */,
true /* testSessionKey */, false /* testIkeTunConnParams */);
}
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
@Test
public void testBuildIkev2VpnProfileWithAutomaticNattKeepaliveTimerEnabled() throws Exception {
- // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
- // 34 shims, and @IgnoreUpTo does not check that.
- assumeTrue(TestUtils.shouldTestUApis());
-
final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
- Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
- assertFalse(shimWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled());
+ assertFalse(profileWithDefaultValue.isAutomaticNattKeepaliveTimerEnabled());
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
false /* isRestrictedToTestNetworks */,
false /* requiresValidation */,
false /* automaticIpVersionSelectionEnabled */,
true /* automaticNattKeepaliveTimerEnabled */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
- Ikev2VpnProfileShimImpl.newInstance(profile);
- assertTrue(shim.isAutomaticNattKeepaliveTimerEnabled());
+ assertTrue(profile.isAutomaticNattKeepaliveTimerEnabled());
}
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
@Test
public void testBuildIkev2VpnProfileWithAutomaticIpVersionSelectionEnabled() throws Exception {
- // Cannot use @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) because this test also requires API
- // 34 shims, and @IgnoreUpTo does not check that.
- assumeTrue(TestUtils.shouldTestUApis());
-
final Ikev2VpnProfile profileWithDefaultValue = buildIkev2VpnProfilePsk(TEST_SERVER_ADDR_V6,
false /* isRestrictedToTestNetworks */, false /* requiresValidation */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shimWithDefaultValue =
- Ikev2VpnProfileShimImpl.newInstance(profileWithDefaultValue);
- assertFalse(shimWithDefaultValue.isAutomaticIpVersionSelectionEnabled());
+ assertFalse(profileWithDefaultValue.isAutomaticIpVersionSelectionEnabled());
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthPsk(TEST_PSK);
final Ikev2VpnProfile profile = buildIkev2VpnProfileCommon(builder,
false /* isRestrictedToTestNetworks */,
false /* requiresValidation */,
true /* automaticIpVersionSelectionEnabled */,
false /* automaticNattKeepaliveTimerEnabled */);
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shim =
- Ikev2VpnProfileShimImpl.newInstance(profile);
- assertTrue(shim.isAutomaticIpVersionSelectionEnabled());
+ assertTrue(profile.isAutomaticIpVersionSelectionEnabled());
}
private static class CertificateAndKey {
diff --git a/tests/cts/net/src/android/net/cts/VpnServiceTest.java b/tests/cts/net/src/android/net/cts/VpnServiceTest.java
index 5c7b5ca..f343e83 100644
--- a/tests/cts/net/src/android/net/cts/VpnServiceTest.java
+++ b/tests/cts/net/src/android/net/cts/VpnServiceTest.java
@@ -15,12 +15,28 @@
*/
package android.net.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import android.test.AndroidTestCase;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.net.DatagramSocket;
import java.net.Socket;
@@ -30,12 +46,21 @@
* blocks us from writing tests for positive cases. For now we only test for
* negative cases, and we will try to cover the rest in the future.
*/
-public class VpnServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class VpnServiceTest {
private static final String TAG = VpnServiceTest.class.getSimpleName();
+ private final Context mContext = InstrumentationRegistry.getContext();
private VpnService mVpnService = new VpnService();
+ @Before
+ public void setUp() {
+ assumeFalse("Skipping test because watches don't support VPN",
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+ }
+
+ @Test
@AppModeFull(reason = "PackageManager#queryIntentActivities cannot access in instant app mode")
public void testPrepare() throws Exception {
// Should never return null since we are not prepared.
@@ -47,6 +72,7 @@
assertEquals(1, count);
}
+ @Test
@AppModeFull(reason = "establish() requires prepare(), which requires PackageManager access")
public void testEstablish() throws Exception {
ParcelFileDescriptor descriptor = null;
@@ -63,6 +89,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_DatagramSocket() throws Exception {
DatagramSocket socket = new DatagramSocket();
@@ -78,6 +105,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_Socket() throws Exception {
Socket socket = new Socket();
@@ -93,6 +121,7 @@
}
}
+ @Test
@AppModeFull(reason = "Protecting sockets requires prepare(), which requires PackageManager")
public void testProtect_int() throws Exception {
DatagramSocket socket = new DatagramSocket();
@@ -114,6 +143,7 @@
}
}
+ @Test
public void testTunDevice() throws Exception {
File file = new File("/dev/tun");
assertTrue(file.exists());
diff --git a/tests/unit/java/android/net/VpnManagerTest.java b/tests/unit/java/android/net/VpnManagerTest.java
index 532081a..2ab4e45 100644
--- a/tests/unit/java/android/net/VpnManagerTest.java
+++ b/tests/unit/java/android/net/VpnManagerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
@@ -27,11 +28,13 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.test.mock.MockContext;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.MessageUtils;
@@ -47,6 +50,7 @@
@RunWith(DevSdkIgnoreRunner.class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class VpnManagerTest {
+
private static final String PKG_NAME = "fooPackage";
private static final String SESSION_NAME_STRING = "testSession";
@@ -66,6 +70,9 @@
@Before
public void setUp() throws Exception {
+ assumeFalse("Skipping test because watches don't support VPN",
+ InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH));
mMockService = mock(IVpnManager.class);
mVpnManager = new VpnManager(mMockContext, mMockService);
}
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
index 1e3f389..87f7369 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -18,9 +18,12 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL as NET_CAP_PORTAL
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET as NET_CAP_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH as NET_CAP_PRIO_BW
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkScore.KEEP_CONNECTED_NONE
+import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY
import android.net.NetworkScore.POLICY_EXITING as EXITING
import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY as PRIMARY
import android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI as YIELD_TO_BAD_WIFI
@@ -50,8 +53,8 @@
class NetworkRankerTest(private val activelyPreferBadWifi: Boolean) {
private val mRanker = NetworkRanker(NetworkRanker.Configuration(activelyPreferBadWifi))
- private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities)
- : NetworkRanker.Scoreable {
+ private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities) :
+ NetworkRanker.Scoreable {
override fun getScore() = sc
override fun getCapsNoCopy(): NetworkCapabilities = nc
}
@@ -196,4 +199,41 @@
val badExitingWifi = TestScore(score(EVER_EVALUATED, EVER_VALIDATED, EXITING), CAPS_WIFI)
assertEquals(cell, rank(cell, badExitingWifi))
}
+
+ @Test
+ fun testValidatedPolicyStrongerThanSlice() {
+ val unvalidatedNonslice = TestScore(score(EVER_EVALUATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val slice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(slice, rank(slice, unvalidatedNonslice))
+ }
+
+ @Test
+ fun testPrimaryPolicyStrongerThanSlice() {
+ val nonslice = TestScore(score(EVER_EVALUATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val primarySlice = TestScore(score(EVER_EVALUATED, POLICY_TRANSPORT_PRIMARY),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(primarySlice, rank(nonslice, primarySlice))
+ }
+
+ @Test
+ fun testPreferNonSlices() {
+ // Slices lose to non-slices for general ranking
+ val nonslice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val slice = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(nonslice, rank(slice, nonslice))
+ }
+
+ @Test
+ fun testSlicePolicyStrongerThanTransport() {
+ val nonSliceCell = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_CELLULAR, NET_CAP_INTERNET))
+ val sliceWifi = TestScore(score(EVER_EVALUATED, IS_VALIDATED),
+ caps(TRANSPORT_WIFI, NET_CAP_INTERNET, NET_CAP_PRIO_BW))
+ assertEquals(nonSliceCell, rank(nonSliceCell, sliceWifi))
+ }
}