Merge changes from topic "am-cc17cb7d48ea4bd7adc9183dc0c381e3-sc-dev" into sc-dev
* changes:
Apply jarjar rules on coverage tests
Re-skip connectivity unit tests before S
Move ConnectivityCoverageTests to general-tests
Fix ConnectivityManagerTest initialization on Q
Move test_mainline_modules to AndroidTest.xml
Add ConnectivityCoverageTests to postsubmit
Add connectivity coverage tests
Make tests compatible with mockito-extended
Fix KeepalivePacketDataUtilTest crash on eng build
Update connectivity TEST_MAPPING
diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c
index 6ff370c..336d27a 100644
--- a/Tethering/bpf_progs/offload.c
+++ b/Tethering/bpf_progs/offload.c
@@ -569,6 +569,16 @@
// For a rawip tx interface it will simply be a bunch of zeroes and later stripped.
*eth = v->macHeader;
+ // Decrement the IPv4 TTL, we already know it's greater than 1.
+ // u8 TTL field is followed by u8 protocol to make a u16 for ipv4 header checksum update.
+ // Since we're keeping the ipv4 checksum valid (which means the checksum of the entire
+ // ipv4 header remains 0), the overall checksum of the entire packet does not change.
+ const int sz2 = sizeof(__be16);
+ const __be16 old_ttl_proto = *(__be16 *)&ip->ttl;
+ const __be16 new_ttl_proto = old_ttl_proto - htons(0x0100);
+ bpf_l3_csum_replace(skb, ETH_IP4_OFFSET(check), old_ttl_proto, new_ttl_proto, sz2);
+ bpf_skb_store_bytes(skb, ETH_IP4_OFFSET(ttl), &new_ttl_proto, sz2, 0);
+
const int l4_offs_csum = is_tcp ? ETH_IP4_TCP_OFFSET(check) : ETH_IP4_UDP_OFFSET(check);
const int sz4 = sizeof(__be32);
// UDP 0 is special and stored as FFFF (this flag also causes a csum of 0 to be unmodified)
@@ -586,7 +596,6 @@
bpf_l3_csum_replace(skb, ETH_IP4_OFFSET(check), old_saddr, new_saddr, sz4);
bpf_skb_store_bytes(skb, ETH_IP4_OFFSET(saddr), &new_saddr, sz4, 0);
- const int sz2 = sizeof(__be16);
// The offsets for TCP and UDP ports: source (u16 @ L4 offset 0) & dest (u16 @ L4 offset 2) are
// actually the same, so the compiler should just optimize them both down to a constant.
bpf_l4_csum_replace(skb, l4_offs_csum, k.srcPort, v->srcPort, sz2 | l4_flags);
@@ -597,8 +606,6 @@
bpf_skb_store_bytes(skb, is_tcp ? ETH_IP4_TCP_OFFSET(dest) : ETH_IP4_UDP_OFFSET(dest),
&v->dstPort, sz2, 0);
- // TEMP HACK: lack of TTL decrement
-
// This requires the bpf_ktime_get_boot_ns() helper which was added in 5.8,
// and backported to all Android Common Kernel 4.14+ trees.
if (updatetime) v->last_used = bpf_ktime_get_boot_ns();
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 56dc69c..2c1fd29 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -1069,10 +1069,11 @@
throw new AssertionError("IP address array not valid IPv4 address!");
}
+ final String protoStr = (key.l4proto == OsConstants.IPPROTO_TCP) ? "tcp" : "udp";
final String ageStr = (value.lastUsed == 0) ? "-"
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
- return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
- key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
+ return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
+ protoStr, key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
value.oif, getIfName(value.oif),
public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageStr);
}
@@ -1095,12 +1096,14 @@
try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
BpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) {
- pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
+ pw.println("IPv4 Upstream: proto [inDstMac] iif(iface) src -> nat -> "
+ + "dst [outDstMac] age");
pw.increaseIndent();
dumpIpv4ForwardingRuleMap(now, UPSTREAM, upstreamMap, pw);
pw.decreaseIndent();
- pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
+ pw.println("IPv4 Downstream: proto [inDstMac] iif(iface) src -> nat -> "
+ + "dst [outDstMac] age");
pw.increaseIndent();
dumpIpv4ForwardingRuleMap(now, DOWNSTREAM, downstreamMap, pw);
pw.decreaseIndent();
diff --git a/framework/Android.bp b/framework/Android.bp
index a447a9c..5e7262a 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -76,8 +76,6 @@
],
},
impl_only_libs: [
- // TODO (b/183097033) remove once module_current includes core_platform
- "stable.core.platform.api.stubs",
"framework-tethering.stubs.module_lib",
"framework-wifi.stubs.module_lib",
"net-utils-device-common",
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 758c612..2eb5fb7 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4948,7 +4948,7 @@
Log.e(TAG, "Can't set proxy properties", e);
}
// Must flush DNS cache as new network may have different DNS resolutions.
- InetAddressCompat.clearDnsCache();
+ InetAddress.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 085de6b..8fc0065 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -29,6 +29,8 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.net.ConnectivityManager.MultipathPreference;
+import android.os.Binder;
+import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
@@ -1039,6 +1041,15 @@
return getUidSetFromString(uidList);
}
+ private static boolean isCallingFromSystem() {
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ if (uid == Process.SYSTEM_UID && pid == Process.myPid()) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
*
@@ -1047,6 +1058,15 @@
*/
public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
@NonNull Set<Integer> uidList) {
+ final boolean calledFromSystem = isCallingFromSystem();
+ if (!calledFromSystem) {
+ // Enforce NETWORK_SETTINGS check if it's debug build. This is for MTS test only.
+ if (!Build.isDebuggable()) {
+ throw new SecurityException("Only system can set this setting.");
+ }
+ context.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
+ "Requires NETWORK_SETTINGS permission");
+ }
final String uids = getUidStringFromSet(uidList);
Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
uids);
diff --git a/framework/src/android/net/InetAddressCompat.java b/framework/src/android/net/InetAddressCompat.java
deleted file mode 100644
index 6b7e75c..0000000
--- a/framework/src/android/net/InetAddressCompat.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * Compatibility utility for InetAddress core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
- * @hide
- */
-public class InetAddressCompat {
-
- /**
- * @see InetAddress#clearDnsCache()
- */
- public static void clearDnsCache() {
- try {
- InetAddress.class.getMethod("clearDnsCache").invoke(null);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
- }
- }
-
- /**
- * @see InetAddress#getAllByNameOnNet(String, int)
- */
- public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
- }
-
- /**
- * @see InetAddress#getByNameOnNet(String, int)
- */
- public static InetAddress getByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
- }
-
- private static Object callGetByNameMethod(String method, String host, int netId)
- throws UnknownHostException {
- try {
- return InetAddress.class.getMethod(method, String.class, int.class)
- .invoke(null, host, netId);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof UnknownHostException) {
- throw (UnknownHostException) e.getCause();
- }
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
- throw new IllegalStateException("Error querying via " + method, e);
- }
- }
-}
diff --git a/framework/src/android/net/Network.java b/framework/src/android/net/Network.java
index 1f49033..b3770ea 100644
--- a/framework/src/android/net/Network.java
+++ b/framework/src/android/net/Network.java
@@ -142,7 +142,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
+ return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -155,7 +155,7 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
+ return InetAddress.getByNameOnNet(host, getNetIdForResolv());
}
/**
diff --git a/service/Android.bp b/service/Android.bp
index 9cf1b09..7fe0e2b 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -57,9 +57,6 @@
":net-module-utils-srcs",
],
libs: [
- // TODO (b/183097033) remove once system_server_current includes core_current
- "stable.core.platform.api.stubs",
- "android_system_server_stubs_current",
"framework-annotations-lib",
"framework-connectivity.impl",
"framework-tethering.stubs.module_lib",
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index 70ddb9a..bf32ad5 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -111,4 +111,7 @@
notification that can be dismissed. -->
<bool name="config_ongoingSignInNotification">false</bool>
+ <!-- Whether to cancel network notifications automatically when tapped -->
+ <bool name="config_autoCancelNetworkNotifications">true</bool>
+
</resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index fd23566..6ac6a0e 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -31,7 +31,9 @@
<item type="integer" name="config_networkNotifySwitchType"/>
<item type="array" name="config_networkNotifySwitches"/>
<item type="bool" name="config_ongoingSignInNotification"/>
-
+ <item type="bool" name="config_autoCancelNetworkNotifications"/>
+ <item type="drawable" name="stat_notify_wifi_in_range"/>
+ <item type="drawable" name="stat_notify_rssi_in_range"/>
</policy>
</overlayable>
</resources>
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 7b58503..0b61247 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -178,6 +178,7 @@
import android.net.VpnTransportInfo;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
+import android.net.netd.aidl.NativeUidRangeConfig;
import android.net.netlink.InetDiagMessage;
import android.net.networkstack.ModuleNetworkStackClient;
import android.net.networkstack.NetworkStackClientBase;
@@ -3268,11 +3269,6 @@
}
case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
// TODO: prevent loops, e.g., if a network declares itself as underlying.
- if (!nai.supportsUnderlyingNetworks()) {
- Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
- break;
- }
-
final List<Network> underlying = (List<Network>) arg.second;
if (isLegacyLockdownNai(nai)
@@ -4213,10 +4209,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())
- /* nri.getDefaultNetworkPriority() */);
+ mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ satisfier.network.getNetId(),
+ toUidRangeStableParcels(nri.getUids()),
+ nri.getDefaultNetworkPriority()));
} catch (RemoteException e) {
loge("Exception setting network preference default network", e);
}
@@ -5285,12 +5281,12 @@
* information, e.g underlying ifaces.
*/
private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
- if (!nai.isVPN()) return null;
-
Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
// see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
// the underlyingNetworks list.
- if (underlyingNetworks == null) {
+ // TODO: stop using propagateUnderlyingCapabilities here, for example, by always
+ // initializing NetworkAgentInfo#declaredUnderlyingNetworks to an empty array.
+ if (underlyingNetworks == null && nai.propagateUnderlyingCapabilities()) {
final NetworkAgentInfo defaultNai = getDefaultNetworkForUid(
nai.networkCapabilities.getOwnerUid());
if (defaultNai != null) {
@@ -5339,7 +5335,7 @@
private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) {
// TODO: support more than one level of underlying networks, either via a fixed-depth search
// (e.g., 2 levels of underlying networks), or via loop detection, or....
- if (!nai.supportsUnderlyingNetworks()) return false;
+ if (!nai.propagateUnderlyingCapabilities()) return false;
final Network[] underlying = underlyingNetworksOrDefault(
nai.networkCapabilities.getOwnerUid(), nai.declaredUnderlyingNetworks);
return CollectionUtils.contains(underlying, network);
@@ -7303,7 +7299,7 @@
newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
- if (nai.supportsUnderlyingNetworks()) {
+ if (nai.propagateUnderlyingCapabilities()) {
applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities,
newNc);
}
@@ -7473,13 +7469,11 @@
maybeCloseSockets(nai, ranges, exemptUids);
try {
if (add) {
- // TODO: Passing default network priority to netd.
- mNetd.networkAddUidRanges(nai.network.netId, ranges
- /* DEFAULT_NETWORK_PRIORITY_NONE */);
+ mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
+ nai.network.netId, ranges, DEFAULT_NETWORK_PRIORITY_NONE));
} else {
- // TODO: Passing default network priority to netd.
- mNetd.networkRemoveUidRanges(nai.network.netId, ranges
- /* DEFAULT_NETWORK_PRIORITY_NONE */);
+ mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ nai.network.netId, ranges, DEFAULT_NETWORK_PRIORITY_NONE));
}
} catch (Exception e) {
loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
@@ -7821,18 +7815,16 @@
+ " any applications to set as the default." + nri);
}
if (null != newDefaultNetwork) {
- // TODO: Passing default network priority to netd.
- mNetd.networkAddUidRanges(
+ mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
newDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids())
- /* nri.getDefaultNetworkPriority() */);
+ toUidRangeStableParcels(nri.getUids()),
+ nri.getDefaultNetworkPriority()));
}
if (null != oldDefaultNetwork) {
- // TODO: Passing default network priority to netd.
- mNetd.networkRemoveUidRanges(
+ mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
oldDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids())
- /* nri.getDefaultNetworkPriority() */);
+ toUidRangeStableParcels(nri.getUids()),
+ nri.getDefaultNetworkPriority()));
}
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception setting app default network", e);
@@ -8445,7 +8437,7 @@
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
if (!createNativeNetwork(networkAgent)) return;
- if (networkAgent.supportsUnderlyingNetworks()) {
+ if (networkAgent.propagateUnderlyingCapabilities()) {
// Initialize the network's capabilities to their starting values according to the
// underlying networks. This ensures that the capabilities are correct before
// anything happens to the network.
@@ -9354,7 +9346,7 @@
private boolean ownsVpnRunningOverNetwork(int uid, Network network) {
for (NetworkAgentInfo virtual : mNetworkAgentInfos) {
- if (virtual.supportsUnderlyingNetworks()
+ if (virtual.propagateUnderlyingCapabilities()
&& virtual.networkCapabilities.getOwnerUid() == uid
&& CollectionUtils.contains(virtual.declaredUnderlyingNetworks, network)) {
return true;
@@ -9953,7 +9945,7 @@
// - The request for the mobile network preferred.
// - The request for the default network, for fallback.
requests.add(createDefaultInternetRequestForTransport(
- TRANSPORT_CELLULAR, NetworkRequest.Type.LISTEN));
+ TRANSPORT_CELLULAR, NetworkRequest.Type.REQUEST));
requests.add(createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
final Set<UidRange> ranges = new ArraySet<>();
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 18becd4..bbf523a 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -157,8 +157,8 @@
@NonNull public NetworkCapabilities networkCapabilities;
@NonNull public final NetworkAgentConfig networkAgentConfig;
- // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
- // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
+ // Underlying networks declared by the agent.
+ // The networks in this list might be declared by a VPN using setUnderlyingNetworks and are
// not guaranteed to be current or correct, or even to exist.
//
// This array is read and iterated on multiple threads with no locking so its contents must
@@ -168,7 +168,7 @@
// The capabilities originally announced by the NetworkAgent, regardless of any capabilities
// that were added or removed due to this network's underlying networks.
- // Only set if #supportsUnderlyingNetworks is true.
+ // Only set if #propagateUnderlyingCapabilities is true.
public @Nullable NetworkCapabilities declaredCapabilities;
// Indicates if netd has been told to create this Network. From this point on the appropriate
@@ -898,8 +898,11 @@
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
- /** Whether this network might have underlying networks. Currently only true for VPNs. */
- public boolean supportsUnderlyingNetworks() {
+ /**
+ * Whether this network should propagate the capabilities from its underlying networks.
+ * Currently only true for VPNs.
+ */
+ public boolean propagateUnderlyingCapabilities() {
return isVPN();
}
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
index 3dc79c5..ae98d92 100644
--- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -274,7 +274,7 @@
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
.setSmallIcon(icon)
- .setAutoCancel(true)
+ .setAutoCancel(r.getBoolean(R.bool.config_autoCancelNetworkNotifications))
.setTicker(title)
.setColor(mContext.getColor(android.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/service/src/com/android/server/connectivity/OsCompat.java b/service/src/com/android/server/connectivity/OsCompat.java
deleted file mode 100644
index 57e3dcd..0000000
--- a/service/src/com/android/server/connectivity/OsCompat.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-
-/**
- * Compatibility utility for android.system.Os core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because Os is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/157639992, b/183097033): remove as soon as core_current is part of system_server_current
- * @hide
- */
-public class OsCompat {
- // This value should be correct on all architectures supported by Android, but hardcoding ioctl
- // numbers should be avoided.
- /**
- * @see android.system.OsConstants#TIOCOUTQ
- */
- public static final int TIOCOUTQ = 0x5411;
-
- /**
- * @see android.system.Os#getsockoptInt(FileDescriptor, int, int)
- */
- public static int getsockoptInt(FileDescriptor fd, int level, int option) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "getsockoptInt", FileDescriptor.class, int.class, int.class)
- .invoke(null, fd, level, option);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling getsockoptInt", e);
- }
- }
-
- /**
- * @see android.system.Os#ioctlInt(FileDescriptor, int)
- */
- public static int ioctlInt(FileDescriptor fd, int cmd) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "ioctlInt", FileDescriptor.class, int.class).invoke(null, fd, cmd);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling ioctlInt", e);
- }
- }
-}
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index e98a638..56b2e6d 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -121,15 +121,23 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final Uri packageData = intent.getData();
- final String packageName =
- packageData != null ? packageData.getSchemeSpecificPart() : null;
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
onPackageAdded(packageName, uid);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
onPackageRemoved(packageName, uid);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ final String[] pkgList =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ onExternalApplicationsAvailable(pkgList);
} else {
Log.wtf(TAG, "received unexpected intent: " + action);
}
@@ -194,6 +202,12 @@
mIntentReceiver, intentFilter, null /* broadcastPermission */,
null /* scheduler */);
+ final IntentFilter externalIntentFilter =
+ new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ userAllContext.registerReceiver(
+ mIntentReceiver, externalIntentFilter, null /* broadcastPermission */,
+ null /* scheduler */);
+
// Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
mDeps.registerContentObserver(
userAllContext,
@@ -812,6 +826,21 @@
update(mUsers, removedUids, false /* add */);
}
+ private synchronized void onExternalApplicationsAvailable(String[] pkgList) {
+ if (CollectionUtils.isEmpty(pkgList)) {
+ Log.e(TAG, "No available external application.");
+ return;
+ }
+
+ for (String app : pkgList) {
+ final PackageInfo info = getPackageInfo(app);
+ if (info == null || info.applicationInfo == null) continue;
+
+ final int appId = info.applicationInfo.uid;
+ onPackageAdded(app, appId); // Use onPackageAdded to add package one by one.
+ }
+ }
+
/** Dump info to dumpsys */
public void dump(IndentingPrintWriter pw) {
pw.println("Interface filtering rules:");
diff --git a/service/src/com/android/server/connectivity/TcpKeepaliveController.java b/service/src/com/android/server/connectivity/TcpKeepaliveController.java
index 73f3475..c480594 100644
--- a/service/src/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/service/src/com/android/server/connectivity/TcpKeepaliveController.java
@@ -27,8 +27,7 @@
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IP_TOS;
import static android.system.OsConstants.IP_TTL;
-
-import static com.android.server.connectivity.OsCompat.TIOCOUTQ;
+import static android.system.OsConstants.TIOCOUTQ;
import android.annotation.NonNull;
import android.net.InvalidPacketException;
@@ -176,10 +175,10 @@
}
// Query write sequence number from SEND_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
- tcpDetails.seq = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Query read sequence number from RECV_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
- tcpDetails.ack = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
// Finally, check if socket is still idle. TODO : this check needs to move to
@@ -199,9 +198,9 @@
tcpDetails.rcvWndScale = trw.rcvWndScale;
if (tcpDetails.srcAddress.length == 4 /* V4 address length */) {
// Query TOS.
- tcpDetails.tos = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
+ tcpDetails.tos = Os.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
// Query TTL.
- tcpDetails.ttl = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
+ tcpDetails.ttl = Os.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
}
} catch (ErrnoException e) {
Log.e(TAG, "Exception reading TCP state from socket", e);
@@ -306,7 +305,7 @@
private static boolean isReceiveQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCINQ);
+ final int result = Os.ioctlInt(fd, SIOCINQ);
if (result != 0) {
Log.e(TAG, "Read queue has data");
return false;
@@ -316,7 +315,7 @@
private static boolean isSendQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCOUTQ);
+ final int result = Os.ioctlInt(fd, SIOCOUTQ);
if (result != 0) {
Log.e(TAG, "Write queue has data");
return false;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
index ddc5fd4..ad7ec9e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
@@ -23,6 +23,8 @@
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidNetworkingBlocked;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidRestrictedOnMeteredNetworks;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -79,6 +81,7 @@
assertFalse(isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED
}
+ @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withSystemUid() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -103,6 +106,7 @@
}
}
+ @RequiredProperties({DATA_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withDataSaverMode() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -182,6 +186,7 @@
}
}
+ @RequiredProperties({BATTERY_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withPowerSaverMode() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -209,6 +214,7 @@
}
}
+ @RequiredProperties({DATA_SAVER_MODE})
@Test
public void testIsUidRestrictedOnMeteredNetworks() throws Exception {
try {
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index a54fd64..86642ea 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -35,6 +35,7 @@
import android.os.Build;
import android.os.connectivity.CellularBatteryStats;
import android.os.connectivity.WifiBatteryStats;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
@@ -80,6 +81,7 @@
}
@Test
+ @AppModeFull(reason = "Cannot get CHANGE_NETWORK_STATE to request wifi/cell in instant mode")
@SkipPresubmit(reason = "Virtual hardware does not support wifi battery stats")
public void testReportNetworkInterfaceForTransports() throws Exception {
try {
@@ -132,6 +134,7 @@
}
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testReportNetworkInterfaceForTransports_throwsSecurityException()
throws Exception {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index bff20b0..9be7855 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -501,6 +501,7 @@
@Test
public void testGetAllNetworkStateSnapshots()
throws InterruptedException {
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
// Make sure cell is active to retrieve IMSI for verification in later step.
final Network cellNetwork = mCtsNetUtils.connectToCell();
final String subscriberId = getSubscriberIdForCellNetwork(cellNetwork);
@@ -1079,7 +1080,7 @@
final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
if (!m.find()) {
- fail("Unexpected format from cmd netpolicy");
+ fail("Unexpected format from cmd netpolicy, policyString = " + policyString);
}
return m.group(1);
}
@@ -2879,6 +2880,10 @@
public void testUidsAllowedOnRestrictedNetworks() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
+ // TODO (b/175199465): figure out a reasonable permission check for
+ // setUidsAllowedOnRestrictedNetworks that allows tests but not system-external callers.
+ assumeTrue(Build.isDebuggable());
+
final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */);
final Set<Integer> originalUidsAllowedOnRestrictedNetworks =
ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext);
@@ -2886,8 +2891,9 @@
// because it has been just installed to device. In case the uid is existed in setting
// mistakenly, try to remove the uid and set correct uids to setting.
originalUidsAllowedOnRestrictedNetworks.remove(uid);
- ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext,
- originalUidsAllowedOnRestrictedNetworks);
+ runWithShellPermissionIdentity(() ->
+ ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
+ mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
final Handler h = new Handler(Looper.getMainLooper());
final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
@@ -2934,8 +2940,9 @@
final Set<Integer> newUidsAllowedOnRestrictedNetworks =
new ArraySet<>(originalUidsAllowedOnRestrictedNetworks);
newUidsAllowedOnRestrictedNetworks.add(uid);
- ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext,
- newUidsAllowedOnRestrictedNetworks);
+ runWithShellPermissionIdentity(() ->
+ ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
+ mContext, newUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
// Wait a while for sending allowed uids on the restricted network to netd.
// TODD: Have a significant signal to know the uids has been send to netd.
assertBindSocketToNetworkSuccess(network);
@@ -2944,8 +2951,9 @@
agent.unregister();
// Restore setting.
- ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(mContext,
- originalUidsAllowedOnRestrictedNetworks);
+ runWithShellPermissionIdentity(() ->
+ ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
+ mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
}
}
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index ccc9416..7c380e3 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -101,6 +101,7 @@
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.Assert.assertArrayEquals
+import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -1034,6 +1035,9 @@
@Test
fun testQosCallbackRegisterWithUnregister() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
@@ -1060,6 +1064,9 @@
@Test
fun testQosCallbackOnQosSession() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
Executors.newSingleThreadExecutor().let { executor ->
@@ -1104,6 +1111,9 @@
@Test
fun testQosCallbackOnError() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
Executors.newSingleThreadExecutor().let { executor ->
@@ -1142,6 +1152,9 @@
@Test
fun testQosCallbackIdsAreMappedCorrectly() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback1 = TestableQosCallback()
val qosCallback2 = TestableQosCallback()
@@ -1182,6 +1195,9 @@
@Test
fun testQosCallbackWhenNetworkReleased() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
Executors.newSingleThreadExecutor().let { executor ->
try {
diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
index 7d5e9ff..a20f1cc 100644
--- a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
@@ -35,6 +35,7 @@
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.util.Range;
@@ -145,6 +146,7 @@
}
}
+ @AppModeFull(reason = "Instant apps can't bind sockets to localhost for a test proxy server")
@Test
public void testSetCurrentProxyScriptUrl() throws Exception {
// Register a PacProxyInstalledListener
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 0a5e506..bd1b74a 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -361,6 +361,7 @@
@Test
public void testRequestLatestEntitlementResult() throws Exception {
assumeTrue(mTM.isTetheringSupported());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
// Verify that requestLatestTetheringEntitlementResult() can get entitlement
// result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener.
assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
diff --git a/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
index 17db179..95ea401 100644
--- a/tests/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -55,6 +55,7 @@
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkCallback;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -255,6 +256,15 @@
}
}
+ public void setUnderlyingNetworks(List<Network> underlyingNetworks) {
+ mNetworkAgent.setUnderlyingNetworks(underlyingNetworks);
+ }
+
+ public void setOwnerUid(int uid) {
+ mNetworkCapabilities.setOwnerUid(uid);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
public void connect() {
if (!mConnected.compareAndSet(false /* expect */, true /* update */)) {
// compareAndSet returns false when the value couldn't be updated because it did not
diff --git a/tests/unit/java/android/net/NetworkStatsTest.java b/tests/unit/java/android/net/NetworkStatsTest.java
index 1cdc6cb..c971da1 100644
--- a/tests/unit/java/android/net/NetworkStatsTest.java
+++ b/tests/unit/java/android/net/NetworkStatsTest.java
@@ -734,6 +734,56 @@
ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
}
+ // Tests a case where an PlatformVpn is used, where the entire datapath is in the kernel,
+ // including all encapsulation/decapsulation.
+ @Test
+ public void testMigrateTun_platformVpn() {
+ final int ownerUid = Process.SYSTEM_UID;
+ final String tunIface = "ipsec1";
+ final String underlyingIface = "wlan0";
+ NetworkStats delta = new NetworkStats(TEST_START, 9)
+ // 2 different apps sent/receive data via ipsec1.
+ .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
+ .insertEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
+ // Owner (system) sends data through the tunnel
+ .insertEntry(tunIface, ownerUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 2000L, 20L, 3000L, 30L, 0L)
+ // 1 app already has some traffic on the underlying interface, the other doesn't yet
+ .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L);
+
+ delta.migrateTun(ownerUid, tunIface, Arrays.asList(underlyingIface));
+ assertEquals(9, delta.size()); // 3 DBG entries + 1 entry per app per interface
+
+ // tunIface entries should not be changed.
+ assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+ assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
+ assertValues(delta, 2, tunIface, ownerUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 2000L, 20L, 3000L, 30L, 0L);
+
+ // Existing underlying Iface entries are updated to include usage over ipsec1
+ assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 51000L, 35L, 102000L, 70L, 0L);
+
+ // New entries are added on underlying Iface traffic
+ assertContains(delta, underlyingIface, ownerUid, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 2000L, 20L, 3000L, 30L, 0L);
+ assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
+
+ // New entries are added for debug purpose
+ assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+ assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 500, 2L, 200L, 5L, 0L);
+ assertContains(delta, underlyingIface, ownerUid, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 2000L, 20L, 3000L, 30L, 0L);
+ }
+
@Test
public void testFilter_NoFilter() {
NetworkStats.Entry entry1 = new NetworkStats.Entry(
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 307e2c8..cdf5d62 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -126,7 +126,9 @@
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_NONE;
import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_OEM;
+import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_PROFILE;
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
import static com.android.testutils.ConcurrentUtils.await;
import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -258,6 +260,7 @@
import android.net.VpnManager;
import android.net.VpnTransportInfo;
import android.net.metrics.IpConnectivityLog;
+import android.net.netd.aidl.NativeUidRangeConfig;
import android.net.networkstack.NetworkStackClientBase;
import android.net.resolv.aidl.Nat64PrefixEventParcel;
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
@@ -1296,10 +1299,12 @@
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(uids)));
- verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
+ verify(mMockNetd, times(1)).networkAddUidRangesParcel(
+ new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
+ toUidRangeStableParcels(uids), DEFAULT_NETWORK_PRIORITY_NONE));
+ verify(mMockNetd, never()).networkRemoveUidRangesParcel(argThat(config ->
+ mMockVpn.getNetwork().getNetId() == config.netId
+ && DEFAULT_NETWORK_PRIORITY_NONE == config.subPriority));
mAgentRegistered = true;
verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
!mMockNetworkAgent.isBypassableVpn(), mVpnType));
@@ -6147,7 +6152,7 @@
verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
- assertSameElements(networksCaptor.getValue(), networks);
+ assertSameElements(networks, networksCaptor.getValue());
List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
@@ -6352,6 +6357,77 @@
}
@Test
+ public void testNonVpnUnderlyingNetworks() throws Exception {
+ // Ensure wifi and cellular are not torn down.
+ for (int transport : new int[]{TRANSPORT_CELLULAR, TRANSPORT_WIFI}) {
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .addTransportType(transport)
+ .removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ mCm.requestNetwork(request, new NetworkCallback());
+ }
+
+ // Connect a VCN-managed wifi network.
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+ mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ mWiFiNetworkAgent.connect(true /* validated */);
+
+ final List<Network> none = List.of();
+ expectNotifyNetworkStatus(none, null); // Wifi is not the default network
+
+ // Create a virtual network based on the wifi network.
+ final int ownerUid = 10042;
+ NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .setOwnerUid(ownerUid)
+ .setAdministratorUids(new int[]{ownerUid})
+ .build();
+ final String vcnIface = "ipsec42";
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(vcnIface);
+ final TestNetworkAgentWrapper vcn = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, lp, nc);
+ vcn.setUnderlyingNetworks(List.of(mWiFiNetworkAgent.getNetwork()));
+ vcn.connect(false /* validated */);
+
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(callback);
+ callback.expectAvailableCallbacksUnvalidated(vcn);
+
+ // The underlying wifi network's capabilities are not propagated to the virtual network,
+ // but NetworkStatsService is informed of the underlying interface.
+ nc = mCm.getNetworkCapabilities(vcn.getNetwork());
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+ final List<Network> onlyVcn = List.of(vcn.getNetwork());
+ expectNotifyNetworkStatus(onlyVcn, vcnIface, ownerUid, vcnIface, List.of(WIFI_IFNAME));
+
+ // Add NOT_METERED to the underlying network, check that it is not propagated.
+ mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ callback.assertNoCallback();
+ nc = mCm.getNetworkCapabilities(vcn.getNetwork());
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+
+ // Switch underlying networks.
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ mCellNetworkAgent.connect(false /* validated */);
+ vcn.setUnderlyingNetworks(List.of(mCellNetworkAgent.getNetwork()));
+
+ // The underlying capability changes do not propagate to the virtual network, but
+ // NetworkStatsService is informed of the new underlying interface.
+ callback.assertNoCallback();
+ nc = mCm.getNetworkCapabilities(vcn.getNetwork());
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ expectNotifyNetworkStatus(onlyVcn, vcnIface, ownerUid, vcnIface, List.of(MOBILE_IFNAME));
+ }
+
+ @Test
public void testBasicDnsConfigurationPushed() throws Exception {
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
@@ -10478,13 +10554,13 @@
assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
if (add) {
- inOrder.verify(mMockNetd, times(1))
- .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
+ inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(
+ new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
+ toUidRangeStableParcels(vpnRanges), DEFAULT_NETWORK_PRIORITY_NONE));
} else {
- inOrder.verify(mMockNetd, times(1))
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
+ inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(
+ new NativeUidRangeConfig(mMockVpn.getNetwork().getNetId(),
+ toUidRangeStableParcels(vpnRanges), DEFAULT_NETWORK_PRIORITY_NONE));
}
inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
@@ -11716,14 +11792,15 @@
final boolean useAnyIdForAdd = OEM_PREF_ANY_NET_ID == addUidRangesNetId;
final boolean useAnyIdForRemove = OEM_PREF_ANY_NET_ID == removeUidRangesNetId;
- // Validate netd.
- verify(mMockNetd, times(addUidRangesTimes))
- .networkAddUidRanges(
- (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(addedUidRanges));
- verify(mMockNetd, times(removeUidRangesTimes))
- .networkRemoveUidRanges(
- (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)),
- eq(removedUidRanges));
+ // Validate that add/remove uid range (with oem priority) to/from netd.
+ verify(mMockNetd, times(addUidRangesTimes)).networkAddUidRangesParcel(argThat(config ->
+ (useAnyIdForAdd ? true : addUidRangesNetId == config.netId)
+ && Arrays.equals(addedUidRanges, config.uidRanges)
+ && DEFAULT_NETWORK_PRIORITY_OEM == config.subPriority));
+ verify(mMockNetd, times(removeUidRangesTimes)).networkRemoveUidRangesParcel(
+ argThat(config -> (useAnyIdForRemove ? true : removeUidRangesNetId == config.netId)
+ && Arrays.equals(removedUidRanges, config.uidRanges)
+ && DEFAULT_NETWORK_PRIORITY_OEM == config.subPriority));
if (shouldDestroyNetwork) {
verify(mMockNetd, times(1))
.networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
@@ -12876,8 +12953,9 @@
// rules to the correct network – in this case the system default network. The case where
// the default network for the profile happens to be the same as the system default
// is not handled specially, the rules are always active as long as a preference is set.
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
// The enterprise network is not ready yet.
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -12891,10 +12969,12 @@
mDefaultNetworkCallback.assertNoCallback();
inOrder.verify(mMockNetd).networkCreate(
nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
+ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
// Make sure changes to the work agent send callbacks to the app in the work profile, but
// not to the other apps.
@@ -12942,8 +13022,9 @@
mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
mCellNetworkAgent.disconnect();
@@ -12966,8 +13047,9 @@
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ workAgent2.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
workAgent2.setNetworkValid(true /* isStrictMode */);
workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
@@ -12975,7 +13057,7 @@
nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
&& !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inOrder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
// When the agent disconnects, test that the app on the work profile falls back to the
// default network.
@@ -13012,8 +13094,9 @@
listener.expectOnComplete();
inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
registerDefaultNetworkCallbacks();
@@ -13027,8 +13110,9 @@
mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
workAgent.disconnect();
mCellNetworkAgent.disconnect();
@@ -13072,8 +13156,9 @@
mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
r -> r.run(), listener);
listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle2),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13082,8 +13167,9 @@
mCm.setProfileNetworkPreference(testHandle4, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
r -> r.run(), listener);
listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle4));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle4),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
app4Cb.expectAvailableCallbacksValidated(workAgent);
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13092,8 +13178,9 @@
mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_DEFAULT,
r -> r.run(), listener);
listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
+ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ workAgent.getNetwork().netId, uidRangeFor(testHandle2),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
@@ -13120,15 +13207,17 @@
listener.expectOnComplete();
inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
processBroadcast(removedIntent);
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkRemoveUidRangesParcel(new NativeUidRangeConfig(
+ mCellNetworkAgent.getNetwork().netId, uidRangeFor(testHandle),
+ DEFAULT_NETWORK_PRIORITY_PROFILE));
}
/**
@@ -13377,15 +13466,17 @@
// Initial mobile data preferred uids status.
setAndUpdateMobileDataPreferredUids(Set.of());
- inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
- inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(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));
+ final NativeUidRangeConfig config1 = new NativeUidRangeConfig(cellNetId, uidRanges1,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
setAndUpdateMobileDataPreferredUids(uids1);
- inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges1);
- inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config1);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
// Set MOBILE_DATA_PREFERRED_UIDS setting again and verify that old rules are removed and
// new rules are added.
@@ -13393,17 +13484,17 @@
PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2),
SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
+ final NativeUidRangeConfig config2 = new NativeUidRangeConfig(cellNetId, uidRanges2,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
setAndUpdateMobileDataPreferredUids(uids2);
- inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges1);
- inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges2);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config1);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(config2);
// 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());
+ setAndUpdateMobileDataPreferredUids(Set.of());
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(config2);
+ inorder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
}
/**
@@ -13434,16 +13525,18 @@
// Initial mobile data preferred uids status.
setAndUpdateMobileDataPreferredUids(Set.of());
- inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
- inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkAddUidRangesParcel(any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(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));
+ final NativeUidRangeConfig wifiConfig = new NativeUidRangeConfig(wifiNetId, uidRanges,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
setAndUpdateMobileDataPreferredUids(uids);
- inorder.verify(mMockNetd, times(1)).networkAddUidRanges(wifiNetId, uidRanges);
- inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(wifiConfig);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
// Cellular network connected. mTestPackageDefaultNetworkCallback should receive
// callback with cellular network and net id and uid ranges should be updated to netd.
@@ -13455,10 +13548,12 @@
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ final NativeUidRangeConfig cellConfig = new NativeUidRangeConfig(cellNetId, uidRanges,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
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);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(wifiConfig);
// Cellular network disconnected. mTestPackageDefaultNetworkCallback should receive
// callback with wifi network from fallback request.
@@ -13468,8 +13563,8 @@
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, times(1)).networkAddUidRangesParcel(wifiConfig);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
inorder.verify(mMockNetd).networkDestroy(cellNetId);
// Cellular network comes back. mTestPackageDefaultNetworkCallback should receive
@@ -13482,10 +13577,12 @@
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
final int cellNetId2 = mCellNetworkAgent.getNetwork().netId;
+ final NativeUidRangeConfig cellConfig2 = new NativeUidRangeConfig(cellNetId2, uidRanges,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED);
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);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(cellConfig2);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(wifiConfig);
// Wifi network disconnected. mTestPackageDefaultNetworkCallback should not receive
// any callback.
@@ -13495,51 +13592,51 @@
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, never()).networkAddUidRangesParcel(any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRangesParcel(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
+ public void testMultilayerRequestsOfSetMobileDataPreferredUids() throws Exception {
+ // First set mobile data preferred uid to create a multi-layer requests: 1. request 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()
+ final NetworkCapabilities cellFilter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
- internetFactory.setScoreFilter(40);
+ final MockNetworkFactory cellFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "cellFactory", cellFilter, mCsHandlerThread);
+ cellFactory.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);
+ cellFactory.register();
+ // Default internet request and the mobile data preferred request.
+ cellFactory.expectRequestAdds(2);
+ cellFactory.assertRequestCountEquals(2);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
- // The internet factory however is outscored, and should lose its requests.
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
+ // The cellFactory however is outscored, and should lose default internet request.
+ // But it should still see mobile data preferred request.
+ cellFactory.expectRequestRemove();
+ cellFactory.assertRequestCountEquals(1);
- mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
// The network satisfying the default internet request has disconnected, so the
- // internetFactory sees the default request again.
- internetFactory.expectRequestAdds(1);
- internetFactory.assertRequestCountEquals(1);
+ // cellFactory sees the default internet requests again.
+ cellFactory.expectRequestAdd();
+ cellFactory.assertRequestCountEquals(2);
} finally {
- internetFactory.terminate();
+ cellFactory.terminate();
handlerThread.quitSafely();
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index fb6f0b6..c1059b3 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.LOST_INTERNET;
@@ -81,6 +82,8 @@
private static final String TEST_SSID = "Test SSID";
private static final String TEST_EXTRA_INFO = "extra";
+ private static final int TEST_NOTIF_ID = 101;
+ private static final String TEST_NOTIF_TAG = NetworkNotificationManager.tagFor(TEST_NOTIF_ID);
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
@@ -145,6 +148,7 @@
}
when(mResources.getStringArray(R.array.network_switch_type_name))
.thenReturn(transportNames);
+ when(mResources.getBoolean(R.bool.config_autoCancelNetworkNotifications)).thenReturn(true);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
@@ -241,57 +245,65 @@
verify(mNotificationManager, never()).notify(any(), anyInt(), any());
}
- private void assertNotification(NotificationType type, boolean ongoing) {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ private void assertNotification(NotificationType type, boolean ongoing, boolean autoCancel) {
final ArgumentCaptor<Notification> noteCaptor = ArgumentCaptor.forClass(Notification.class);
- mManager.showNotification(id, type, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(type.eventId),
+ mManager.showNotification(TEST_NOTIF_ID, type, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1)).notify(eq(TEST_NOTIF_TAG), eq(type.eventId),
noteCaptor.capture());
assertEquals("Notification ongoing flag should be " + (ongoing ? "set" : "unset"),
ongoing, (noteCaptor.getValue().flags & FLAG_ONGOING_EVENT) != 0);
+ assertEquals("Notification autocancel flag should be " + (autoCancel ? "set" : "unset"),
+ autoCancel, (noteCaptor.getValue().flags & FLAG_AUTO_CANCEL) != 0);
}
@Test
public void testDuplicatedNotificationsNoInternetThenSignIn() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
// Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
+ assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, false /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
+ assertNotification(SIGN_IN, false /* ongoing */, true /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
// Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
}
@Test
public void testOngoingSignInNotification() {
doReturn(true).when(mResources).getBoolean(R.bool.config_ongoingSignInNotification);
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
// Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
+ assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, true /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
+ assertNotification(SIGN_IN, true /* ongoing */, true /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
// Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
+ }
+
+ @Test
+ public void testNoAutoCancelNotification() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_autoCancelNetworkNotifications);
+
+ // Show NO_INTERNET, then SIGN_IN
+ assertNotification(NO_INTERNET, false /* ongoing */, false /* autoCancel */);
+ assertNotification(SIGN_IN, false /* ongoing */, false /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
+
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
}
@Test
public void testDuplicatedNotificationsSignInThenNoInternet() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ final int id = TEST_NOTIF_ID;
+ final String tag = TEST_NOTIF_TAG;
// Show first SIGN_IN
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
@@ -310,8 +322,8 @@
@Test
public void testClearNotificationByType() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ final int id = TEST_NOTIF_ID;
+ final String tag = TEST_NOTIF_TAG;
// clearNotification(int id, NotificationType notifyType) will check if given type is equal
// to previous type or not. If they are equal then clear the notification; if they are not
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index 7f923d6..8f46508 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -98,6 +98,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
@RunWith(DevSdkIgnoreRunner.class)
@@ -211,16 +212,12 @@
return packageInfo;
}
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid,
- UserHandle user) {
+ private static PackageInfo buildPackageInfo(String packageName, int uid,
+ String... permissions) {
final PackageInfo pkgInfo;
- if (hasSystemPermission) {
- pkgInfo = systemPackageInfoWithPermissions(
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- } else {
- pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
- }
- pkgInfo.applicationInfo.uid = user.getUid(UserHandle.getAppId(uid));
+ pkgInfo = systemPackageInfoWithPermissions(permissions);
+ pkgInfo.packageName = packageName;
+ pkgInfo.applicationInfo.uid = uid;
return pkgInfo;
}
@@ -606,15 +603,12 @@
@Test
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
- eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
+ List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS),
+ buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
+ buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2),
+ buildPackageInfo(SYSTEM_PACKAGE2, VPN_UID)));
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -658,13 +652,10 @@
@Test
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
- eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
+ List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+ NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS),
+ buildPackageInfo(SYSTEM_PACKAGE2, VPN_UID)));
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
mPermissionMonitor.startMonitoring();
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
@@ -901,13 +892,26 @@
new int[]{ MOCK_UID2 });
}
+ private BroadcastReceiver expectBroadcastReceiver(String... actions) {
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(),
+ argThat(filter -> {
+ for (String action : actions) {
+ if (!filter.hasAction(action)) {
+ return false;
+ }
+ }
+ return true;
+ }), any(), any());
+ return receiverCaptor.getValue();
+ }
+
@Test
public void testIntentReceiver() throws Exception {
final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
- final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
- final BroadcastReceiver receiver = receiverCaptor.getValue();
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_REMOVED);
// Verify receiving PACKAGE_ADDED intent.
final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
@@ -1061,4 +1065,136 @@
netdMonitor.expectNoPermission(
new UserHandle[]{MOCK_USER2}, new int[]{ MOCK_UID1, MOCK_UID2 });
}
+
+ @Test
+ public void testOnExternalApplicationsAvailable() throws Exception {
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+
+ // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
+ // and have different uids. There has no permission for both uids.
+ when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
+ buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2)));
+ mPermissionMonitor.startMonitoring();
+ netdMonitor.expectNoPermission(
+ new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1, MOCK_UID2});
+ netdServiceMonitor.expectPermission(
+ INetd.PERMISSION_NONE, new int[]{MOCK_UID1, MOCK_UID2});
+
+ // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
+ final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ new String[] { MOCK_PACKAGE1 , MOCK_PACKAGE2});
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, INTERNET);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2, CHANGE_NETWORK_STATE,
+ UPDATE_DEVICE_STATS);
+ receiver.onReceive(mContext, externalIntent);
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[] { MOCK_UID1 });
+ netdServiceMonitor.expectPermission(
+ INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID2});
+ }
+
+ @Test
+ public void testOnExternalApplicationsAvailable_AppsNotRegisteredOnStartMonitoring()
+ throws Exception {
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+
+ // One user MOCK_USER1
+ mPermissionMonitor.onUserAdded(MOCK_USER1);
+
+ // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
+ // and have different uids. There has no permission for both uids.
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, INTERNET);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2, CHANGE_NETWORK_STATE,
+ UPDATE_DEVICE_STATS);
+
+ // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
+ final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ new String[] { MOCK_PACKAGE1 , MOCK_PACKAGE2});
+ receiver.onReceive(mContext, externalIntent);
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[] { MOCK_UID1 });
+ netdServiceMonitor.expectPermission(
+ INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID2});
+ }
+
+ @Test
+ public void testOnExternalApplicationsAvailableWithSharedUid()
+ throws Exception {
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+
+ // Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
+ // storage and shared on MOCK_UID1. There has no permission for MOCK_UID1.
+ when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
+ buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1)));
+ mPermissionMonitor.startMonitoring();
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[] {MOCK_UID1});
+
+ // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
+ final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, UPDATE_DEVICE_STATS);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1))
+ .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
+ receiver.onReceive(mContext, externalIntent);
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(
+ INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] {MOCK_UID1});
+ }
+
+ @Test
+ public void testOnExternalApplicationsAvailableWithSharedUid_DifferentStorage()
+ throws Exception {
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+
+ // Initial the permission state. MOCK_PACKAGE1 is installed on external storage and
+ // MOCK_PACKAGE2 is installed on device. These two packages are shared on MOCK_UID1.
+ // MOCK_UID1 has NETWORK and INTERNET permissions.
+ when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
+ buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
+ INTERNET)));
+ mPermissionMonitor.startMonitoring();
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[] {MOCK_UID1});
+
+ // Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
+ final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, UPDATE_DEVICE_STATS);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
+ INTERNET);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1))
+ .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
+ receiver.onReceive(mContext, externalIntent);
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ new int[] {MOCK_UID1});
+ }
}