Merge "Add a test to check if the VPN type is set or not"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 5a08b23..d3b9393 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -156,7 +156,5 @@
sdk {
name: "tethering-module-sdk",
- java_sdk_libs: [
- "framework-tethering",
- ],
+ bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
}
diff --git a/Tethering/bpf_progs/Android.bp b/Tethering/bpf_progs/Android.bp
index 289d75d..5b00dfe 100644
--- a/Tethering/bpf_progs/Android.bp
+++ b/Tethering/bpf_progs/Android.bp
@@ -48,10 +48,6 @@
"-Wall",
"-Werror",
],
- include_dirs: [
- // TODO: get rid of system/netd.
- "system/netd/bpf_progs", // for bpf_net_helpers.h
- ],
}
bpf {
@@ -61,8 +57,4 @@
"-Wall",
"-Werror",
],
- include_dirs: [
- // TODO: get rid of system/netd.
- "system/netd/bpf_progs", // for bpf_net_helpers.h
- ],
}
diff --git a/Tethering/bpf_progs/bpf_net_helpers.h b/Tethering/bpf_progs/bpf_net_helpers.h
new file mode 100644
index 0000000..c798580
--- /dev/null
+++ b/Tethering/bpf_progs/bpf_net_helpers.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/bpf.h>
+#include <linux/if_packet.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+// this returns 0 iff skb->sk is NULL
+static uint64_t (*bpf_get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie;
+
+static uint32_t (*bpf_get_socket_uid)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_uid;
+
+static int (*bpf_skb_pull_data)(struct __sk_buff* skb, __u32 len) = (void*)BPF_FUNC_skb_pull_data;
+
+static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
+ int len) = (void*)BPF_FUNC_skb_load_bytes;
+
+static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
+ __u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
+
+static int64_t (*bpf_csum_diff)(__be32* from, __u32 from_size, __be32* to, __u32 to_size,
+ __wsum seed) = (void*)BPF_FUNC_csum_diff;
+
+static int64_t (*bpf_csum_update)(struct __sk_buff* skb, __wsum csum) = (void*)BPF_FUNC_csum_update;
+
+static int (*bpf_skb_change_proto)(struct __sk_buff* skb, __be16 proto,
+ __u64 flags) = (void*)BPF_FUNC_skb_change_proto;
+static int (*bpf_l3_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
+ __u64 flags) = (void*)BPF_FUNC_l3_csum_replace;
+static int (*bpf_l4_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
+ __u64 flags) = (void*)BPF_FUNC_l4_csum_replace;
+static int (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void*)BPF_FUNC_redirect;
+static int (*bpf_redirect_map)(const struct bpf_map_def* map, __u32 key,
+ __u64 flags) = (void*)BPF_FUNC_redirect_map;
+
+static int (*bpf_skb_change_head)(struct __sk_buff* skb, __u32 head_room,
+ __u64 flags) = (void*)BPF_FUNC_skb_change_head;
+static int (*bpf_skb_adjust_room)(struct __sk_buff* skb, __s32 len_diff, __u32 mode,
+ __u64 flags) = (void*)BPF_FUNC_skb_adjust_room;
+
+// Android only supports little endian architectures
+#define htons(x) (__builtin_constant_p(x) ? ___constant_swab16(x) : __builtin_bswap16(x))
+#define htonl(x) (__builtin_constant_p(x) ? ___constant_swab32(x) : __builtin_bswap32(x))
+#define ntohs(x) htons(x)
+#define ntohl(x) htonl(x)
+
+static inline __always_inline __unused bool is_received_skb(struct __sk_buff* skb) {
+ return skb->pkt_type == PACKET_HOST || skb->pkt_type == PACKET_BROADCAST ||
+ skb->pkt_type == PACKET_MULTICAST;
+}
+
+// try to make the first 'len' header bytes readable via direct packet access
+static inline __always_inline void try_make_readable(struct __sk_buff* skb, int len) {
+ if (len > skb->len) len = skb->len;
+ if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
+}
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 8adcbd9..36a2f10 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -48,6 +48,7 @@
import android.net.util.SharedLog;
import android.net.util.TetheringUtils.ForwardedStats;
import android.os.Handler;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.text.TextUtils;
import android.util.Log;
@@ -773,6 +774,12 @@
}
pw.decreaseIndent();
+ pw.println("BPF stats:");
+ pw.increaseIndent();
+ dumpBpfStats(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("Forwarding rules:");
pw.increaseIndent();
dumpIpv6UpstreamRules(pw);
@@ -800,6 +807,22 @@
upstreamIfindex), stats.toString()));
}
}
+ private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
+ try (BpfMap<TetherStatsKey, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
+ if (map == null) {
+ pw.println("No BPF stats map");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("<empty>");
+ }
+ map.forEach((k, v) -> {
+ pw.println(String.format("%s: %s", k, v));
+ });
+ } catch (ErrnoException e) {
+ pw.println("Error dumping BPF stats map: " + e);
+ }
+ }
private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) {
if (mIpv6ForwardingRules.size() == 0) {
@@ -849,7 +872,7 @@
}
}
- private String ipv4RuleToString(Tether4Key key, Tether4Value value) {
+ private String ipv4RuleToString(long now, Tether4Key key, Tether4Value value) {
final String private4, public4, dst4;
try {
private4 = InetAddress.getByAddress(key.src4).getHostAddress();
@@ -858,29 +881,43 @@
} catch (UnknownHostException impossible) {
throw new AssertionError("4-byte array not valid IPv4 address!");
}
- return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d",
+ long ageMs = (now - value.lastUsed) / 1_000_000;
+ return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d %dms",
key.dstMac, key.iif, getIfName(key.iif), private4, key.srcPort,
value.oif, getIfName(value.oif),
- public4, value.srcPort, dst4, key.dstPort);
+ public4, value.srcPort, dst4, key.dstPort, ageMs);
+ }
+
+ private void dumpIpv4ForwardingRuleMap(long now, BpfMap<Tether4Key, Tether4Value> map,
+ IndentingPrintWriter pw) throws ErrnoException {
+ if (map == null) {
+ pw.println("No IPv4 support");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("No rules");
+ return;
+ }
+ map.forEach((k, v) -> pw.println(ipv4RuleToString(now, k, v)));
}
private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) {
- try (BpfMap<Tether4Key, Tether4Value> map = mDeps.getBpfUpstream4Map()) {
- if (map == null) {
- pw.println("No IPv4 support");
- return;
- }
- if (map.isEmpty()) {
- pw.println("No IPv4 rules");
- return;
- }
- pw.println("IPv4: [inDstMac] iif(iface) src -> nat -> dst");
+ final long now = SystemClock.elapsedRealtimeNanos();
+
+ try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
+ BpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) {
+ pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst");
pw.increaseIndent();
- map.forEach((k, v) -> pw.println(ipv4RuleToString(k, v)));
+ dumpIpv4ForwardingRuleMap(now, upstreamMap, pw);
+ pw.decreaseIndent();
+
+ pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst");
+ pw.increaseIndent();
+ dumpIpv4ForwardingRuleMap(now, downstreamMap, pw);
+ pw.decreaseIndent();
} catch (ErrnoException e) {
pw.println("Error dumping IPv4 map: " + e);
}
- pw.decreaseIndent();
}
/**
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 90d821b..3a07db3 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -817,6 +817,7 @@
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
final TransportInfo originalTransportInfo = getTransportInfo();
+ final Set<Integer> originalSubIds = getSubscriptionIds();
clearAll();
if (0 != (originalCapabilities & NET_CAPABILITY_NOT_RESTRICTED)) {
// If the test network is not restricted, then it is only allowed to declare some
@@ -825,6 +826,9 @@
mTransportTypes =
(originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS)
| (1 << TRANSPORT_TEST);
+
+ // SubIds are only allowed for Test Networks that only declare TRANSPORT_TEST.
+ setSubscriptionIds(originalSubIds);
} else {
// If the test transport is restricted, then it may declare any transport.
mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST));
@@ -1565,6 +1569,28 @@
}
/**
+ * Compare if the given NetworkCapabilities have the same UIDs.
+ *
+ * @hide
+ */
+ public static boolean hasSameUids(@Nullable NetworkCapabilities nc1,
+ @Nullable NetworkCapabilities nc2) {
+ final Set<UidRange> uids1 = (nc1 == null) ? null : nc1.mUids;
+ final Set<UidRange> uids2 = (nc2 == null) ? null : nc2.mUids;
+ if (null == uids1) return null == uids2;
+ if (null == uids2) return false;
+ // Make a copy so it can be mutated to check that all ranges in uids2 also are in uids.
+ final Set<UidRange> uids = new ArraySet<>(uids2);
+ for (UidRange range : uids1) {
+ if (!uids.contains(range)) {
+ return false;
+ }
+ uids.remove(range);
+ }
+ return uids.isEmpty();
+ }
+
+ /**
* Tests if the set of UIDs that this network applies to is the same as the passed network.
* <p>
* This test only checks whether equal range objects are in both sets. It will
@@ -1580,19 +1606,7 @@
*/
@VisibleForTesting
public boolean equalsUids(@NonNull NetworkCapabilities nc) {
- Set<UidRange> comparedUids = nc.mUids;
- if (null == comparedUids) return null == mUids;
- if (null == mUids) return false;
- // Make a copy so it can be mutated to check that all ranges in mUids
- // also are in uids.
- final Set<UidRange> uids = new ArraySet<>(mUids);
- for (UidRange range : comparedUids) {
- if (!uids.contains(range)) {
- return false;
- }
- uids.remove(range);
- }
- return uids.isEmpty();
+ return hasSameUids(nc, this);
}
/**
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 15b666a..9d318cd 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -79,6 +79,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
@@ -398,6 +400,32 @@
}
/**
+ * The priority value is used when issue uid ranges rules to netd. Netd will use the priority
+ * value and uid ranges to generate corresponding ip rules specific to the given preference.
+ * Thus, any device originated data traffic of the applied uids can be routed to the altered
+ * default network which has highest priority.
+ *
+ * Note: The priority value should be in 0~1000. Larger value means lower priority, see
+ * {@link NativeUidRangeConfig}.
+ */
+ // This is default priority value for those NetworkRequests which doesn't have preference to
+ // alter default network and use the global one.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_NONE = 0;
+ // Used by automotive devices to set the network preferences used to direct traffic at an
+ // application level. See {@link #setOemNetworkPreference}.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_OEM = 10;
+ // Request that a user profile is put by default on a network matching a given preference.
+ // See {@link #setProfileNetworkPreference}.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_PROFILE = 20;
+ // Set by MOBILE_DATA_PREFERRED_UIDS setting. Use mobile data in preference even when
+ // higher-priority networks are connected.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED = 30;
+
+ /**
* used internally to clear a wakelock when transitioning
* from one net to another. Clear happens when we get a new
* network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
@@ -1516,7 +1544,7 @@
}
// Note that registering observer for setting do not get initial callback when registering,
- // callers might have self-initialization to update status if need.
+ // callers must fetch the initial value of the setting themselves if needed.
private void registerSettingsCallbacks() {
// Watch for global HTTP proxy changes.
mSettingsObserver.observe(
@@ -2596,6 +2624,12 @@
"ConnectivityService");
}
+ private void enforceManageTestNetworksPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ "ConnectivityService");
+ }
+
private boolean checkNetworkStackPermission() {
return checkAnyPermissionOf(
android.Manifest.permission.NETWORK_STACK,
@@ -4146,8 +4180,10 @@
final NetworkAgentInfo satisfier = nri.getSatisfier();
if (null != satisfier) {
try {
+ // TODO: Passing default network priority to netd.
mNetd.networkRemoveUidRanges(satisfier.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
} catch (RemoteException e) {
loge("Exception setting network preference default network", e);
}
@@ -5592,6 +5628,13 @@
// maximum limit of registered callbacks per UID.
final int mAsUid;
+ // Default network priority of this request.
+ private final int mDefaultNetworkPriority;
+
+ int getDefaultNetworkPriority() {
+ return mDefaultNetworkPriority;
+ }
+
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
// callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
// maintained for keying off of. This is only a concern when the original nri
@@ -5621,12 +5664,13 @@
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
@Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
- this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
+ this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag,
+ DEFAULT_NETWORK_PRIORITY_NONE);
}
NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
+ @Nullable String callingAttributionTag, final int defaultNetworkPriority) {
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
mNetworkRequestForCallback = requestForCallback;
@@ -5644,6 +5688,7 @@
*/
mCallbackFlags = NetworkCallback.FLAG_NONE;
mCallingAttributionTag = callingAttributionTag;
+ mDefaultNetworkPriority = defaultNetworkPriority;
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@@ -5673,6 +5718,7 @@
mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
+ mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
linkDeathRecipient();
}
@@ -5712,15 +5758,18 @@
mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
linkDeathRecipient();
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
- this(asUid, Collections.singletonList(r));
+ this(asUid, Collections.singletonList(r), DEFAULT_NETWORK_PRIORITY_NONE);
}
- NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
- this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
+ final int defaultNetworkPriority) {
+ this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */,
+ defaultNetworkPriority);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -7300,6 +7349,8 @@
mDnsManager.updateTransportsForNetwork(
nai.network.getNetId(), newNc.getTransportTypes());
}
+
+ maybeSendProxyBroadcast(nai, prevNc, newNc);
}
/** Convenience method to update the capabilities for a given network. */
@@ -7377,9 +7428,13 @@
maybeCloseSockets(nai, ranges, exemptUids);
try {
if (add) {
- mNetd.networkAddUidRanges(nai.network.netId, ranges);
+ // TODO: Passing default network priority to netd.
+ mNetd.networkAddUidRanges(nai.network.netId, ranges
+ /* DEFAULT_NETWORK_PRIORITY_NONE */);
} else {
- mNetd.networkRemoveUidRanges(nai.network.netId, ranges);
+ // TODO: Passing default network priority to netd.
+ mNetd.networkRemoveUidRanges(nai.network.netId, ranges
+ /* DEFAULT_NETWORK_PRIORITY_NONE */);
}
} catch (Exception e) {
loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
@@ -7388,6 +7443,30 @@
maybeCloseSockets(nai, ranges, exemptUids);
}
+ private boolean isProxySetOnAnyDefaultNetwork() {
+ ensureRunningOnConnectivityServiceThread();
+ for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
+ final NetworkAgentInfo nai = nri.getSatisfier();
+ if (nai != null && nai.linkProperties.getHttpProxy() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void maybeSendProxyBroadcast(NetworkAgentInfo nai, NetworkCapabilities prevNc,
+ NetworkCapabilities newNc) {
+ // When the apps moved from/to a VPN, a proxy broadcast is needed to inform the apps that
+ // the proxy might be changed since the default network satisfied by the apps might also
+ // changed.
+ // TODO: Try to track the default network that apps use and only send a proxy broadcast when
+ // that happens to prevent false alarms.
+ if (nai.isVPN() && nai.everConnected && !NetworkCapabilities.hasSameUids(prevNc, newNc)
+ && (nai.linkProperties.getHttpProxy() != null || isProxySetOnAnyDefaultNetwork())) {
+ mProxyTracker.sendProxyBroadcast();
+ }
+ }
+
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) {
Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
@@ -7690,14 +7769,18 @@
+ " any applications to set as the default." + nri);
}
if (null != newDefaultNetwork) {
+ // TODO: Passing default network priority to netd.
mNetd.networkAddUidRanges(
newDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
}
if (null != oldDefaultNetwork) {
+ // TODO: Passing default network priority to netd.
mNetd.networkRemoveUidRanges(
oldDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
}
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception setting app default network", e);
@@ -9755,7 +9838,8 @@
nrs.add(createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
- final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
+ DEFAULT_NETWORK_PRIORITY_PROFILE);
result.add(nri);
}
return result;
@@ -9825,7 +9909,8 @@
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- nris.add(new NetworkRequestInfo(Process.myUid(), requests));
+ nris.add(new NetworkRequestInfo(Process.myUid(), requests,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED));
return nris;
}
@@ -9876,8 +9961,15 @@
@NonNull final OemNetworkPreferences preference,
@Nullable final IOnCompleteListener listener) {
- enforceAutomotiveDevice();
- enforceOemNetworkPreferencesPermission();
+ Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+ // Only bypass the permission/device checks if this is a valid test request.
+ if (isValidTestOemNetworkPreference(preference)) {
+ enforceManageTestNetworksPermission();
+ } else {
+ enforceAutomotiveDevice();
+ enforceOemNetworkPreferencesPermission();
+ validateOemNetworkPreferences(preference);
+ }
// TODO: Have a priority for each preference.
if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
@@ -9889,18 +9981,41 @@
throwConcurrentPreferenceException();
}
- Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
- validateOemNetworkPreferences(preference);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
new Pair<>(preference, listener)));
}
+ /**
+ * Check the validity of an OEM network preference to be used for testing purposes.
+ * @param preference the preference to validate
+ * @return true if this is a valid OEM network preference test request.
+ */
+ private boolean isValidTestOemNetworkPreference(
+ @NonNull final OemNetworkPreferences preference) {
+ // Allow for clearing of an existing OemNetworkPreference used for testing.
+ // This isn't called on the handler thread so it is possible that mOemNetworkPreferences
+ // changes after this check is complete. This is an unlikely scenario as calling of this API
+ // is controlled by the OEM therefore the added complexity is not worth adding given those
+ // circumstances. That said, it is an edge case to be aware of hence this comment.
+ final boolean isValidTestClearPref = preference.getNetworkPreferences().size() == 0
+ && isTestOemNetworkPreference(mOemNetworkPreferences);
+ return isTestOemNetworkPreference(preference) || isValidTestClearPref;
+ }
+
+ private boolean isTestOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
+ final Map<String, Integer> prefMap = preference.getNetworkPreferences();
+ return prefMap.size() == 1
+ && (prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST)
+ || prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST_ONLY));
+ }
+
private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
for (@OemNetworkPreferences.OemNetworkPreference final int pref
: preference.getNetworkPreferences().values()) {
- if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
- final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
- throw new IllegalArgumentException(msg);
+ if (pref <= 0 || OemNetworkPreferences.OEM_NETWORK_PREFERENCE_MAX < pref) {
+ throw new IllegalArgumentException(
+ OemNetworkPreferences.oemNetworkPreferenceToString(pref)
+ + " is an invalid value.");
}
}
}
@@ -10069,7 +10184,7 @@
private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
@NonNull final OemNetworkPreferences preference) {
- final SparseArray<Set<Integer>> uids = new SparseArray<>();
+ final SparseArray<Set<Integer>> prefToUids = new SparseArray<>();
final PackageManager pm = mContext.getPackageManager();
final List<UserHandle> users =
mContext.getSystemService(UserManager.class).getUserHandles(true);
@@ -10077,29 +10192,29 @@
if (VDBG || DDBG) {
log("No users currently available for setting the OEM network preference.");
}
- return uids;
+ return prefToUids;
}
for (final Map.Entry<String, Integer> entry :
preference.getNetworkPreferences().entrySet()) {
@OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
- try {
- final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
- if (!uids.contains(pref)) {
- uids.put(pref, new ArraySet<>());
+ // Add the rules for all users as this policy is device wide.
+ for (final UserHandle user : users) {
+ try {
+ final int uid = pm.getApplicationInfoAsUser(entry.getKey(), 0, user).uid;
+ if (!prefToUids.contains(pref)) {
+ prefToUids.put(pref, new ArraySet<>());
+ }
+ prefToUids.get(pref).add(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Although this may seem like an error scenario, it is ok that uninstalled
+ // packages are sent on a network preference as the system will watch for
+ // package installations associated with this network preference and update
+ // accordingly. This is done to minimize race conditions on app install.
+ continue;
}
- for (final UserHandle ui : users) {
- // Add the rules for all users as this policy is device wide.
- uids.get(pref).add(ui.getUid(uid));
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Although this may seem like an error scenario, it is ok that uninstalled
- // packages are sent on a network preference as the system will watch for
- // package installations associated with this network preference and update
- // accordingly. This is done so as to minimize race conditions on app install.
- continue;
}
}
- return uids;
+ return prefToUids;
}
private NetworkRequestInfo createNriFromOemNetworkPreferences(
@@ -10124,18 +10239,27 @@
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
requests.add(createOemPrivateNetworkRequest());
break;
+ case OEM_NETWORK_PREFERENCE_TEST:
+ requests.add(createUnmeteredNetworkRequest());
+ requests.add(createTestNetworkRequest());
+ requests.add(createDefaultRequest());
+ break;
+ case OEM_NETWORK_PREFERENCE_TEST_ONLY:
+ requests.add(createTestNetworkRequest());
+ break;
default:
// This should never happen.
throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
+ " called with invalid preference of " + preference);
}
- final ArraySet ranges = new ArraySet<Integer>();
+ final ArraySet<UidRange> ranges = new ArraySet<>();
for (final int uid : uids) {
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(Process.myUid(), requests);
+ return new NetworkRequestInfo(
+ Process.myUid(), requests, DEFAULT_NETWORK_PRIORITY_OEM);
}
private NetworkRequest createUnmeteredNetworkRequest() {
@@ -10162,10 +10286,17 @@
}
private NetworkCapabilities createDefaultPerAppNetCap() {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- return netCap;
+ final NetworkCapabilities netcap = new NetworkCapabilities();
+ netcap.addCapability(NET_CAPABILITY_INTERNET);
+ netcap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
+ return netcap;
+ }
+
+ private NetworkRequest createTestNetworkRequest() {
+ final NetworkCapabilities netcap = new NetworkCapabilities();
+ netcap.clearAll();
+ netcap.addTransportType(TRANSPORT_TEST);
+ return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
}
}
}
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index 09873f4..fffd2be 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -48,7 +48,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
-import com.android.net.module.util.PermissionUtils;
import java.io.UncheckedIOException;
import java.net.Inet4Address;
@@ -123,6 +122,8 @@
addr.getPrefixLength());
}
+ NetdUtils.setInterfaceUp(mNetd, iface);
+
return new TestNetworkInterface(tunIntf, iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -324,14 +325,6 @@
}
try {
- final long token = Binder.clearCallingIdentity();
- try {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- NetdUtils.setInterfaceUp(mNetd, iface);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
// Synchronize all accesses to mTestNetworkTracker to prevent the case where:
// 1. TestNetworkAgent successfully binds to death of binder
// 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
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 1afbfb0..7d30056 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
@@ -106,6 +106,8 @@
private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+ private static final String EMPTY_STRING = "";
+
protected static final int TYPE_COMPONENT_ACTIVTIY = 0;
protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
@@ -206,6 +208,8 @@
final String resultData = getResultData();
if (resultData == null) {
Log.e(TAG, "Received null data from ordered intent");
+ // Offer an empty string so that the code waiting for the result can return.
+ result.offer(EMPTY_STRING);
return;
}
result.offer(resultData);
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index cd69b13..e28c33f 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -38,6 +38,7 @@
srcs: [
"src/**/*.java",
"src/**/*.kt",
+ ":ike-aes-xcbc",
],
jarjar_rules: "jarjar-rules-shared.txt",
static_libs: [
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index a889c41..f993aed 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -20,6 +20,7 @@
import android.Manifest.permission.NETWORK_SETTINGS
import android.Manifest.permission.READ_DEVICE_CONFIG
import android.content.pm.PackageManager.FEATURE_TELEPHONY
+import android.content.pm.PackageManager.FEATURE_WATCH
import android.content.pm.PackageManager.FEATURE_WIFI
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
@@ -57,6 +58,7 @@
import junit.framework.AssertionFailedError
import org.junit.After
import org.junit.Assume.assumeTrue
+import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.runner.RunWith
import java.util.concurrent.CompletableFuture
@@ -128,6 +130,7 @@
fun testCaptivePortalIsNotDefaultNetwork() {
assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
assumeTrue(pm.hasSystemFeature(FEATURE_WIFI))
+ assumeFalse(pm.hasSystemFeature(FEATURE_WATCH))
utils.ensureWifiConnected()
val cellNetwork = utils.connectToCell()
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 0075b54..8b8a8fb 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -65,11 +65,13 @@
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.AF_UNSPEC;
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
@@ -112,6 +114,7 @@
import android.net.NetworkSpecifier;
import android.net.NetworkStateSnapshot;
import android.net.NetworkUtils;
+import android.net.OemNetworkPreferences;
import android.net.ProxyInfo;
import android.net.SocketKeepalive;
import android.net.TelephonyNetworkSpecifier;
@@ -151,9 +154,11 @@
import com.android.networkstack.apishim.common.ConnectivityManagerShim;
import com.android.testutils.CompatUtil;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRuleKt;
import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.SkipPresubmit;
+import com.android.testutils.TestNetworkTracker;
import com.android.testutils.TestableNetworkCallback;
import junit.framework.AssertionFailedError;
@@ -190,6 +195,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -460,6 +466,7 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
}
+ @AppModeFull(reason = "Cannot request network in instant app mode")
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testGetAllNetworkStateSnapshots()
@@ -516,13 +523,8 @@
@Test
@SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks")
public void testOpenConnection() throws Exception {
- boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
- && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
- if (!canRunTest) {
- Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
- + "and a cellular connection");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
Network wifiNetwork = mCtsNetUtils.connectToWifi();
Network cellNetwork = mCtsNetUtils.connectToCell();
@@ -660,6 +662,31 @@
.build();
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testIsPrivateDnsBroken() throws InterruptedException {
+ final String invalidPrivateDnsServer = "invalidhostname.example.com";
+ final String goodPrivateDnsServer = "dns.google";
+ mCtsNetUtils.storePrivateDnsSetting();
+ final TestableNetworkCallback cb = new TestableNetworkCallback();
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), cb);
+ try {
+ // Verifying the good private DNS sever
+ mCtsNetUtils.setPrivateDnsStrictMode(goodPrivateDnsServer);
+ final Network networkForPrivateDns = mCtsNetUtils.ensureWifiConnected();
+ cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
+
+ // Verifying the broken private DNS sever
+ mCtsNetUtils.setPrivateDnsStrictMode(invalidPrivateDnsServer);
+ cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> (((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
+ } finally {
+ mCtsNetUtils.restorePrivateDnsSetting();
+ }
+ }
+
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
@@ -672,10 +699,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testRegisterNetworkCallback() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
// We will register for a WIFI network being available or lost.
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -739,10 +763,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testRegisterNetworkCallback_withPendingIntent() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
// Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
// action, NETWORK_CALLBACK_ACTION.
@@ -913,7 +934,8 @@
}
}
- private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness)
+ private void waitForActiveNetworkMetered(final int targetTransportType,
+ final boolean requestedMeteredness, final boolean useSystemDefault)
throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final NetworkCallback networkCallback = new NetworkCallback() {
@@ -927,17 +949,36 @@
}
}
};
- // Registering a callback here guarantees onCapabilitiesChanged is called immediately
- // with the current setting. Therefore, if the setting has already been changed,
- // this method will return right away, and if not it will wait for the setting to change.
- mCm.registerDefaultNetworkCallback(networkCallback);
- // Changing meteredness on wifi involves reconnecting, which can take several seconds
- // (involves re-associating, DHCP...).
- if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- fail("Timed out waiting for active network metered status to change to "
- + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+
+ try {
+ // Registering a callback here guarantees onCapabilitiesChanged is called immediately
+ // with the current setting. Therefore, if the setting has already been changed,
+ // this method will return right away, and if not, it'll wait for the setting to change.
+ if (useSystemDefault) {
+ runWithShellPermissionIdentity(() ->
+ mCmShim.registerSystemDefaultNetworkCallback(networkCallback,
+ new Handler(Looper.getMainLooper())),
+ NETWORK_SETTINGS);
+ } else {
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ }
+
+ // Changing meteredness on wifi involves reconnecting, which can take several seconds
+ // (involves re-associating, DHCP...).
+ if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Timed out waiting for active network metered status to change to "
+ + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+ }
+ } finally {
+ mCm.unregisterNetworkCallback(networkCallback);
}
- mCm.unregisterNetworkCallback(networkCallback);
+ }
+
+ private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+ setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
+ waitForActiveNetworkMetered(TRANSPORT_WIFI,
+ isMetered /* requestedMeteredness */,
+ true /* useSystemDefault */);
}
private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
@@ -999,10 +1040,9 @@
int newMeteredPreference = findNextPrefValue(resolver);
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
Integer.toString(newMeteredPreference));
- setWifiMeteredStatus(ssid, "true");
- waitForActiveNetworkMetered(TRANSPORT_WIFI, true);
// Wifi meterness changes from unmetered to metered will disconnect and reconnect since
// R.
+ setWifiMeteredStatusAndWait(ssid, true);
final Network network = mCtsNetUtils.ensureWifiConnected();
assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
@@ -1019,9 +1059,8 @@
assertMultipathPreferenceIsEventually(network,
oldMeteredPreference, newMeteredPreference);
- setWifiMeteredStatus(ssid, "false");
// No disconnect from unmetered to metered.
- waitForActiveNetworkMetered(TRANSPORT_WIFI, false);
+ setWifiMeteredStatusAndWait(ssid, false);
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
NET_CAPABILITY_NOT_METERED), true);
assertMultipathPreferenceIsEventually(network, newMeteredPreference,
@@ -1211,11 +1250,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testKeepaliveWifiUnsupported() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) != 0) return;
@@ -1232,10 +1267,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testCreateTcpKeepalive() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) == 0) return;
@@ -1442,11 +1474,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testSocketKeepaliveLimitWifi() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
final int supported = getSupportedKeepalivesForNet(network);
@@ -1539,11 +1567,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testSocketKeepaliveUnprivileged() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
final int supported = getSupportedKeepalivesForNet(network);
@@ -1690,6 +1714,24 @@
c -> c instanceof CallbackEntry.Available);
}
+ private void waitForAvailable(
+ @NonNull final TestableNetworkCallback cb, final int expectedTransport) {
+ cb.eventuallyExpect(
+ CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork());
+ return nc.hasTransport(expectedTransport);
+ }
+ );
+ }
+
+ private void waitForAvailable(
+ @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) {
+ cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */,
+ true /* validated */,
+ false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS);
+ }
+
private void waitForLost(@NonNull final TestableNetworkCallback cb) {
cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
c -> c instanceof CallbackEntry.Lost);
@@ -2010,6 +2052,7 @@
assertThrows(SecurityException.class, () -> mCm.factoryReset());
}
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testFactoryReset() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
@@ -2075,4 +2118,172 @@
startTetheringCallback.verifyTetheringStarted();
callback.expectTetheredInterfacesChanged(wifiRegexs, TETHERING_WIFI);
}
+
+ /**
+ * Verify that per-app OEM network preference functions as expected for network preference TEST.
+ * For specified apps, validate networks are prioritized in order: unmetered, TEST transport,
+ * default network.
+ */
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testSetOemNetworkPreferenceForTestPref() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+ // shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestSApis());
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+
+ final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+ () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+ final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+ final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
+ () -> mCm.getNetworkCapabilities(wifiNetwork));
+ final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
+ final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
+
+ try {
+ // This network will be used for unmetered.
+ setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
+
+ setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
+ registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+
+ // Validate that an unmetered network is used over other networks.
+ waitForAvailable(defaultCallback, wifiNetwork);
+ waitForAvailable(systemDefaultCallback, wifiNetwork);
+
+ // Validate when setting unmetered to metered, unmetered is lost and replaced by the
+ // network with the TEST transport.
+ setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
+ defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork);
+ waitForAvailable(defaultCallback, tnt.getNetwork());
+ // Depending on if this device has cellular connectivity or not, multiple available
+ // callbacks may be received. Eventually, metered Wi-Fi should be the final available
+ // callback in any case therefore confirm its receipt before continuing to assure the
+ // system is in the expected state.
+ waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI);
+ } finally {
+ // Validate that removing the test network will fallback to the default network.
+ runWithShellPermissionIdentity(tnt::teardown);
+ defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+ waitForAvailable(defaultCallback);
+
+ setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
+
+ // Cleanup any prior test state from setOemNetworkPreference
+ clearOemNetworkPreference();
+ unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ }
+ }
+
+ /**
+ * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY.
+ * For specified apps, validate that only TEST transport type networks are used.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+ // shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestSApis());
+
+ final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+ () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+ final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+ final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+
+ try {
+ setOemNetworkPreferenceForMyPackage(
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
+ registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ waitForAvailable(defaultCallback, tnt.getNetwork());
+ waitForAvailable(systemDefaultCallback, wifiNetwork);
+ } finally {
+ runWithShellPermissionIdentity(tnt::teardown);
+ defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+
+ // This network preference should only ever use the test network therefore available
+ // should not trigger when the test network goes down (e.g. switch to cellular).
+ defaultCallback.assertNoCallback();
+ // The system default should still be connected to Wi-fi
+ assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork());
+
+ // Cleanup any prior test state from setOemNetworkPreference
+ clearOemNetworkPreference();
+
+ // The default (non-test) network should be available as the network pref was cleared.
+ waitForAvailable(defaultCallback);
+ unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ }
+ }
+
+ private void unregisterTestOemNetworkPreferenceCallbacks(
+ @NonNull final TestableNetworkCallback defaultCallback,
+ @NonNull final TestableNetworkCallback systemDefaultCallback) {
+ mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(systemDefaultCallback);
+ }
+
+ private void registerTestOemNetworkPreferenceCallbacks(
+ @NonNull final TestableNetworkCallback defaultCallback,
+ @NonNull final TestableNetworkCallback systemDefaultCallback) {
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ runWithShellPermissionIdentity(() ->
+ mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+ new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
+ }
+
+ private static final class OnCompleteListenerCallback {
+ final CompletableFuture<Object> mDone = new CompletableFuture<>();
+
+ public void onComplete() {
+ mDone.complete(new Object());
+ }
+
+ void expectOnComplete() throws Exception {
+ try {
+ mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ fail("Expected onComplete() not received after "
+ + NETWORK_CALLBACK_TIMEOUT_MS + " ms");
+ }
+ }
+ }
+
+ private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception {
+ final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+ .addNetworkPreference(mContext.getPackageName(), networkPref)
+ .build();
+ final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ mCm.setOemNetworkPreference(
+ pref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ oemPrefListener.expectOnComplete();
+ }
+
+ /**
+ * This will clear the OEM network preference on the device. As there is currently no way of
+ * getting the existing preference, if this is executed while an existing preference is in
+ * place, that preference will need to be reapplied after executing this test.
+ * @throws Exception
+ */
+ private void clearOemNetworkPreference() throws Exception {
+ final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build();
+ final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ mCm.setOemNetworkPreference(
+ clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ oemPrefListener.expectOnComplete();
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index c6d8d65..6e9f0cd 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -39,13 +39,11 @@
import android.net.ConnectivityManager;
import android.net.Ikev2VpnProfile;
import android.net.IpSecAlgorithm;
-import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.ProxyInfo;
import android.net.TestNetworkInterface;
-import android.net.TestNetworkManager;
import android.net.VpnManager;
import android.net.cts.util.CtsNetUtils;
import android.os.Build;
@@ -439,41 +437,37 @@
assertEquals(vpnNetwork, cb.lastLostNetwork);
}
- private void doTestStartStopVpnProfile(boolean testIpv6) throws Exception {
- // Non-final; these variables ensure we clean up properly after our test if we have
- // allocated test network resources
- final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class);
- TestNetworkInterface testIface = null;
- TestNetworkCallback tunNetworkCallback = null;
+ private class VerifyStartStopVpnProfileTest implements TestNetworkRunnable.Test {
+ private final boolean mTestIpv6Only;
- try {
- // Build underlying test network
- testIface = tnm.createTunInterface(
- new LinkAddress[] {
- new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN),
- new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)});
+ /**
+ * Constructs the test
+ *
+ * @param testIpv6Only if true, builds a IPv6-only test; otherwise builds a IPv4-only test
+ */
+ VerifyStartStopVpnProfileTest(boolean testIpv6Only) {
+ mTestIpv6Only = testIpv6Only;
+ }
- // Hold on to this callback to ensure network does not get reaped.
- tunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(
- testIface.getInterfaceName());
+ @Override
+ public void runTest(TestNetworkInterface testIface, TestNetworkCallback tunNetworkCallback)
+ throws Exception {
final IkeTunUtils tunUtils = new IkeTunUtils(testIface.getFileDescriptor());
- checkStartStopVpnProfileBuildsNetworks(tunUtils, testIpv6);
- } finally {
- // Make sure to stop the VPN profile. This is safe to call multiple times.
+ checkStartStopVpnProfileBuildsNetworks(tunUtils, mTestIpv6Only);
+ }
+
+ @Override
+ public void cleanupTest() {
sVpnMgr.stopProvisionedVpnProfile();
+ }
- if (testIface != null) {
- testIface.getFileDescriptor().close();
- }
-
- if (tunNetworkCallback != null) {
- sCM.unregisterNetworkCallback(tunNetworkCallback);
- }
-
- final Network testNetwork = tunNetworkCallback.currentNetwork;
- if (testNetwork != null) {
- tnm.teardownTestNetwork(testNetwork);
+ @Override
+ public InetAddress[] getTestNetworkAddresses() {
+ if (mTestIpv6Only) {
+ return new InetAddress[] {LOCAL_OUTER_6};
+ } else {
+ return new InetAddress[] {LOCAL_OUTER_4};
}
}
}
@@ -483,9 +477,8 @@
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
// Requires shell permission to update appops.
- runWithShellPermissionIdentity(() -> {
- doTestStartStopVpnProfile(false);
- });
+ runWithShellPermissionIdentity(
+ new TestNetworkRunnable(new VerifyStartStopVpnProfileTest(false)));
}
@Test
@@ -493,9 +486,8 @@
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
// Requires shell permission to update appops.
- runWithShellPermissionIdentity(() -> {
- doTestStartStopVpnProfile(true);
- });
+ runWithShellPermissionIdentity(
+ new TestNetworkRunnable(new VerifyStartStopVpnProfileTest(true)));
}
private static class CertificateAndKey {
diff --git a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
new file mode 100644
index 0000000..2f29273
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2020 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.cts;
+
+import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
+import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
+import static android.net.cts.PacketUtils.AES_CMAC;
+import static android.net.cts.PacketUtils.AES_CMAC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_CMAC_KEY_LEN;
+import static android.net.cts.PacketUtils.AES_CTR;
+import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_20;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_28;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_36;
+import static android.net.cts.PacketUtils.AES_CTR_SALT_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC;
+import static android.net.cts.PacketUtils.AES_XCBC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC_KEY_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_BLK_SIZE;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_ICV_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_IV_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_KEY_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_SALT_LEN;
+import static android.net.cts.PacketUtils.ESP_HDRLEN;
+import static android.net.cts.PacketUtils.IP6_HDRLEN;
+import static android.net.cts.PacketUtils.getIpHeader;
+import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assume.assumeTrue;
+
+import android.net.IpSecAlgorithm;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.net.Network;
+import android.net.TestNetworkInterface;
+import android.net.cts.PacketUtils.BytePayload;
+import android.net.cts.PacketUtils.EspAeadCipher;
+import android.net.cts.PacketUtils.EspAuth;
+import android.net.cts.PacketUtils.EspAuthNull;
+import android.net.cts.PacketUtils.EspCipher;
+import android.net.cts.PacketUtils.EspCipherNull;
+import android.net.cts.PacketUtils.EspCryptCipher;
+import android.net.cts.PacketUtils.EspHeader;
+import android.net.cts.PacketUtils.IpHeader;
+import android.net.cts.PacketUtils.UdpHeader;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Socket cannot bind in instant app mode")
+public class IpSecAlgorithmImplTest extends IpSecBaseTest {
+ private static final InetAddress LOCAL_ADDRESS =
+ InetAddress.parseNumericAddress("2001:db8:1::1");
+ private static final InetAddress REMOTE_ADDRESS =
+ InetAddress.parseNumericAddress("2001:db8:1::2");
+
+ private static final int REMOTE_PORT = 12345;
+ private static final IpSecManager sIpSecManager =
+ InstrumentationRegistry.getContext().getSystemService(IpSecManager.class);
+
+ private static class CheckCryptoImplTest implements TestNetworkRunnable.Test {
+ private final IpSecAlgorithm mIpsecEncryptAlgo;
+ private final IpSecAlgorithm mIpsecAuthAlgo;
+ private final IpSecAlgorithm mIpsecAeadAlgo;
+ private final EspCipher mEspCipher;
+ private final EspAuth mEspAuth;
+
+ CheckCryptoImplTest(
+ IpSecAlgorithm ipsecEncryptAlgo,
+ IpSecAlgorithm ipsecAuthAlgo,
+ IpSecAlgorithm ipsecAeadAlgo,
+ EspCipher espCipher,
+ EspAuth espAuth) {
+ mIpsecEncryptAlgo = ipsecEncryptAlgo;
+ mIpsecAuthAlgo = ipsecAuthAlgo;
+ mIpsecAeadAlgo = ipsecAeadAlgo;
+ mEspCipher = espCipher;
+ mEspAuth = espAuth;
+ }
+
+ private static byte[] buildTransportModeEspPayload(
+ int srcPort, int dstPort, int spi, EspCipher espCipher, EspAuth espAuth)
+ throws Exception {
+ final UdpHeader udpPayload =
+ new UdpHeader(srcPort, dstPort, new BytePayload(TEST_DATA));
+ final IpHeader preEspIpHeader =
+ getIpHeader(
+ udpPayload.getProtocolId(), LOCAL_ADDRESS, REMOTE_ADDRESS, udpPayload);
+
+ final PacketUtils.EspHeader espPayload =
+ new EspHeader(
+ udpPayload.getProtocolId(),
+ spi,
+ 1 /* sequence number */,
+ udpPayload.getPacketBytes(preEspIpHeader),
+ espCipher,
+ espAuth);
+ return espPayload.getPacketBytes(preEspIpHeader);
+ }
+
+ @Override
+ public void runTest(TestNetworkInterface testIface, TestNetworkCallback tunNetworkCallback)
+ throws Exception {
+ final TunUtils tunUtils = new TunUtils(testIface.getFileDescriptor());
+ tunNetworkCallback.waitForAvailable();
+ final Network testNetwork = tunNetworkCallback.currentNetwork;
+
+ final IpSecTransform.Builder transformBuilder =
+ new IpSecTransform.Builder(InstrumentationRegistry.getContext());
+ if (mIpsecAeadAlgo != null) {
+ transformBuilder.setAuthenticatedEncryption(mIpsecAeadAlgo);
+ } else {
+ if (mIpsecEncryptAlgo != null) {
+ transformBuilder.setEncryption(mIpsecEncryptAlgo);
+ }
+ if (mIpsecAuthAlgo != null) {
+ transformBuilder.setAuthentication(mIpsecAuthAlgo);
+ }
+ }
+
+ try (IpSecManager.SecurityParameterIndex outSpi =
+ sIpSecManager.allocateSecurityParameterIndex(REMOTE_ADDRESS);
+ IpSecManager.SecurityParameterIndex inSpi =
+ sIpSecManager.allocateSecurityParameterIndex(LOCAL_ADDRESS);
+ IpSecTransform outTransform =
+ transformBuilder.buildTransportModeTransform(LOCAL_ADDRESS, outSpi);
+ IpSecTransform inTransform =
+ transformBuilder.buildTransportModeTransform(REMOTE_ADDRESS, inSpi);
+ // Bind localSocket to a random available port.
+ DatagramSocket localSocket = new DatagramSocket(0)) {
+ sIpSecManager.applyTransportModeTransform(
+ localSocket, IpSecManager.DIRECTION_IN, inTransform);
+ sIpSecManager.applyTransportModeTransform(
+ localSocket, IpSecManager.DIRECTION_OUT, outTransform);
+
+ // Send ESP packet
+ final DatagramPacket outPacket =
+ new DatagramPacket(
+ TEST_DATA, 0, TEST_DATA.length, REMOTE_ADDRESS, REMOTE_PORT);
+ testNetwork.bindSocket(localSocket);
+ localSocket.send(outPacket);
+ final byte[] outEspPacket =
+ tunUtils.awaitEspPacket(outSpi.getSpi(), false /* useEncap */);
+
+ // Remove transform for good hygiene
+ sIpSecManager.removeTransportModeTransforms(localSocket);
+
+ // Get the kernel-generated ESP payload
+ final byte[] outEspPayload = new byte[outEspPacket.length - IP6_HDRLEN];
+ System.arraycopy(outEspPacket, IP6_HDRLEN, outEspPayload, 0, outEspPayload.length);
+
+ // Get the IV of the kernel-generated ESP payload
+ final byte[] iv =
+ Arrays.copyOfRange(
+ outEspPayload, ESP_HDRLEN, ESP_HDRLEN + mEspCipher.ivLen);
+
+ // Build ESP payload using the kernel-generated IV and the user space crypto
+ // implementations
+ mEspCipher.updateIv(iv);
+ final byte[] expectedEspPayload =
+ buildTransportModeEspPayload(
+ localSocket.getLocalPort(),
+ REMOTE_PORT,
+ outSpi.getSpi(),
+ mEspCipher,
+ mEspAuth);
+
+ // Compare user-space-generated and kernel-generated ESP payload
+ assertArrayEquals(expectedEspPayload, outEspPayload);
+ }
+ }
+
+ @Override
+ public void cleanupTest() {
+ // Do nothing
+ }
+
+ @Override
+ public InetAddress[] getTestNetworkAddresses() {
+ return new InetAddress[] {LOCAL_ADDRESS};
+ }
+ }
+
+ private void checkAesCtr(int keyLen) throws Exception {
+ final byte[] cryptKey = getKeyBytes(keyLen);
+
+ final IpSecAlgorithm ipsecEncryptAlgo =
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CTR, cryptKey);
+ final EspCipher espCipher =
+ new EspCryptCipher(
+ AES_CTR, AES_CTR_BLK_SIZE, cryptKey, AES_CTR_IV_LEN, AES_CTR_SALT_LEN);
+
+ runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+ ipsecEncryptAlgo, null /* ipsecAuthAlgo */, null /* ipsecAeadAlgo */,
+ espCipher, EspAuthNull.getInstance())));
+ }
+
+ @Test
+ public void testAesCtr160() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_20);
+ }
+
+ @Test
+ public void testAesCtr224() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_28);
+ }
+
+ @Test
+ public void testAesCtr288() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ checkAesCtr(AES_CTR_KEY_LEN_36);
+ }
+
+ @Test
+ public void testAesXcbc() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final byte[] authKey = getKeyBytes(AES_XCBC_KEY_LEN);
+ final IpSecAlgorithm ipsecAuthAlgo =
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_XCBC, authKey, AES_XCBC_ICV_LEN * 8);
+ final EspAuth espAuth = new EspAuth(AES_XCBC, authKey, AES_XCBC_ICV_LEN);
+
+ runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+ null /* ipsecEncryptAlgo */, ipsecAuthAlgo, null /* ipsecAeadAlgo */,
+ EspCipherNull.getInstance(), espAuth)));
+ }
+
+ @Test
+ public void testAesCmac() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final byte[] authKey = getKeyBytes(AES_CMAC_KEY_LEN);
+ final IpSecAlgorithm ipsecAuthAlgo =
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_CMAC, authKey, AES_CMAC_ICV_LEN * 8);
+ final EspAuth espAuth = new EspAuth(AES_CMAC, authKey, AES_CMAC_ICV_LEN);
+
+ runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+ null /* ipsecEncryptAlgo */, ipsecAuthAlgo, null /* ipsecAeadAlgo */,
+ EspCipherNull.getInstance(), espAuth)));
+ }
+
+ @Test
+ public void testChaCha20Poly1305() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final byte[] cryptKey = getKeyBytes(CHACHA20_POLY1305_KEY_LEN);
+ final IpSecAlgorithm ipsecAeadAlgo =
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305,
+ cryptKey,
+ CHACHA20_POLY1305_ICV_LEN * 8);
+ final EspAeadCipher espAead =
+ new EspAeadCipher(
+ CHACHA20_POLY1305,
+ CHACHA20_POLY1305_BLK_SIZE,
+ cryptKey,
+ CHACHA20_POLY1305_IV_LEN,
+ CHACHA20_POLY1305_ICV_LEN,
+ CHACHA20_POLY1305_SALT_LEN);
+
+ runWithShellPermissionIdentity(
+ new TestNetworkRunnable(
+ new CheckCryptoImplTest(
+ null /* ipsecEncryptAlgo */,
+ null /* ipsecAuthAlgo */,
+ ipsecAeadAlgo,
+ espAead,
+ EspAuthNull.getInstance())));
+ }
+}
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index e7e1d67..5c95aa3 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -33,7 +33,7 @@
import static android.net.cts.PacketUtils.AES_CMAC_KEY_LEN;
import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
-import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN_20;
import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_GCM_IV_LEN;
import static android.net.cts.PacketUtils.AES_XCBC_ICV_LEN;
@@ -74,7 +74,6 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.SkipPresubmit;
import org.junit.Rule;
import org.junit.Test;
@@ -771,7 +770,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacMd5Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -804,7 +802,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha1Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -837,7 +834,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha256Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -870,7 +866,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha384Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -903,7 +898,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha512Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -928,7 +922,7 @@
}
private static IpSecAlgorithm buildCryptAesCtr() throws Exception {
- return new IpSecAlgorithm(CRYPT_AES_CTR, getKeyBytes(AES_CTR_KEY_LEN));
+ return new IpSecAlgorithm(CRYPT_AES_CTR, getKeyBytes(AES_CTR_KEY_LEN_20));
}
private static IpSecAlgorithm buildAuthHmacSha512() throws Exception {
@@ -947,7 +941,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCtrHmacSha512Tcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
@@ -1002,7 +995,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcAesXCbcTcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
@@ -1043,7 +1035,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcAesCmacTcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
@@ -1082,7 +1073,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm64Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -1115,7 +1105,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm96Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -1148,7 +1137,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm128Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -1187,7 +1175,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testChaCha20Poly1305Tcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
@@ -1463,7 +1450,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testCryptTcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
@@ -1471,7 +1457,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAuthTcp6() throws Exception {
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 7e622f6..4d924d1 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -19,6 +19,10 @@
import static android.system.OsConstants.IPPROTO_IPV6;
import static android.system.OsConstants.IPPROTO_UDP;
+import android.util.ArraySet;
+
+import com.android.internal.net.ipsec.ike.crypto.AesXCbcImpl;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -27,6 +31,7 @@
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -43,7 +48,9 @@
static final int UDP_HDRLEN = 8;
static final int TCP_HDRLEN = 20;
static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
+ static final int ESP_HDRLEN = 8;
static final int ESP_BLK_SIZE = 4; // ESP has to be 4-byte aligned
+ static final int ESP_TRAILER_LEN = 2;
// Not defined in OsConstants
static final int IPPROTO_IPV4 = 4;
@@ -52,19 +59,25 @@
// Encryption parameters
static final int AES_CBC_IV_LEN = 16;
static final int AES_CBC_BLK_SIZE = 16;
+ static final int AES_CTR_SALT_LEN = 4;
- static final int AES_CTR_KEY_LEN = 20;
+ static final int AES_CTR_KEY_LEN_20 = 20;
+ static final int AES_CTR_KEY_LEN_28 = 28;
+ static final int AES_CTR_KEY_LEN_36 = 36;
static final int AES_CTR_BLK_SIZE = ESP_BLK_SIZE;
static final int AES_CTR_IV_LEN = 8;
// AEAD parameters
static final int AES_GCM_IV_LEN = 8;
static final int AES_GCM_BLK_SIZE = 4;
+ static final int CHACHA20_POLY1305_KEY_LEN = 36;
static final int CHACHA20_POLY1305_BLK_SIZE = ESP_BLK_SIZE;
static final int CHACHA20_POLY1305_IV_LEN = 8;
+ static final int CHACHA20_POLY1305_SALT_LEN = 4;
static final int CHACHA20_POLY1305_ICV_LEN = 16;
// Authentication parameters
+ static final int HMAC_SHA256_ICV_LEN = 16;
static final int HMAC_SHA512_KEY_LEN = 64;
static final int HMAC_SHA512_ICV_LEN = 32;
static final int AES_XCBC_KEY_LEN = 16;
@@ -72,10 +85,25 @@
static final int AES_CMAC_KEY_LEN = 16;
static final int AES_CMAC_ICV_LEN = 12;
+ // Block counter field should be 32 bits and starts from value one as per RFC 3686
+ static final byte[] AES_CTR_INITIAL_COUNTER = new byte[] {0x00, 0x00, 0x00, 0x01};
+
// Encryption algorithms
static final String AES = "AES";
static final String AES_CBC = "AES/CBC/NoPadding";
+ static final String AES_CTR = "AES/CTR/NoPadding";
+
+ // AEAD algorithms
+ static final String CHACHA20_POLY1305 = "ChaCha20/Poly1305/NoPadding";
+
+ // Authentication algorithms
+ static final String HMAC_MD5 = "HmacMD5";
+ static final String HMAC_SHA1 = "HmacSHA1";
static final String HMAC_SHA_256 = "HmacSHA256";
+ static final String HMAC_SHA_384 = "HmacSHA384";
+ static final String HMAC_SHA_512 = "HmacSHA512";
+ static final String AES_CMAC = "AESCMAC";
+ static final String AES_XCBC = "AesXCbc";
public interface Payload {
byte[] getPacketBytes(IpHeader header) throws Exception;
@@ -328,8 +356,9 @@
public final int nextHeader;
public final int spi;
public final int seqNum;
- public final byte[] key;
public final byte[] payload;
+ public final EspCipher cipher;
+ public final EspAuth auth;
/**
* Generic constructor for ESP headers.
@@ -340,11 +369,48 @@
* calculated using the pre-encryption IP header
*/
public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) {
+ this(nextHeader, spi, seqNum, payload, getDefaultCipher(key), getDefaultAuth(key));
+ }
+
+ /**
+ * Generic constructor for ESP headers that allows configuring encryption and authentication
+ * algortihms.
+ *
+ * <p>For Tunnel mode, payload will be a full IP header + attached payloads
+ *
+ * <p>For Transport mode, payload will be only the attached payloads, but with the checksum
+ * calculated using the pre-encryption IP header
+ */
+ public EspHeader(
+ int nextHeader,
+ int spi,
+ int seqNum,
+ byte[] payload,
+ EspCipher cipher,
+ EspAuth auth) {
this.nextHeader = nextHeader;
this.spi = spi;
this.seqNum = seqNum;
- this.key = key;
this.payload = payload;
+ this.cipher = cipher;
+ this.auth = auth;
+
+ if (cipher instanceof EspCipherNull && auth instanceof EspAuthNull) {
+ throw new IllegalArgumentException("No algorithm is provided");
+ }
+
+ if (cipher instanceof EspAeadCipher && !(auth instanceof EspAuthNull)) {
+ throw new IllegalArgumentException(
+ "AEAD is provided with an authentication" + " algorithm.");
+ }
+ }
+
+ private static EspCipher getDefaultCipher(byte[] key) {
+ return new EspCryptCipher(AES_CBC, AES_CBC_BLK_SIZE, key, AES_CBC_IV_LEN);
+ }
+
+ private static EspAuth getDefaultAuth(byte[] key) {
+ return new EspAuth(HMAC_SHA_256, key, HMAC_SHA256_ICV_LEN);
}
public int getProtocolId() {
@@ -352,9 +418,10 @@
}
public short length() {
- // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len)
- return (short)
- calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128);
+ final int icvLen =
+ cipher instanceof EspAeadCipher ? ((EspAeadCipher) cipher).icvLen : auth.icvLen;
+ return calculateEspPacketSize(
+ payload.length, cipher.ivLen, cipher.blockSize, icvLen * 8);
}
public byte[] getPacketBytes(IpHeader header) throws Exception {
@@ -368,58 +435,12 @@
ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN);
espPayloadBuffer.putInt(spi);
espPayloadBuffer.putInt(seqNum);
- espPayloadBuffer.put(getCiphertext(key));
- espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16);
+ espPayloadBuffer.put(cipher.getCipherText(nextHeader, payload, spi, seqNum));
+ espPayloadBuffer.put(auth.getIcv(getByteArrayFromBuffer(espPayloadBuffer)));
+
resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer));
}
-
- private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
- Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256);
- SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256);
- sha256HMAC.init(authKey);
-
- return sha256HMAC.doFinal(authenticatedSection);
- }
-
- /**
- * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks
- *
- * <p>The ciphertext does NOT include the SPI/Sequence numbers, or the ICV.
- */
- private byte[] getCiphertext(byte[] key) throws GeneralSecurityException {
- int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE);
- ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
- paddedPayload.put(payload);
-
- // Add padding - consecutive integers from 0x01
- int pad = 1;
- while (paddedPayload.position() < paddedPayload.limit()) {
- paddedPayload.put((byte) pad++);
- }
-
- paddedPayload.position(paddedPayload.limit() - 2);
- paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length
- paddedPayload.put((byte) nextHeader);
-
- // Generate Initialization Vector
- byte[] iv = new byte[AES_CBC_IV_LEN];
- new SecureRandom().nextBytes(iv);
- IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
- SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
-
- // Encrypt payload
- Cipher cipher = Cipher.getInstance(AES_CBC);
- cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
- byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload));
-
- // Build ciphertext
- ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length);
- cipherText.put(iv);
- cipherText.put(encrypted);
-
- return getByteArrayFromBuffer(cipherText);
- }
}
private static int addAndWrapForChecksum(int currentChecksum, int value) {
@@ -436,15 +457,14 @@
return (short) ((~val) & 0xffff);
}
- public static int calculateEspPacketSize(
+ public static short calculateEspPacketSize(
int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) {
- final int ESP_HDRLEN = 4 + 4; // SPI + Seq#
final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length
- payloadLen += cryptIvLength; // Initialization Vector
// Align to block size of encryption algorithm
payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize);
- return payloadLen + ESP_HDRLEN + ICV_LEN;
+ payloadLen += cryptIvLength; // Initialization Vector
+ return (short) (payloadLen + ESP_HDRLEN + ICV_LEN);
}
private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) {
@@ -475,6 +495,237 @@
}
}
+ public abstract static class EspCipher {
+ protected static final int SALT_LEN_UNUSED = 0;
+
+ public final String algoName;
+ public final int blockSize;
+ public final byte[] key;
+ public final int ivLen;
+ public final int saltLen;
+ protected byte[] mIv;
+
+ public EspCipher(String algoName, int blockSize, byte[] key, int ivLen, int saltLen) {
+ this.algoName = algoName;
+ this.blockSize = blockSize;
+ this.key = key;
+ this.ivLen = ivLen;
+ this.saltLen = saltLen;
+ this.mIv = getIv(ivLen);
+ }
+
+ public void updateIv(byte[] iv) {
+ this.mIv = iv;
+ }
+
+ public static byte[] getPaddedPayload(int nextHeader, byte[] payload, int blockSize) {
+ final int paddedLen = calculateEspEncryptedLength(payload.length, blockSize);
+ final ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen);
+ paddedPayload.put(payload);
+
+ // Add padding - consecutive integers from 0x01
+ byte pad = 1;
+ while (paddedPayload.position() < paddedPayload.limit() - ESP_TRAILER_LEN) {
+ paddedPayload.put((byte) pad++);
+ }
+
+ // Add padding length and next header
+ paddedPayload.put((byte) (paddedLen - ESP_TRAILER_LEN - payload.length));
+ paddedPayload.put((byte) nextHeader);
+
+ return getByteArrayFromBuffer(paddedPayload);
+ }
+
+ private static byte[] getIv(int ivLen) {
+ final byte[] iv = new byte[ivLen];
+ new SecureRandom().nextBytes(iv);
+ return iv;
+ }
+
+ public abstract byte[] getCipherText(int nextHeader, byte[] payload, int spi, int seqNum)
+ throws GeneralSecurityException;
+ }
+
+ public static final class EspCipherNull extends EspCipher {
+ private static final String CRYPT_NULL = "CRYPT_NULL";
+ private static final int IV_LEN_UNUSED = 0;
+ private static final byte[] KEY_UNUSED = new byte[0];
+
+ private static final EspCipherNull sInstance = new EspCipherNull();
+
+ private EspCipherNull() {
+ super(CRYPT_NULL, ESP_BLK_SIZE, KEY_UNUSED, IV_LEN_UNUSED, SALT_LEN_UNUSED);
+ }
+
+ public static EspCipherNull getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public byte[] getCipherText(int nextHeader, byte[] payload, int spi, int seqNum)
+ throws GeneralSecurityException {
+ return getPaddedPayload(nextHeader, payload, blockSize);
+ }
+ }
+
+ public static final class EspCryptCipher extends EspCipher {
+ public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen) {
+ this(algoName, blockSize, key, ivLen, SALT_LEN_UNUSED);
+ }
+
+ public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen, int saltLen) {
+ super(algoName, blockSize, key, ivLen, saltLen);
+ }
+
+ @Override
+ public byte[] getCipherText(int nextHeader, byte[] payload, int spi, int seqNum)
+ throws GeneralSecurityException {
+ final IvParameterSpec ivParameterSpec;
+ final SecretKeySpec secretKeySpec;
+
+ if (AES_CBC.equals(algoName)) {
+ ivParameterSpec = new IvParameterSpec(mIv);
+ secretKeySpec = new SecretKeySpec(key, algoName);
+ } else if (AES_CTR.equals(algoName)) {
+ // Provided key consists of encryption/decryption key plus 4-byte salt. Salt is used
+ // with ESP payload IV and initial block counter value to build IvParameterSpec.
+ final byte[] secretKey = Arrays.copyOfRange(key, 0, key.length - saltLen);
+ final byte[] salt = Arrays.copyOfRange(key, secretKey.length, key.length);
+ secretKeySpec = new SecretKeySpec(secretKey, algoName);
+
+ final ByteBuffer ivParameterBuffer =
+ ByteBuffer.allocate(mIv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
+ ivParameterBuffer.put(salt);
+ ivParameterBuffer.put(mIv);
+ ivParameterBuffer.put(AES_CTR_INITIAL_COUNTER);
+ ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
+ } else {
+ throw new IllegalArgumentException("Invalid algorithm " + algoName);
+ }
+
+ // Encrypt payload
+ final Cipher cipher = Cipher.getInstance(algoName);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
+ final byte[] encrypted =
+ cipher.doFinal(getPaddedPayload(nextHeader, payload, blockSize));
+
+ // Build ciphertext
+ final ByteBuffer cipherText = ByteBuffer.allocate(mIv.length + encrypted.length);
+ cipherText.put(mIv);
+ cipherText.put(encrypted);
+
+ return getByteArrayFromBuffer(cipherText);
+ }
+ }
+
+ public static final class EspAeadCipher extends EspCipher {
+ public final int icvLen;
+
+ public EspAeadCipher(
+ String algoName, int blockSize, byte[] key, int ivLen, int icvLen, int saltLen) {
+ super(algoName, blockSize, key, ivLen, saltLen);
+ this.icvLen = icvLen;
+ }
+
+ @Override
+ public byte[] getCipherText(int nextHeader, byte[] payload, int spi, int seqNum)
+ throws GeneralSecurityException {
+ // Provided key consists of encryption/decryption key plus salt. Salt is used
+ // with ESP payload IV to build IvParameterSpec.
+ final byte[] secretKey = Arrays.copyOfRange(key, 0, key.length - saltLen);
+ final byte[] salt = Arrays.copyOfRange(key, secretKey.length, key.length);
+
+ final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, algoName);
+
+ final ByteBuffer ivParameterBuffer = ByteBuffer.allocate(saltLen + mIv.length);
+ ivParameterBuffer.put(salt);
+ ivParameterBuffer.put(mIv);
+ final IvParameterSpec ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
+
+ final ByteBuffer aadBuffer = ByteBuffer.allocate(ESP_HDRLEN);
+ aadBuffer.putInt(spi);
+ aadBuffer.putInt(seqNum);
+
+ // Encrypt payload
+ final Cipher cipher = Cipher.getInstance(algoName);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
+ cipher.updateAAD(aadBuffer.array());
+ final byte[] encryptedTextAndIcv =
+ cipher.doFinal(getPaddedPayload(nextHeader, payload, blockSize));
+
+ // Build ciphertext
+ final ByteBuffer cipherText =
+ ByteBuffer.allocate(mIv.length + encryptedTextAndIcv.length);
+ cipherText.put(mIv);
+ cipherText.put(encryptedTextAndIcv);
+
+ return getByteArrayFromBuffer(cipherText);
+ }
+ }
+
+ public static class EspAuth {
+ public final String algoName;
+ public final byte[] key;
+ public final int icvLen;
+
+ private static final Set<String> JCE_SUPPORTED_MACS = new ArraySet<>();
+
+ static {
+ JCE_SUPPORTED_MACS.add(HMAC_MD5);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA1);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_256);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_384);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_512);
+ JCE_SUPPORTED_MACS.add(AES_CMAC);
+ }
+
+ public EspAuth(String algoName, byte[] key, int icvLen) {
+ this.algoName = algoName;
+ this.key = key;
+ this.icvLen = icvLen;
+ }
+
+ public byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
+ if (AES_XCBC.equals(algoName)) {
+ final Cipher aesCipher = Cipher.getInstance(AES_CBC);
+ return new AesXCbcImpl().mac(key, authenticatedSection, true /* needTruncation */);
+ } else if (JCE_SUPPORTED_MACS.contains(algoName)) {
+ final Mac mac = Mac.getInstance(algoName);
+ final SecretKeySpec authKey = new SecretKeySpec(key, algoName);
+ mac.init(authKey);
+
+ final ByteBuffer buffer = ByteBuffer.wrap(mac.doFinal(authenticatedSection));
+ final byte[] icv = new byte[icvLen];
+ buffer.get(icv);
+ return icv;
+ } else {
+ throw new IllegalArgumentException("Invalid algorithm: " + algoName);
+ }
+ }
+ }
+
+ public static final class EspAuthNull extends EspAuth {
+ private static final String AUTH_NULL = "AUTH_NULL";
+ private static final int ICV_LEN_UNUSED = 0;
+ private static final byte[] KEY_UNUSED = new byte[0];
+ private static final byte[] ICV_EMPTY = new byte[0];
+
+ private static final EspAuthNull sInstance = new EspAuthNull();
+
+ private EspAuthNull() {
+ super(AUTH_NULL, KEY_UNUSED, ICV_LEN_UNUSED);
+ }
+
+ public static EspAuthNull getInstance() {
+ return sInstance;
+ }
+
+ @Override
+ public byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException {
+ return ICV_EMPTY;
+ }
+ }
+
/*
* Debug printing
*/
diff --git a/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java b/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java
new file mode 100644
index 0000000..0eb5644
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/TestNetworkRunnable.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 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.cts;
+
+import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.Network;
+import android.net.TestNetworkInterface;
+import android.net.TestNetworkManager;
+import android.net.cts.util.CtsNetUtils;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ThrowingRunnable;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+/** This class supports running a test with a test network. */
+public class TestNetworkRunnable implements ThrowingRunnable {
+ private static final int IP4_PREFIX_LEN = 32;
+ private static final int IP6_PREFIX_LEN = 128;
+
+ private static final InetAddress DEFAULT_ADDRESS_4 =
+ InetAddress.parseNumericAddress("192.2.0.2");
+ private static final InetAddress DEFAULT_ADDRESS_6 =
+ InetAddress.parseNumericAddress("2001:db8:1::2");
+
+ private static final Context sContext = InstrumentationRegistry.getContext();
+ private static final ConnectivityManager sCm =
+ sContext.getSystemService(ConnectivityManager.class);
+
+ private final Test mTest;
+
+ public TestNetworkRunnable(Test test) {
+ mTest = test;
+ }
+
+ private void runTest() throws Exception {
+ final TestNetworkManager tnm = sContext.getSystemService(TestNetworkManager.class);
+
+ // Non-final; these variables ensure we clean up properly after our test if we
+ // have allocated test network resources
+ TestNetworkInterface testIface = null;
+ TestNetworkCallback tunNetworkCallback = null;
+
+ final CtsNetUtils ctsNetUtils = new CtsNetUtils(sContext);
+ final InetAddress[] addresses = mTest.getTestNetworkAddresses();
+ final LinkAddress[] linkAddresses = new LinkAddress[addresses.length];
+ for (int i = 0; i < addresses.length; i++) {
+ InetAddress address = addresses[i];
+ if (address instanceof Inet4Address) {
+ linkAddresses[i] = new LinkAddress(address, IP4_PREFIX_LEN);
+ } else {
+ linkAddresses[i] = new LinkAddress(address, IP6_PREFIX_LEN);
+ }
+ }
+
+ try {
+ // Build underlying test network
+ testIface = tnm.createTunInterface(linkAddresses);
+
+ // Hold on to this callback to ensure network does not get reaped.
+ tunNetworkCallback = ctsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName());
+
+ mTest.runTest(testIface, tunNetworkCallback);
+ } finally {
+ try {
+ mTest.cleanupTest();
+ } catch (Exception e) {
+ // No action
+ }
+
+ if (testIface != null) {
+ testIface.getFileDescriptor().close();
+ }
+
+ if (tunNetworkCallback != null) {
+ sCm.unregisterNetworkCallback(tunNetworkCallback);
+ }
+
+ final Network testNetwork = tunNetworkCallback.currentNetwork;
+ if (testNetwork != null) {
+ tnm.teardownTestNetwork(testNetwork);
+ }
+ }
+ }
+
+ @Override
+ public void run() throws Exception {
+ if (sContext.checkSelfPermission(MANAGE_TEST_NETWORKS) == PERMISSION_GRANTED) {
+ runTest();
+ } else {
+ runWithShellPermissionIdentity(this::runTest, MANAGE_TEST_NETWORKS);
+ }
+ }
+
+ /** Interface for test caller to configure the test that will be run with a test network */
+ public interface Test {
+ /** Runs the test with a test network */
+ void runTest(TestNetworkInterface testIface, TestNetworkCallback tunNetworkCallback)
+ throws Exception;
+
+ /** Cleans up when the test is finished or interrupted */
+ void cleanupTest();
+
+ /** Returns the IP addresses that will be used by the test network */
+ default InetAddress[] getTestNetworkAddresses() {
+ return new InetAddress[] {DEFAULT_ADDRESS_4, DEFAULT_ADDRESS_6};
+ }
+ }
+}
diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java
index 7887385..d8e39b4 100644
--- a/tests/cts/net/src/android/net/cts/TunUtils.java
+++ b/tests/cts/net/src/android/net/cts/TunUtils.java
@@ -147,6 +147,10 @@
return espPkt; // We've found the packet we're looking for.
}
+ public byte[] awaitEspPacket(int spi, boolean useEncap) throws Exception {
+ return awaitPacket((pkt) -> isEsp(pkt, spi, useEncap));
+ }
+
private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) {
// Check SPI byte by byte.
return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff)
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 6b7921b..6c4bb90 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -56,21 +56,21 @@
"java/**/*.kt",
],
test_suites: ["device-tests"],
+ certificate: "platform",
jarjar_rules: "jarjar-rules.txt",
static_libs: [
"androidx.test.rules",
"bouncycastle-repackaged-unbundled",
+ "FrameworksNetCommonTests",
"frameworks-base-testutils",
"frameworks-net-integration-testutils",
"framework-protos",
- "mockito-target-extended-minus-junit4",
+ "mockito-target-minus-junit4",
"net-tests-utils",
"platform-test-annotations",
"service-connectivity-pre-jarjar",
"services.core",
"services.net",
- // At the bottom to prefer test libraries above instead of those in the common tests
- "FrameworksNetCommonTests",
],
libs: [
"android.net.ipsec.ike.stubs.module_lib",
@@ -80,9 +80,6 @@
"ServiceConnectivityResources",
],
jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
"libservice-connectivity",
],
}
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index 18653dc..4c60ccf 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -42,7 +42,7 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
<uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
@@ -50,8 +50,7 @@
<uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
<uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
- <!-- Debuggable is necessary for mockito extended -->
- <application android:debuggable="true">
+ <application>
<uses-library android:name="android.test.runner" />
<uses-library android:name="android.net.ipsec.ike" />
</application>
diff --git a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
index 899295a..6bd2bd5 100644
--- a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
+++ b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
@@ -24,8 +24,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,6 +52,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkStatsManagerTest {
+ private static final String TEST_SUBSCRIBER_ID = "subid";
private @Mock INetworkStatsService mService;
private @Mock INetworkStatsSession mStatsSession;
@@ -69,7 +70,6 @@
@Test
public void testQueryDetails() throws RemoteException {
- final String subscriberId = "subid";
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
@@ -113,7 +113,7 @@
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
+ assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId());
return history1;
});
@@ -124,13 +124,13 @@
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
+ assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId());
return history2;
});
NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
+ ConnectivityManager.TYPE_MOBILE, TEST_SUBSCRIBER_ID, startTime, endTime);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -166,35 +166,30 @@
assertFalse(stats.hasNextBucket());
}
- @Test
- public void testQueryDetails_NoSubscriberId() throws RemoteException {
+ private void runQueryDetailsAndCheckTemplate(int networkType, String subscriberId,
+ NetworkTemplate expectedTemplate) throws RemoteException {
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
final int uid2 = 10002;
+ reset(mStatsSession);
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
-
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
.thenReturn(new NetworkStatsHistory(10, 0));
+ NetworkStats stats = mManager.queryDetails(
+ networkType, subscriberId, startTime, endTime);
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+ eq(expectedTemplate),
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+ eq(expectedTemplate),
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
@@ -202,6 +197,25 @@
assertFalse(stats.hasNextBucket());
}
+ @Test
+ public void testNetworkTemplateWhenRunningQueryDetails_NoSubscriberId() throws RemoteException {
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_MOBILE,
+ null /* subscriberId */, NetworkTemplate.buildTemplateMobileWildcard());
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ "" /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard());
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ null /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard());
+ }
+
+ @Test
+ public void testNetworkTemplateWhenRunningQueryDetails_MergedCarrierWifi()
+ throws RemoteException {
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ TEST_SUBSCRIBER_ID,
+ NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
+ TEST_SUBSCRIBER_ID));
+ }
+
private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
assertEquals(expected.uid, actual.getUid());
assertEquals(expected.rxBytes, actual.getRxBytes());
diff --git a/tests/unit/java/android/net/ConnectivityManagerTest.java b/tests/unit/java/android/net/ConnectivityManagerTest.java
index b1b4218..591e0cc 100644
--- a/tests/unit/java/android/net/ConnectivityManagerTest.java
+++ b/tests/unit/java/android/net/ConnectivityManagerTest.java
@@ -46,7 +46,6 @@
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -217,7 +216,6 @@
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest request = makeRequest(1);
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- doCallRealMethod().when(callback).onAvailable(any(), any(), any(), anyInt());
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
@@ -246,7 +244,6 @@
NetworkRequest req1 = makeRequest(1);
NetworkRequest req2 = makeRequest(2);
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- doCallRealMethod().when(callback).onAvailable(any(), any(), any(), anyInt());
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
diff --git a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
index fc739fb..bc6dbf2 100644
--- a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
@@ -24,7 +24,9 @@
import static org.junit.Assert.fail;
import android.net.util.KeepalivePacketDataUtil;
+import android.util.Log;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,8 +40,19 @@
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
+ private Log.TerribleFailureHandler mOriginalHandler;
+
@Before
- public void setUp() {}
+ public void setUp() {
+ // Terrible failures are logged when using deprecated methods on newer platforms
+ mOriginalHandler = Log.setWtfHandler((tag, what, sys) ->
+ Log.e(tag, "Terrible failure in test", what));
+ }
+
+ @After
+ public void tearDown() {
+ Log.setWtfHandler(mOriginalHandler);
+ }
@Test
public void testFromTcpKeepaliveStableParcelable() throws Exception {
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
index 370179c..b0a9b8a 100644
--- a/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -20,12 +20,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
@@ -66,7 +66,7 @@
MockitoAnnotations.initMocks(this);
mServiceHandler = spy(MockServiceHandler.create(mContext));
- doReturn(new Messenger(mServiceHandler)).when(mService).getMessenger();
+ when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
mManager = makeManager();
}
diff --git a/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index 9291532..25aa626 100644
--- a/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -74,7 +74,6 @@
doReturn(Context.TELEPHONY_SERVICE).`when`(it)
.getSystemServiceName(TelephonyManager::class.java)
doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
- doReturn(telephonyManager).`when`(it).getSystemService(TelephonyManager::class.java)
doReturn(subscriptionManager).`when`(it)
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
doReturn(resolver).`when`(it).contentResolver
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 2c19cb8..e8f249e 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -18,14 +18,10 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE;
import static android.Manifest.permission.DUMP;
-import static android.Manifest.permission.GET_INTENT_SENDER_INTENT;
import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
@@ -113,6 +109,8 @@
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
@@ -122,6 +120,8 @@
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
+import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED;
+import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_OEM;
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
import static com.android.testutils.ConcurrentUtils.await;
import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -134,7 +134,6 @@
import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
import static com.android.testutils.MiscAsserts.assertSameElements;
import static com.android.testutils.MiscAsserts.assertThrows;
-import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -260,7 +259,6 @@
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.os.BadParcelableException;
-import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -462,6 +460,7 @@
private TestNetworkCallback mDefaultNetworkCallback;
private TestNetworkCallback mSystemDefaultNetworkCallback;
private TestNetworkCallback mProfileDefaultNetworkCallback;
+ private TestNetworkCallback mTestPackageDefaultNetworkCallback;
// State variables required to emulate NetworkPolicyManagerService behaviour.
private int mBlockedReasons = BLOCKED_REASON_NONE;
@@ -469,7 +468,6 @@
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@Mock NetworkStatsManager mStatsManager;
- @Mock BatteryStatsManager mBatteryStatsManager;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClientBase mNetworkStack;
@@ -488,6 +486,7 @@
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
@Mock Resources mResources;
+ @Mock ProxyTracker mProxyTracker;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -580,7 +579,6 @@
if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
- if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager;
return super.getSystemService(name);
}
@@ -661,13 +659,6 @@
public void setPermission(String permission, Integer granted) {
mMockedPermissions.put(permission, granted);
}
-
- @Override
- public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
- @NonNull IntentFilter filter, @Nullable String broadcastPermission,
- @Nullable Handler scheduler) {
- return null;
- }
}
private void waitForIdle() {
@@ -1217,22 +1208,7 @@
return mDeviceIdleInternal;
}
},
- mNetworkManagementService, mMockNetd, userId, mVpnProfileStore,
- new SystemServices(mServiceContext) {
- @Override
- public String settingsSecureGetStringForUser(String key, int userId) {
- switch (key) {
- // Settings keys not marked as @Readable are not readable from
- // non-privileged apps, unless marked as testOnly=true
- // (atest refuses to install testOnly=true apps), even if mocked
- // in the content provider.
- case Settings.Secure.ALWAYS_ON_VPN_APP:
- return null;
- default:
- return super.settingsSecureGetStringForUser(key, userId);
- }
- }
- }, new Ikev2SessionCreator());
+ mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
}
public void setUids(Set<UidRange> uids) {
@@ -1305,10 +1281,14 @@
return mMockNetworkAgent;
}
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
- boolean hasInternet, boolean isStrictMode) throws Exception {
+ private void setOwnerAndAdminUid(int uid) throws Exception {
mNetworkCapabilities.setOwnerUid(uid);
mNetworkCapabilities.setAdministratorUids(new int[]{uid});
+ }
+
+ public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
+ boolean hasInternet, boolean isStrictMode) throws Exception {
+ setOwnerAndAdminUid(uid);
registerAgent(false, ranges, lp);
connect(validated, hasInternet, isStrictMode);
waitForIdle();
@@ -1553,6 +1533,8 @@
}
private static final int PRIMARY_USER = 0;
+ private static final int SECONDARY_USER = 10;
+ private static final int TERTIARY_USER = 11;
private static final UidRange PRIMARY_UIDRANGE =
UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
@@ -1561,8 +1543,8 @@
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
UserInfo.FLAG_PRIMARY);
private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
- private static final int SECONDARY_USER = 10;
private static final UserHandle SECONDARY_USER_HANDLE = new UserHandle(SECONDARY_USER);
+ private static final UserHandle TERTIARY_USER_HANDLE = new UserHandle(TERTIARY_USER);
private static final int RESTRICTED_USER = 1;
private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
@@ -1610,11 +1592,6 @@
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
new FakeSettingsProvider());
mServiceContext.setUseRegisteredHandlers(true);
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
- mServiceContext.setPermission(CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_GRANTED);
- mServiceContext.setPermission(PACKET_KEEPALIVE_OFFLOAD, PERMISSION_GRANTED);
- mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED);
mAlarmManagerThread = new HandlerThread("TestAlarmManager");
mAlarmManagerThread.start();
@@ -1666,7 +1643,7 @@
doReturn(mNetIdManager).when(deps).makeNetIdManager();
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(mSystemProperties).when(deps).getSystemProperties();
- doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
+ doReturn(mProxyTracker).when(deps).makeProxyTracker(any(), any());
doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
@@ -1845,16 +1822,6 @@
assertEmpty(mCm.getAllNetworkStateSnapshots());
}
- private static PendingIntent wrapPendingIntent(final PendingIntent intent) {
- final PendingIntent ret = spy(intent);
- // intentFilterEquals requires GET_INTENT_SENDER_INTENT permission
- doAnswer(inv -> {
- final PendingIntent other = inv.getArgument(0);
- return runAsShell(GET_INTENT_SENDER_INTENT, () -> intent.intentFilterEquals(other));
- }).when(ret).intentFilterEquals(any());
- return ret;
- }
-
/**
* Class to simplify expecting broadcasts using BroadcastInterceptingContext.
* Ensures that the receiver is unregistered after the expected broadcast is received. This
@@ -3303,8 +3270,8 @@
@Test
public void testNoMutableNetworkRequests() throws Exception {
- final PendingIntent pendingIntent = wrapPendingIntent(PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE));
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
NetworkRequest request1 = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_VALIDATED)
.build();
@@ -4148,16 +4115,16 @@
mCm.registerNetworkCallback(r, new NetworkCallback()));
assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, wrapPendingIntent(PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE))));
+ mCm.registerNetworkCallback(r, PendingIntent.getService(
+ mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
// Requesting a Network with signal strength should get IllegalArgumentException.
assertThrows(IllegalArgumentException.class, () ->
mCm.requestNetwork(r, new NetworkCallback()));
assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, wrapPendingIntent(PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE))));
+ mCm.requestNetwork(r, PendingIntent.getService(
+ mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
}
@Test
@@ -5713,14 +5680,14 @@
}
j = 0;
while (j++ < INTENTS / 2) {
- final PendingIntent pi = wrapPendingIntent(PendingIntent.getBroadcast(mContext,
- 0 /* requestCode */, new Intent("a" + j), FLAG_IMMUTABLE));
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("a" + j), FLAG_IMMUTABLE);
mCm.requestNetwork(networkRequest, pi);
registered.add(pi);
}
while (j++ < INTENTS) {
- final PendingIntent pi = wrapPendingIntent(PendingIntent.getBroadcast(mContext,
- 0 /* requestCode */, new Intent("b" + j), FLAG_IMMUTABLE));
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("b" + j), FLAG_IMMUTABLE);
mCm.registerNetworkCallback(networkRequest, pi);
registered.add(pi);
}
@@ -5734,13 +5701,13 @@
);
assertThrows(TooManyRequestsException.class, () ->
mCm.requestNetwork(networkRequest,
- wrapPendingIntent(PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("c"), FLAG_IMMUTABLE)))
+ PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("c"), FLAG_IMMUTABLE))
);
assertThrows(TooManyRequestsException.class, () ->
mCm.registerNetworkCallback(networkRequest,
- wrapPendingIntent(PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("d"), FLAG_IMMUTABLE)))
+ PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("d"), FLAG_IMMUTABLE))
);
// The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
@@ -5820,16 +5787,16 @@
waitForIdle();
for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = wrapPendingIntent(PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE));
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
mCm.requestNetwork(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
waitForIdle();
for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = wrapPendingIntent(PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("f" + i), FLAG_IMMUTABLE));
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("f" + i), FLAG_IMMUTABLE);
mCm.registerNetworkCallback(networkRequest, pendingIntent);
mCm.unregisterNetworkCallback(pendingIntent);
}
@@ -9272,7 +9239,8 @@
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
+ PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
PERMISSION_DENIED);
}
@@ -9713,7 +9681,7 @@
setupConnectionOwnerUid(vpnOwnerUid, vpnType);
// Test as VPN app
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
mServiceContext.setPermission(
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
}
@@ -9753,7 +9721,8 @@
public void testGetConnectionOwnerUidVpnServiceNetworkStackDoesNotThrow() throws Exception {
final int myUid = Process.myUid();
setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
}
@@ -9921,7 +9890,8 @@
public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
assertTrue(
"NetworkStack permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
@@ -9937,7 +9907,7 @@
nc.setAdministratorUids(new int[] {wrongUid});
final NetworkAgentInfo naiWithUid = fakeWifiNai(nc);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
assertFalse(
"Mismatched uid/package name should not pass the location permission check",
@@ -9947,7 +9917,7 @@
private void verifyConnectivityDiagnosticsPermissionsWithNetworkAgentInfo(
NetworkAgentInfo info, boolean expectPermission) {
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
assertEquals(
"Unexpected ConnDiags permission",
@@ -10015,7 +9985,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
assertTrue(
"NetworkCapabilities administrator uid permission not applied",
@@ -10032,7 +10002,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
// Use wrong pid and uid
assertFalse(
@@ -10058,7 +10028,8 @@
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
@@ -10077,7 +10048,8 @@
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
- mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
@@ -10297,16 +10269,23 @@
@Test
public void testVpnUidRangesUpdate() throws Exception {
- LinkProperties lp = new LinkProperties();
+ // Set up a WiFi network without proxy.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ assertNull(mService.getProxyForNetwork(null));
+ assertNull(mCm.getDefaultProxy());
+
+ final LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
final UidRange vpnRange = PRIMARY_UIDRANGE;
- Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
+ final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
+ // VPN is connected but proxy is not set, so there is no need to send proxy broadcast.
+ verify(mProxyTracker, never()).sendProxyBroadcast();
- reset(mMockNetd);
// Update to new range which is old range minus APP1, i.e. only APP2
final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
new UidRange(vpnRange.start, APP1_UID - 1),
@@ -10316,6 +10295,101 @@
assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
+
+ // Uid has changed but proxy is not set, so there is no need to send proxy broadcast.
+ verify(mProxyTracker, never()).sendProxyBroadcast();
+
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ lp.setHttpProxy(testProxyInfo);
+ mMockVpn.sendLinkProperties(lp);
+ waitForIdle();
+ // Proxy is set, so send a proxy broadcast.
+ verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ reset(mProxyTracker);
+
+ mMockVpn.setUids(vpnRanges);
+ waitForIdle();
+ // Uid has changed and proxy is already set, so send a proxy broadcast.
+ verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ reset(mProxyTracker);
+
+ // Proxy is removed, send a proxy broadcast.
+ lp.setHttpProxy(null);
+ mMockVpn.sendLinkProperties(lp);
+ waitForIdle();
+ verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ reset(mProxyTracker);
+
+ // Proxy is added in WiFi(default network), setDefaultProxy will be called.
+ final LinkProperties wifiLp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
+ assertNotNull(wifiLp);
+ wifiLp.setHttpProxy(testProxyInfo);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ waitForIdle();
+ verify(mProxyTracker, times(1)).setDefaultProxy(eq(testProxyInfo));
+ reset(mProxyTracker);
+ }
+
+ @Test
+ public void testProxyBroadcastWillBeSentWhenVpnHasProxyAndConnects() throws Exception {
+ // Set up a WiFi network without proxy.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ assertNull(mService.getProxyForNetwork(null));
+ assertNull(mCm.getDefaultProxy());
+
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ lp.setHttpProxy(testProxyInfo);
+ final UidRange vpnRange = PRIMARY_UIDRANGE;
+ final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
+ mMockVpn.setOwnerAndAdminUid(VPN_UID);
+ mMockVpn.registerAgent(false, vpnRanges, lp);
+ // In any case, the proxy broadcast won't be sent before VPN goes into CONNECTED state.
+ // Otherwise, the app that calls ConnectivityManager#getDefaultProxy() when it receives the
+ // proxy broadcast will get null.
+ verify(mProxyTracker, never()).sendProxyBroadcast();
+ mMockVpn.connect(true /* validated */, true /* hasInternet */, false /* isStrictMode */);
+ waitForIdle();
+ assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
+ // Vpn is connected with proxy, so the proxy broadcast will be sent to inform the apps to
+ // update their proxy data.
+ verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ }
+
+ @Test
+ public void testProxyBroadcastWillBeSentWhenTheProxyOfNonDefaultNetworkHasChanged()
+ throws Exception {
+ // Set up a CELLULAR network without proxy.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ assertNull(mService.getProxyForNetwork(null));
+ assertNull(mCm.getDefaultProxy());
+ // CELLULAR network should be the default network.
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ // Set up a WiFi network without proxy.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ assertNull(mService.getProxyForNetwork(null));
+ assertNull(mCm.getDefaultProxy());
+ // WiFi network should be the default network.
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ // CELLULAR network is not the default network.
+ assertNotEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ // CELLULAR network is not the system default network, but it might be a per-app default
+ // network. The proxy broadcast should be sent once its proxy has changed.
+ final LinkProperties cellularLp = new LinkProperties();
+ cellularLp.setInterfaceName(MOBILE_IFNAME);
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ cellularLp.setHttpProxy(testProxyInfo);
+ mCellNetworkAgent.sendLinkProperties(cellularLp);
+ waitForIdle();
+ verify(mProxyTracker, times(1)).sendProxyBroadcast();
}
@Test
@@ -10588,29 +10662,30 @@
fail("TOO_MANY_REQUESTS never thrown");
}
- private UidRange createUidRange(int userId) {
- return UidRange.createForUser(UserHandle.of(userId));
+ private void mockGetApplicationInfo(@NonNull final String packageName, final int uid) {
+ mockGetApplicationInfo(packageName, uid, PRIMARY_USER_HANDLE);
}
- private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) {
+ private void mockGetApplicationInfo(@NonNull final String packageName, final int uid,
+ @NonNull final UserHandle user) {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = uid;
try {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenReturn(applicationInfo);
} catch (Exception e) {
fail(e.getMessage());
}
}
- private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+ private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName,
+ @NonNull final UserHandle user)
throws Exception {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenThrow(new PackageManager.NameNotFoundException(packageName));
}
- private void mockHasSystemFeature(@NonNull final String featureName,
- @NonNull final boolean hasFeature) {
+ private void mockHasSystemFeature(@NonNull final String featureName, final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName)))
.thenReturn(hasFeature);
}
@@ -10631,8 +10706,7 @@
}
@Test
- public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
- throws PackageManager.NameNotFoundException {
+ public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError() {
@OemNetworkPreferences.OemNetworkPreference final int prefToTest =
OEM_NETWORK_PREFERENCE_UNINITIALIZED;
@@ -10658,8 +10732,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isListen());
@@ -10687,8 +10762,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isListen());
@@ -10713,8 +10789,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isRequest());
@@ -10736,8 +10813,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isRequest());
@@ -10804,16 +10882,18 @@
}
@Test
- public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids()
+ public void testOemNetworkRequestFactoryMultipleUsersSetsUids()
throws Exception {
// Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
+ final int secondUserTestPackageUid = UserHandle.getUid(SECONDARY_USER, TEST_PACKAGE_UID);
+ final int thirdUserTestPackageUid = UserHandle.getUid(TERTIARY_USER, TEST_PACKAGE_UID);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+ Arrays.asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+ // Arrange PackageManager mocks testing for users who have and don't have a package.
+ mockGetApplicationInfoThrowsNameNotFound(TEST_PACKAGE_NAME, PRIMARY_USER_HANDLE);
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, SECONDARY_USER_HANDLE);
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, thirdUserTestPackageUid, TERTIARY_USER_HANDLE);
// Build OemNetworkPreferences object
final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
@@ -10827,8 +10907,8 @@
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
pref));
- // UIDs for all users and all managed packages should be present.
- // Two users each with two packages.
+ // UIDs for users with installed packages should be present.
+ // Three users exist, but only two have the test package installed.
final int expectedUidSize = 2;
final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
@@ -10836,11 +10916,10 @@
// Sort by uid to access nris by index
uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(0).getLower());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(0).getUpper());
+ assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getLower());
+ assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getUpper());
}
@Test
@@ -10894,7 +10973,48 @@
assertThrows(UnsupportedOperationException.class,
() -> mService.setOemNetworkPreference(
createDefaultOemNetworkPreferences(networkPref),
- new TestOemListenerCallback()));
+ null));
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForTestRequestWithoutPermission() {
+ // Calling setOemNetworkPreference() with a test pref requires the permission
+ // MANAGE_TEST_NETWORKS.
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST;
+
+ // Act on ConnectivityService.setOemNetworkPreference()
+ assertThrows(SecurityException.class,
+ () -> mService.setOemNetworkPreference(
+ createDefaultOemNetworkPreferences(networkPref),
+ null));
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForInvalidTestRequest() {
+ assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST);
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForInvalidTestOnlyRequest() {
+ assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST_ONLY);
+ }
+
+ private void assertSetOemNetworkPreferenceFailsForInvalidTestRequest(
+ @OemNetworkPreferences.OemNetworkPreference final int oemNetworkPreferenceForTest) {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+ final String secondPackage = "does.not.matter";
+
+ // A valid test request would only have a single mapping.
+ final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+ .addNetworkPreference(TEST_PACKAGE_NAME, oemNetworkPreferenceForTest)
+ .addNetworkPreference(secondPackage, oemNetworkPreferenceForTest)
+ .build();
+
+ // Act on ConnectivityService.setOemNetworkPreference()
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.setOemNetworkPreference(pref, null));
}
private void setOemNetworkPreferenceAgentConnected(final int transportType,
@@ -11001,16 +11121,24 @@
}
private void registerDefaultNetworkCallbacks() {
+ if (mSystemDefaultNetworkCallback != null || mDefaultNetworkCallback != null
+ || mProfileDefaultNetworkCallback != null
+ || mTestPackageDefaultNetworkCallback != null) {
+ throw new IllegalStateException("Default network callbacks already registered");
+ }
+
// Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
mProfileDefaultNetworkCallback = new TestNetworkCallback();
+ mTestPackageDefaultNetworkCallback = new TestNetworkCallback();
mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
new Handler(ConnectivityThread.getInstanceLooper()));
mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
TEST_WORK_PROFILE_APP_UID);
+ registerDefaultNetworkCallbackAsUid(mTestPackageDefaultNetworkCallback, TEST_PACKAGE_UID);
// TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
}
@@ -11025,6 +11153,9 @@
if (null != mProfileDefaultNetworkCallback) {
mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
}
+ if (null != mTestPackageDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mTestPackageDefaultNetworkCallback);
+ }
}
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@@ -11060,8 +11191,18 @@
private void setupSetOemNetworkPreferenceForPreferenceTest(
@OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
@NonNull final UidRangeParcel[] uidRanges,
- @NonNull final String testPackageName)
- throws Exception {
+ @NonNull final String testPackageName) throws Exception {
+ setupSetOemNetworkPreferenceForPreferenceTest(
+ networkPrefToSetup, uidRanges, testPackageName, true);
+ }
+
+ private void setupSetOemNetworkPreferenceForPreferenceTest(
+ @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+ @NonNull final UidRangeParcel[] uidRanges,
+ @NonNull final String testPackageName,
+ final boolean hasAutomotiveFeature) throws Exception {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, hasAutomotiveFeature);
+
// These tests work off a single UID therefore using 'start' is valid.
mockGetApplicationInfo(testPackageName, uidRanges[0].start);
@@ -11366,6 +11507,55 @@
}
/**
+ * Test the tracked default requests allows test requests without standard setup.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceAllowsValidTestRequestWithoutChecks() throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST;
+ validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+ }
+
+ /**
+ * Test the tracked default requests allows test only requests without standard setup.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceAllowsValidTestOnlyRequestWithoutChecks()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST_ONLY;
+ validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+ }
+
+ private void validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(int networkPref)
+ throws Exception {
+ // The caller must have the MANAGE_TEST_NETWORKS permission.
+ final int testPackageUid = 123;
+ final String validTestPackageName = "does.not.matter";
+ final UidRangeParcel[] uidRanges =
+ toUidRangeStableParcels(uidRangesForUids(testPackageUid));
+ mServiceContext.setPermission(
+ Manifest.permission.MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
+
+ // Put the system into a state in which setOemNetworkPreference() would normally fail. This
+ // will confirm that a valid test request can bypass these checks.
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+ mServiceContext.setPermission(
+ Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_DENIED);
+
+ // Validate the starting requests only includes the system default request.
+ assertEquals(1, mService.mDefaultNetworkRequests.size());
+
+ // Add an OEM default network request to track.
+ setupSetOemNetworkPreferenceForPreferenceTest(
+ networkPref, uidRanges, validTestPackageName,
+ false /* hasAutomotiveFeature */);
+
+ // Two requests should now exist; the system default and the test request.
+ assertEquals(2, mService.mDefaultNetworkRequests.size());
+ }
+
+ /**
* Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
*/
@Test
@@ -11377,7 +11567,7 @@
final UidRangeParcel[] uidRanges =
toUidRangeStableParcels(uidRangesForUids(testPackageUid));
- // Validate the starting requests only includes the fallback request.
+ // Validate the starting requests only includes the system default request.
assertEquals(1, mService.mDefaultNetworkRequests.size());
// Add an OEM default network request to track.
@@ -11641,6 +11831,7 @@
final UidRangeParcel[] uidRanges =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. No networks should be connected.
@@ -11683,6 +11874,7 @@
final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest(
networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
@@ -11739,7 +11931,7 @@
final UidRangeParcel[] uidRangesSinglePackage =
toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
@@ -11773,7 +11965,7 @@
false /* shouldDestroyNetwork */);
// Set the system to no longer recognize the package to be installed
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
// Send a broadcast indicating a package was removed.
final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
@@ -12808,8 +13000,8 @@
@Test
public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
- final PendingIntent pendingIntent = wrapPendingIntent(PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE));
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
final NetworkCallback networkCallback1 = new NetworkCallback();
final NetworkCallback networkCallback2 = new NetworkCallback();
@@ -12825,8 +13017,8 @@
@Test
public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
- final PendingIntent pendingIntent = wrapPendingIntent(PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE));
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
final Class<SecurityException> expected = SecurityException.class;
assertThrows(
@@ -12914,6 +13106,8 @@
assertEquals(1, nris.size());
assertTrue(nri.isMultilayerRequest());
assertEquals(nri.getUids(), uidRangesForUids(uids));
+ assertEquals(DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED,
+ nri.getDefaultNetworkPriority());
}
/**
@@ -12946,9 +13140,11 @@
@Test
public void testMobileDataPreferredUidsChanged() throws Exception {
final InOrder inorder = inOrder(mMockNetd);
+ registerDefaultNetworkCallbacks();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- waitForIdle();
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
final int cellNetId = mCellNetworkAgent.getNetwork().netId;
inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
@@ -12959,12 +13155,15 @@
inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ // Set MOBILE_DATA_PREFERRED_UIDS setting and verify that net id and uid ranges send to netd
final Set<Integer> uids1 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
setAndUpdateMobileDataPreferredUids(uids1);
inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges1);
inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ // Set MOBILE_DATA_PREFERRED_UIDS setting again and verify that old rules are removed and
+ // new rules are added.
final Set<Integer> uids2 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID),
PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2),
SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
@@ -12972,5 +13171,170 @@
setAndUpdateMobileDataPreferredUids(uids2);
inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges1);
inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges2);
+
+ // Clear MOBILE_DATA_PREFERRED_UIDS setting again and verify that old rules are removed and
+ // new rules are not added.
+ final Set<Integer> uids3 = Set.of();
+ final UidRangeParcel[] uidRanges3 = toUidRangeStableParcels(uidRangesForUids(uids3));
+ setAndUpdateMobileDataPreferredUids(uids3);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges2);
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ }
+
+ /**
+ * Make sure mobile data preferred uids feature behaves as expected when the mobile network
+ * goes up and down while the uids is set. Make sure they behave as expected whether
+ * there is a general default network or not.
+ */
+ @Test
+ public void testMobileDataPreferenceForMobileNetworkUpDown() throws Exception {
+ final InOrder inorder = inOrder(mMockNetd);
+ // File a request for cell to ensure it doesn't go down.
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.requestNetwork(cellRequest, cellNetworkCallback);
+ cellNetworkCallback.assertNoCallback();
+
+ registerDefaultNetworkCallbacks();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int wifiNetId = mWiFiNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ wifiNetId, INetd.PERMISSION_NONE));
+
+ // Initial mobile data preferred uids status.
+ setAndUpdateMobileDataPreferredUids(Set.of());
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ // Set MOBILE_DATA_PREFERRED_UIDS setting and verify that wifi net id and uid ranges send to
+ // netd.
+ final Set<Integer> uids = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
+ final UidRangeParcel[] uidRanges = toUidRangeStableParcels(uidRangesForUids(uids));
+ setAndUpdateMobileDataPreferredUids(uids);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(wifiNetId, uidRanges);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ // Cellular network connected. mTestPackageDefaultNetworkCallback should receive
+ // callback with cellular network and net id and uid ranges should be updated to netd.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.assertNoCallback();
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ cellNetId, INetd.PERMISSION_NONE));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(wifiNetId, uidRanges);
+
+ // Cellular network disconnected. mTestPackageDefaultNetworkCallback should receive
+ // callback with wifi network from fallback request.
+ mCellNetworkAgent.disconnect();
+ mDefaultNetworkCallback.assertNoCallback();
+ cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(wifiNetId, uidRanges);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd).networkDestroy(cellNetId);
+
+ // Cellular network comes back. mTestPackageDefaultNetworkCallback should receive
+ // callback with cellular network.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.assertNoCallback();
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int cellNetId2 = mCellNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ cellNetId2, INetd.PERMISSION_NONE));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId2, uidRanges);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(wifiNetId, uidRanges);
+
+ // Wifi network disconnected. mTestPackageDefaultNetworkCallback should not receive
+ // any callback.
+ mWiFiNetworkAgent.disconnect();
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.assertNoCallback();
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+ waitForIdle();
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd).networkDestroy(wifiNetId);
+
+ mCm.unregisterNetworkCallback(cellNetworkCallback);
+ }
+
+ @Test
+ public void testSetMobileDataPreferredUids_noIssueToFactory() throws Exception {
+ // First set mobile data preferred uid to create a multi-layer requests: 1. listen for
+ // cellular, 2. track the default network for fallback.
+ setAndUpdateMobileDataPreferredUids(
+ Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
+
+ final HandlerThread handlerThread = new HandlerThread("MockFactory");
+ handlerThread.start();
+ NetworkCapabilities internetFilter = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
+ internetFactory.setScoreFilter(40);
+
+ try {
+ internetFactory.register();
+ // Default internet request only. The first request is listen for cellular network,
+ // which is never sent to factories (it's a LISTEN, not requestable). The second
+ // fallback request is TRACK_DEFAULT which is also not sent to factories.
+ internetFactory.expectRequestAdds(1);
+ internetFactory.assertRequestCountEquals(1);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ // The internet factory however is outscored, and should lose its requests.
+ internetFactory.expectRequestRemove();
+ internetFactory.assertRequestCountEquals(0);
+
+ mCellNetworkAgent.disconnect();
+ // The network satisfying the default internet request has disconnected, so the
+ // internetFactory sees the default request again.
+ internetFactory.expectRequestAdds(1);
+ internetFactory.assertRequestCountEquals(1);
+ } finally {
+ internetFactory.terminate();
+ handlerThread.quitSafely();
+ }
+ }
+
+ /**
+ * Validate request counts are counted accurately on MOBILE_DATA_PREFERRED_UIDS change
+ * on set/replace.
+ */
+ @Test
+ public void testMobileDataPreferredUidsChangedCountsRequestsCorrectlyOnSet() throws Exception {
+ ConnectivitySettingsManager.setMobileDataPreferredUids(mServiceContext,
+ Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
+ testRequestCountLimits(() -> {
+ // Set initially to test the limit prior to having existing requests.
+ mService.updateMobileDataPreferredUids();
+ waitForIdle();
+
+ // re-set so as to test the limit as part of replacing existing requests.
+ mService.updateMobileDataPreferredUids();
+ waitForIdle();
+ });
}
}
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index a90fa68..20be5f4 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -57,6 +57,7 @@
public class NsdServiceTest {
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
+ private static final long CLEANUP_DELAY_MS = 500;
long mTimeoutMs = 100; // non-final so that tests can adjust the value.
@@ -86,20 +87,27 @@
}
@Test
- public void testClientsCanConnectAndDisconnect() {
+ public void testNoDaemonStartedWhenClientsConnect() {
when(mSettings.isEnabled()).thenReturn(true);
NsdService service = makeService();
+ // Creating an NsdManager will not cause any cmds executed, which means
+ // no daemon is started.
NsdManager client1 = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
+ verify(mDaemon, never()).execute(any());
+ // Creating another NsdManager will not cause any cmds executed.
NsdManager client2 = connectClient(service);
+ verify(mDaemon, never()).execute(any());
client1.disconnect();
- client2.disconnect();
+ // Still 1 client remains, daemon shouldn't be stopped.
+ verify(mDaemon, never()).maybeStop();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
+ client2.disconnect();
+ // All clients are disconnected, stop the daemon after CLEANUP_DELAY_MS.
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
client1.disconnect();
client2.disconnect();
@@ -113,7 +121,8 @@
NsdService service = makeService();
NsdManager client = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
+ verify(mDaemon, never()).maybeStart();
+ verify(mDaemon, never()).execute(any());
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
request.setPort(2201);
@@ -121,21 +130,24 @@
// Client registration request
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
client.registerService(request, PROTOCOL, listener1);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("register 2 a_name a_type 2201");
// Client discovery request
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
client.discoverServices("a_type", PROTOCOL, listener2);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("discover 3 a_type");
// Client resolve request
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
client.resolveService(request, listener3);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("resolve 4 a_name a_type local.");
- // Client disconnects
+ // Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
client.disconnect();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
// checks that request are cleaned
verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
@@ -143,12 +155,38 @@
client.disconnect();
}
+ @Test
+ public void testCleanupDelayNoRequestActive() {
+ when(mSettings.isEnabled()).thenReturn(true);
+ when(mDaemon.execute(any())).thenReturn(true);
+
+ NsdService service = makeService();
+ NsdManager client = connectClient(service);
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ request.setPort(2201);
+ NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+ client.registerService(request, PROTOCOL, listener1);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
+ verifyDaemonCommand("register 2 a_name a_type 2201");
+
+ client.unregisterService(listener1);
+ verifyDaemonCommand("stop-register 2");
+
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
+ reset(mDaemon);
+ client.disconnect();
+ // Client disconnects, after CLEANUP_DELAY_MS, maybeStop the daemon.
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
+ }
+
NsdService makeService() {
DaemonConnectionSupplier supplier = (callback) -> {
mDaemonCallback = callback;
return mDaemon;
};
- NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
+ NsdService service = new NsdService(mContext, mSettings,
+ mHandler, supplier, CLEANUP_DELAY_MS);
verify(mDaemon, never()).execute(any(String.class));
return service;
}
@@ -157,6 +195,13 @@
return new NsdManager(mContext, service);
}
+ void verifyDelayMaybeStopDaemon(long cleanupDelayMs) {
+ // Stop daemon shouldn't be called immediately.
+ verify(mDaemon, timeout(mTimeoutMs).times(0)).maybeStop();
+ // Clean up the daemon after CLEANUP_DELAY_MS.
+ verify(mDaemon, timeout(cleanupDelayMs + mTimeoutMs)).maybeStop();
+ }
+
void verifyDaemonCommands(String... wants) {
verifyDaemonCommand(String.join(" ", wants), wants.length);
}
diff --git a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index d6bd08e..38f6d7f 100644
--- a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -116,7 +116,6 @@
private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
when(mContext.getSystemService(serviceName)).thenReturn(service);
- when(mContext.getSystemService(serviceClass)).thenReturn(service);
}
@Before
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index 0bfc129..e98f5db 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -139,7 +139,6 @@
.thenReturn(Context.SYSTEM_CONFIG_SERVICE);
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
.thenReturn(mSystemConfigManager);
- when(mContext.getSystemService(SystemConfigManager.class)).thenReturn(mSystemConfigManager);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index a086451..b725b82 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -219,11 +219,19 @@
when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
- mockService(UserManager.class, Context.USER_SERVICE, mUserManager);
- mockService(AppOpsManager.class, Context.APP_OPS_SERVICE, mAppOps);
- mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
- mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
- mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
+ when(mContext.getSystemServiceName(UserManager.class))
+ .thenReturn(Context.USER_SERVICE);
+ when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
+ when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
+ when(mContext.getSystemServiceName(NotificationManager.class))
+ .thenReturn(Context.NOTIFICATION_SERVICE);
+ when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
+ .thenReturn(mNotificationManager);
+ when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
+ .thenReturn(mConnectivityManager);
+ when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
+ when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -251,12 +259,6 @@
.thenReturn(tunnelResp);
}
- private <T> void mockService(Class<T> clazz, String name, T service) {
- doReturn(service).when(mContext).getSystemService(clazz);
- doReturn(service).when(mContext).getSystemService(name);
- doReturn(name).when(mContext).getSystemServiceName(clazz);
- }
-
private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
final Set<Range<Integer>> range = new ArraySet<>();
for (Range<Integer> r : ranges) range.add(r);
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index da2fdf4..0ba5f7d 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -16,16 +16,12 @@
package com.android.server.net;
-import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkIdentity.OEM_PAID;
import static android.net.NetworkIdentity.OEM_PRIVATE;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -110,7 +106,6 @@
import android.provider.Settings;
import android.telephony.TelephonyManager;
-import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -204,26 +199,6 @@
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
return mBaseContext.getSystemService(name);
}
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, @Nullable String message) {
- if (checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
- super.enforceCallingOrSelfPermission(permission, message);
- }
- }
-
- @Override
- public int checkCallingOrSelfPermission(String permission) {
- switch (permission) {
- case PERMISSION_MAINLINE_NETWORK_STACK:
- case READ_NETWORK_USAGE_HISTORY:
- case UPDATE_DEVICE_STATS:
- return PERMISSION_GRANTED;
- default:
- return super.checkCallingOrSelfPermission(permission);
- }
-
- }
}
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {