Merge "Downgrade DNS fail message from Error to Warning"
diff --git a/framework/aidl-export/android/net/IpPrefix.aidl b/framework/aidl-export/android/net/IpPrefix.aidl
index 0d70f2a..3495efc 100644
--- a/framework/aidl-export/android/net/IpPrefix.aidl
+++ b/framework/aidl-export/android/net/IpPrefix.aidl
@@ -18,5 +18,5 @@
package android.net;
// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
-@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// build rule).
+@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/framework/api/current.txt b/framework/api/current.txt
index ad44b27..ab290f9 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -68,6 +68,7 @@
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
@@ -297,7 +298,6 @@
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
- method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -387,7 +387,9 @@
public class NetworkRequest implements android.os.Parcelable {
method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
method public int describeContents();
+ method @NonNull public int[] getCapabilities();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method @NonNull public int[] getTransportTypes();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -405,7 +407,6 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public class ParseException extends java.lang.RuntimeException {
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 35e45ec..cd96a1b 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -120,6 +120,7 @@
}
public class NetworkRequest implements android.os.Parcelable {
+ method @NonNull public int[] getUnwantedCapabilities();
method public boolean hasUnwantedCapability(int);
}
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 1ee79a4..0a82cb7 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -219,7 +219,7 @@
method public void onAutomaticReconnectDisabled();
method public void onBandwidthUpdateRequested();
method public void onNetworkCreated();
- method public void onNetworkDisconnected();
+ method public void onNetworkDestroyed();
method public void onNetworkUnwanted();
method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
method public void onQosCallbackUnregistered(int);
@@ -238,6 +238,7 @@
method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method @Deprecated public void setLegacySubtype(int, @NonNull String);
+ method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
@@ -272,15 +273,19 @@
public final class NetworkCapabilities implements android.os.Parcelable {
method @NonNull public int[] getAdministratorUids();
+ method @Nullable public static String getCapabilityCarrierName(int);
method @Nullable public String getSsid();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @NonNull public int[] getTransportTypes();
method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+ field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
}
public static final class NetworkCapabilities.Builder {
@@ -324,6 +329,7 @@
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public final class NetworkScore implements android.os.Parcelable {
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index d196c1a..92ed7fc 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -921,6 +921,7 @@
BLOCKED_REASON_DOZE,
BLOCKED_REASON_APP_STANDBY,
BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_REASON_LOCKDOWN_VPN,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
@@ -1189,8 +1190,7 @@
*
* @return a {@link Network} object for the current default network for the
* given UID or {@code null} if no default network is currently active
- *
- * @hide
+ * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@Nullable
@@ -3140,18 +3140,27 @@
}
/**
- * Set a network-independent global http proxy. This is not normally what you want
- * for typical HTTP proxies - they are general network dependent. However if you're
- * doing something unusual like general internal filtering this may be useful. On
- * a private network where the proxy is not accessible, you may break HTTP using this.
+ * Set a network-independent global HTTP proxy.
*
- * @param p A {@link ProxyInfo} object defining the new global
- * HTTP proxy. A {@code null} value will clear the global HTTP proxy.
+ * This sets an HTTP proxy that applies to all networks and overrides any network-specific
+ * proxy. If set, HTTP libraries that are proxy-aware will use this global proxy when
+ * accessing any network, regardless of what the settings for that network are.
+ *
+ * Note that HTTP proxies are by nature typically network-dependent, and setting a global
+ * proxy is likely to break networking on multiple networks. This method is only meant
+ * for device policy clients looking to do general internal filtering or similar use cases.
+ *
+ * {@see #getGlobalProxy}
+ * {@see LinkProperties#getHttpProxy}
+ *
+ * @param p A {@link ProxyInfo} object defining the new global HTTP proxy. Calling this
+ * method with a {@code null} value will clear the global HTTP proxy.
* @hide
*/
+ // Used by Device Policy Manager to set the global proxy.
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(@Nullable ProxyInfo p) {
+ public void setGlobalProxy(@Nullable final ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -3659,7 +3668,8 @@
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
/**
- * Called when access to the specified network is blocked or unblocked.
+ * Called when access to the specified network is blocked or unblocked, or the reason for
+ * access being blocked changes.
*
* If a NetworkCallback object implements this method,
* {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
diff --git a/framework/src/android/net/INetworkAgent.aidl b/framework/src/android/net/INetworkAgent.aidl
index f9d3994..d941d4b 100644
--- a/framework/src/android/net/INetworkAgent.aidl
+++ b/framework/src/android/net/INetworkAgent.aidl
@@ -47,5 +47,5 @@
void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
void onQosCallbackUnregistered(int qosCallbackId);
void onNetworkCreated();
- void onNetworkDisconnected();
+ void onNetworkDestroyed();
}
diff --git a/framework/src/android/net/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl
index cbd6193..26cb1ed 100644
--- a/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -41,4 +41,5 @@
void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
+ void sendTeardownDelayMs(int teardownDelayMs);
}
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 6b55bb7..c57da53 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -185,6 +185,20 @@
public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
/**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current value of the teardown
+ * delay.
+ * arg1 = teardown delay in milliseconds
+ * @hide
+ */
+ public static final int EVENT_TEARDOWN_DELAY_CHANGED = BASE + 6;
+
+ /**
+ * The maximum value for the teardown delay, in milliseconds.
+ * @hide
+ */
+ public static final int MAX_TEARDOWN_DELAY_MS = 5000;
+
+ /**
* Sent by ConnectivityService to the NetworkAgent to inform the agent of the
* networks status - whether we could use the network or could not, due to
* either a bad network configuration (no internet link) or captive portal.
@@ -197,7 +211,6 @@
*/
public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
-
/**
* Network validation suceeded.
* Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
@@ -376,7 +389,7 @@
*
* @hide
*/
- public static final int CMD_NETWORK_DISCONNECTED = BASE + 23;
+ public static final int CMD_NETWORK_DESTROYED = BASE + 23;
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
@@ -581,8 +594,8 @@
onNetworkCreated();
break;
}
- case CMD_NETWORK_DISCONNECTED: {
- onNetworkDisconnected();
+ case CMD_NETWORK_DESTROYED: {
+ onNetworkDestroyed();
break;
}
}
@@ -732,8 +745,8 @@
}
@Override
- public void onNetworkDisconnected() {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DISCONNECTED));
+ public void onNetworkDestroyed() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED));
}
}
@@ -851,6 +864,29 @@
}
/**
+ * Sets the value of the teardown delay.
+ *
+ * The teardown delay is the time between when the network disconnects and when the native
+ * network corresponding to this {@code NetworkAgent} is destroyed. By default, the native
+ * network is destroyed immediately. If {@code teardownDelayMs} is non-zero, then when this
+ * network disconnects, the system will instead immediately mark the network as restricted
+ * and unavailable to unprivileged apps, but will defer destroying the native network until the
+ * teardown delay timer expires.
+ *
+ * The interfaces in use by this network will remain in use until the native network is
+ * destroyed and cannot be reused until {@link #onNetworkDestroyed()} is called.
+ *
+ * This method may be called at any time while the network is connected. It has no effect if
+ * the network is already disconnected and the teardown delay timer is running.
+ *
+ * @param teardownDelayMs the teardown delay to set, or 0 to disable teardown delay.
+ */
+ public void setTeardownDelayMs(
+ @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMs) {
+ queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMs));
+ }
+
+ /**
* Change the legacy subtype of this network agent.
*
* This is only for backward compatibility and should not be used by non-legacy network agents,
@@ -1053,7 +1089,7 @@
/**
* Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
*/
- public void onNetworkDisconnected() {}
+ public void onNetworkDestroyed() {}
/**
* Requests that the network hardware send the specified packet at the specified interval.
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 881fa8c..d39f4fb 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -274,6 +274,8 @@
NET_CAPABILITY_VEHICLE_INTERNAL,
NET_CAPABILITY_NOT_VCN_MANAGED,
NET_CAPABILITY_ENTERPRISE,
+ NET_CAPABILITY_VSIM,
+ NET_CAPABILITY_BIP,
})
public @interface NetCapability { }
@@ -493,8 +495,22 @@
*/
public static final int NET_CAPABILITY_ENTERPRISE = 29;
+ /**
+ * Indicates that this network has ability to access the carrier's Virtual Sim service.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_VSIM = 30;
+
+ /**
+ * Indicates that this network has ability to support Bearer Independent Protol.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_BIP = 31;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_BIP;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -538,43 +554,6 @@
| (1 << NET_CAPABILITY_NOT_VPN);
/**
- * Capabilities that suggest that a network is restricted.
- * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
- */
- @VisibleForTesting
- /* package */ static final long RESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_CBS)
- | (1 << NET_CAPABILITY_DUN)
- | (1 << NET_CAPABILITY_EIMS)
- | (1 << NET_CAPABILITY_FOTA)
- | (1 << NET_CAPABILITY_IA)
- | (1 << NET_CAPABILITY_IMS)
- | (1 << NET_CAPABILITY_MCX)
- | (1 << NET_CAPABILITY_RCS)
- | (1 << NET_CAPABILITY_VEHICLE_INTERNAL)
- | (1 << NET_CAPABILITY_XCAP)
- | (1 << NET_CAPABILITY_ENTERPRISE);
-
- /**
- * Capabilities that force network to be restricted.
- * {@see #maybeMarkCapabilitiesRestricted}.
- */
- private static final long FORCE_RESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_OEM_PAID)
- | (1 << NET_CAPABILITY_OEM_PRIVATE);
-
- /**
- * Capabilities that suggest that a network is unrestricted.
- * {@see #maybeMarkCapabilitiesRestricted}.
- */
- @VisibleForTesting
- /* package */ static final long UNRESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_INTERNET)
- | (1 << NET_CAPABILITY_MMS)
- | (1 << NET_CAPABILITY_SUPL)
- | (1 << NET_CAPABILITY_WIFI_P2P);
-
- /**
* Capabilities that are managed by ConnectivityService.
*/
private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
@@ -749,6 +728,23 @@
return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
}
+ /**
+ * Get the name of the given capability that carriers use.
+ * If the capability does not have a carrier-name, returns null.
+ *
+ * @param capability The capability to get the carrier-name of.
+ * @return The carrier-name of the capability, or null if it doesn't exist.
+ * @hide
+ */
+ @SystemApi
+ public static @Nullable String getCapabilityCarrierName(@NetCapability int capability) {
+ if (capability == NET_CAPABILITY_ENTERPRISE) {
+ return capabilityNameOf(capability);
+ } else {
+ return null;
+ }
+ }
+
private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
final long unwantedCaps =
@@ -811,37 +807,12 @@
}
/**
- * Deduces that all the capabilities it provides are typically provided by restricted networks
- * or not.
- *
- * @return {@code true} if the network should be restricted.
- * @hide
- */
- public boolean deduceRestrictedCapability() {
- // Check if we have any capability that forces the network to be restricted.
- final boolean forceRestrictedCapability =
- (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
-
- // Verify there aren't any unrestricted capabilities. If there are we say
- // the whole thing is unrestricted unless it is forced to be restricted.
- final boolean hasUnrestrictedCapabilities =
- (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;
-
- // Must have at least some restricted capabilities.
- final boolean hasRestrictedCapabilities =
- (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
-
- return forceRestrictedCapability
- || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities);
- }
-
- /**
- * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted.
+ * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if inferring the network is restricted.
*
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
- if (deduceRestrictedCapability()) {
+ if (NetworkCapabilitiesUtils.inferRestrictedCapability(this)) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
@@ -2163,6 +2134,8 @@
case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL";
case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED";
case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE";
+ case NET_CAPABILITY_VSIM: return "VSIM";
+ case NET_CAPABILITY_BIP: return "BIP";
default: return Integer.toString(capability);
}
}
@@ -2390,9 +2363,15 @@
/**
* Gets the subscription ID set that associated to this network or request.
+ *
+ * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
+ * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
+ *
* @return
+ * @hide
*/
@NonNull
+ @SystemApi
public Set<Integer> getSubIds() {
return new ArraySet<>(mSubIds);
}
@@ -2757,10 +2736,17 @@
/**
* Set the subscription ID set.
*
+ * <p>SubIds are populated in NetworkCapability instances from the system only for callers
+ * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
+ * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds a set that represent the subscription IDs. Empty if clean up.
* @return this builder.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull final Set<Integer> subIds) {
mCaps.setSubIds(subIds);
return this;
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index bcbc04f7..5d40417 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -501,9 +501,14 @@
* A network will satisfy this request only if it matches one of the subIds in this set.
* An empty set matches all networks, including those without a subId.
*
+ * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds A {@code Set} that represents subscription IDs.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull Set<Integer> subIds) {
mNetworkCapabilities.setSubIds(subIds);
return this;
@@ -699,4 +704,43 @@
public int hashCode() {
return Objects.hash(requestId, legacyType, networkCapabilities, type);
}
+
+ /**
+ * Gets all the capabilities set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of capability values for this instance.
+ */
+ @NonNull
+ public @NetCapability int[] getCapabilities() {
+ // No need to make a defensive copy here as NC#getCapabilities() already returns
+ // a new array.
+ return networkCapabilities.getCapabilities();
+ }
+
+ /**
+ * Gets all the unwanted capabilities set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of unwanted capability values for this instance.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public @NetCapability int[] getUnwantedCapabilities() {
+ // No need to make a defensive copy here as NC#getUnwantedCapabilities() already returns
+ // a new array.
+ return networkCapabilities.getUnwantedCapabilities();
+ }
+
+ /**
+ * Gets all the transports set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of transport type values for this instance.
+ */
+ @NonNull
+ public @Transport int[] getTransportTypes() {
+ // No need to make a defensive copy here as NC#getTransportTypes() already returns
+ // a new array.
+ return networkCapabilities.getTransportTypes();
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0c42585..629006a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -318,6 +318,9 @@
// The maximum number of network request allowed per uid before an exception is thrown.
private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+ // The maximum number of network request allowed for system UIDs before an exception is thrown.
+ private static final int MAX_NETWORK_REQUESTS_PER_SYSTEM_UID = 250;
+
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
@VisibleForTesting
@@ -333,6 +336,7 @@
protected final PermissionMonitor mPermissionMonitor;
private final PerUidCounter mNetworkRequestCounter;
+ private final PerUidCounter mSystemNetworkRequestCounter;
private volatile boolean mLockdownEnabled;
@@ -1201,6 +1205,7 @@
mContext = Objects.requireNonNull(context, "missing Context");
mResources = deps.getResources(mContext);
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
+ mSystemNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
@@ -1276,14 +1281,22 @@
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+ mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
// Listen for user add/removes to inform PermissionMonitor.
// Should run on mHandler to avoid any races.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ final IntentFilter userIntentFilter = new IntentFilter();
+ userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+ userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mUserAllContext.registerReceiver(mUserIntentReceiver, userIntentFilter,
+ null /* broadcastPermission */, mHandler);
- mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+ // Listen to package add/removes for netd
+ final IntentFilter packageIntentFilter = new IntentFilter();
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ packageIntentFilter.addDataScheme("package");
+ mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
null /* broadcastPermission */, mHandler);
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
@@ -1551,16 +1564,16 @@
mNetworkInfoBlockingLogs.log(action + " " + uid);
}
- private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net,
- boolean blocked) {
+ private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net, int blocked) {
if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
return;
}
- final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ final String action = (blocked != 0) ? "BLOCKED" : "UNBLOCKED";
final int requestId = nri.getActiveRequest() != null
? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId()));
+ "%s %d(%d) on netId %d: %s", action, nri.mAsUid, requestId, net.getNetId(),
+ blockedReasonsToString(blocked)));
}
/**
@@ -1890,6 +1903,10 @@
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
newNc.setAdministratorUids(new int[0]);
+ if (!checkAnyPermissionOf(
+ callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
+ newNc.setSubIds(Collections.emptySet());
+ }
return newNc;
}
@@ -3122,6 +3139,13 @@
}
break;
}
+ case NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED: {
+ if (msg.arg1 >= 0 && msg.arg1 <= NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
+ nai.teardownDelayMs = msg.arg1;
+ } else {
+ logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
+ }
+ }
}
}
@@ -3692,6 +3716,23 @@
mLegacyTypeTracker.remove(nai, wasDefault);
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
+
+ // Immediate teardown.
+ if (nai.teardownDelayMs == 0) {
+ destroyNetwork(nai);
+ return;
+ }
+
+ // Delayed teardown.
+ try {
+ mNetd.networkSetPermissionForNetwork(nai.network.netId, INetd.PERMISSION_SYSTEM);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error marking network restricted during teardown: " + e);
+ }
+ mHandler.postDelayed(() -> destroyNetwork(nai), nai.teardownDelayMs);
+ }
+
+ private void destroyNetwork(NetworkAgentInfo nai) {
if (nai.created) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
@@ -3704,7 +3745,7 @@
mDnsManager.removeNetwork(nai.network);
}
mNetIdManager.releaseNetId(nai.network.getNetId());
- nai.onNetworkDisconnected();
+ nai.onNetworkDestroyed();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -4005,7 +4046,7 @@
}
}
}
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ nri.decrementRequestCount();
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
@@ -4116,6 +4157,12 @@
}
}
+ private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
+ return checkAnyPermissionOf(
+ nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ ? mSystemNetworkRequestCounter : mNetworkRequestCounter;
+ }
+
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4919,7 +4966,7 @@
}
@Override
- public void setGlobalProxy(final ProxyInfo proxyProperties) {
+ public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
PermissionUtils.enforceNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -5264,14 +5311,14 @@
}
}
- private void onUserAdded(UserHandle user) {
+ private void onUserAdded(@NonNull final UserHandle user) {
mPermissionMonitor.onUserAdded(user);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
}
}
- private void onUserRemoved(UserHandle user) {
+ private void onUserRemoved(@NonNull final UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
// If there was a network preference for this user, remove it.
handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
@@ -5281,7 +5328,18 @@
}
}
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private void onPackageChanged(@NonNull final String packageName) {
+ // This is necessary in case a package is added or removed, but also when it's replaced to
+ // run as a new UID by its manifest rules. Also, if a separate package shares the same UID
+ // as one in the preferences, then it should follow the same routing as that other package,
+ // which means updating the rules is never to be needed in this case (whether it joins or
+ // leaves a UID with a preference).
+ if (isMappedInOemNetworkPreference(packageName)) {
+ handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+ }
+ }
+
+ private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ensureRunningOnConnectivityServiceThread();
@@ -5304,6 +5362,22 @@
}
};
+ private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ensureRunningOnConnectivityServiceThread();
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ case Intent.ACTION_PACKAGE_REMOVED:
+ case Intent.ACTION_PACKAGE_REPLACED:
+ onPackageChanged(intent.getData().getSchemeSpecificPart());
+ break;
+ default:
+ Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
+ }
+ }
+ };
+
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
@@ -5414,6 +5488,9 @@
@Nullable
final String mCallingAttributionTag;
+ // Counter keeping track of this NRI.
+ final PerUidCounter mPerUidCounter;
+
// Effective UID of this request. This is different from mUid when a privileged process
// files a request on behalf of another UID. This UID is used to determine blocked status,
// UID matching, and so on. mUid above is used for permission checks and to enforce the
@@ -5464,7 +5541,8 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mAsUid = asUid;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -5496,15 +5574,11 @@
mUid = mDeps.getCallingUid();
mAsUid = asUid;
mPendingIntent = null;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
-
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
+ linkDeathRecipient();
}
NetworkRequestInfo(@NonNull final NetworkRequestInfo nri,
@@ -5539,9 +5613,11 @@
mUid = nri.mUid;
mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ linkDeathRecipient();
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
@@ -5570,8 +5646,22 @@
return Collections.unmodifiableList(tempRequests);
}
+ void decrementRequestCount() {
+ mPerUidCounter.decrementCount(mUid);
+ }
+
+ void linkDeathRecipient() {
+ if (null != mBinder) {
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+ }
+
void unlinkDeathRecipient() {
- if (mBinder != null) {
+ if (null != mBinder) {
mBinder.unlinkToDeath(this, 0);
}
}
@@ -5617,6 +5707,10 @@
"Insufficient permissions to request a specific signal strength");
}
mAppOpsManager.checkPackage(callerUid, callerPackageName);
+
+ if (!nc.getSubIds().isEmpty()) {
+ enforceNetworkFactoryPermission();
+ }
}
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
@@ -6107,6 +6201,15 @@
@NonNull
private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
+ /**
+ * Determine whether a given package has a mapping in the current OemNetworkPreferences.
+ * @param packageName the package name to check existence of a mapping for.
+ * @return true if a mapping exists, false otherwise
+ */
+ private boolean isMappedInOemNetworkPreference(@NonNull final String packageName) {
+ return mOemNetworkPreferences.getNetworkPreferences().containsKey(packageName);
+ }
+
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@VisibleForTesting
@@ -6127,7 +6230,7 @@
* @return the NetworkRequestInfo tracking the given uid.
*/
@NonNull
- private NetworkRequestInfo getDefaultRequestTrackingUid(@NonNull final int uid) {
+ private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
if (nri == mDefaultRequest) {
continue;
@@ -6253,8 +6356,8 @@
// Request used to optionally keep vehicle internal network always active
private final NetworkRequest mDefaultVehicleRequest;
- // TODO replace with INetd.DUMMY_NET_ID when available.
- private static final int NO_SERVICE_NET_ID = 51;
+ // TODO replace with INetd.UNREACHABLE_NET_ID when available.
+ private static final int NO_SERVICE_NET_ID = 52;
// Sentinel NAI used to direct apps with default networks that should have no connectivity to a
// network with no service. This NAI should never be matched against, nor should any public API
// ever return the associated network. For this reason, this NAI is not in the list of available
@@ -6574,7 +6677,7 @@
mDeps.reportNetworkInterfaceForTransports(mContext, iface,
caps.getTransportTypes());
} catch (Exception e) {
- loge("Exception adding interface: " + e);
+ logw("Exception adding interface: " + e);
}
}
}
@@ -7348,7 +7451,7 @@
break;
}
case ConnectivityManager.CALLBACK_BLK_CHANGED: {
- maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1 != 0);
+ maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1);
msg.arg1 = arg1;
break;
}
@@ -8724,7 +8827,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ nri.decrementRequestCount();
return;
}
@@ -8790,7 +8893,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ nri.decrementRequestCount();
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -9366,14 +9469,8 @@
throw new IllegalArgumentException("Must explicitly specify a user handle ("
+ "UserHandle.CURRENT not supported)");
}
- final UserManager um;
- try {
- um = mContext.createContextAsUser(profile, 0 /* flags */)
- .getSystemService(UserManager.class);
- } catch (IllegalStateException e) {
- throw new IllegalArgumentException("Profile does not exist");
- }
- if (!um.isManagedProfile()) {
+ final UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.isManagedProfile(profile.getIdentifier())) {
throw new IllegalArgumentException("Profile must be a managed profile");
}
// Strictly speaking, mOemNetworkPreferences should only be touched on the
@@ -9540,7 +9637,6 @@
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
mOemNetworkPreferences = preference;
- // TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
try {
@@ -9697,7 +9793,6 @@
// 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.
- // TODO b/177092163 add app install watching.
continue;
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 97df5bf..ee32fbf 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -201,6 +201,9 @@
// Set to true when partial connectivity was detected.
public boolean partialConnectivity;
+ // Delay between when the network is disconnected and when the native network is destroyed.
+ public int teardownDelayMs;
+
// Captive portal info of the network from RFC8908, if any.
// Obtained by ConnectivityService and merged into NetworkAgent-provided information.
public CaptivePortalData capportApiData;
@@ -589,13 +592,13 @@
}
/**
- * Notify the NetworkAgent that the network is disconnected and destroyed.
+ * Notify the NetworkAgent that the native network has been destroyed.
*/
- public void onNetworkDisconnected() {
+ public void onNetworkDestroyed() {
try {
- networkAgent.onNetworkDisconnected();
+ networkAgent.onNetworkDestroyed();
} catch (RemoteException e) {
- Log.e(TAG, "Error sending network disconnected event", e);
+ Log.e(TAG, "Error sending network destroyed event", e);
}
}
@@ -675,6 +678,12 @@
@QosCallbackException.ExceptionType final int exceptionType) {
mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
}
+
+ @Override
+ public void sendTeardownDelayMs(int teardownDelayMs) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
+ teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+ }
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5e6b9f3..2e51be3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -36,7 +36,7 @@
import android.util.Pair;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
import libcore.io.IoUtils;
@@ -446,7 +446,7 @@
int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
throws ErrnoException, IOException {
final int oldTag = TrafficStats.getAndSetThreadStatsTag(
- TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ NetworkStackConstants.TAG_SYSTEM_PROBE);
try {
mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
} finally {
@@ -745,7 +745,7 @@
if (ensureMeasurementNecessary()) return;
// No need to restore the tag, since this thread is only used for this measurement.
- TrafficStats.getAndSetThreadStatsTag(TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ TrafficStats.getAndSetThreadStatsTag(NetworkStackConstants.TAG_SYSTEM_PROBE);
try (SSLSocket sslSocket = setupSSLSocket()) {
sendDoTProbe(sslSocket);
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1f50e31..e7718b5 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -38,14 +38,12 @@
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
import static android.os.Process.INVALID_UID;
import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
@@ -103,20 +101,6 @@
@Test
public void testMaybeMarkCapabilitiesRestricted() {
- // verify EIMS is restricted
- assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_EIMS));
-
- // verify CBS is also restricted
- assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_CBS));
-
- // verify default is not restricted
- assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
-
- // just to see
- assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
-
// check that internet does not get restricted
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -985,26 +969,6 @@
assertNotEquals(-50, nc.getSignalStrength());
}
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDeduceRestrictedCapability() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // Default capabilities don't have restricted capability.
- assertFalse(nc.deduceRestrictedCapability());
- // If there is a force restricted capability, then the network capabilities is restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, if there is any unrestricted capability in
- // capabilities, then the network capabilities is not restricted.
- nc.removeCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_CBS);
- assertFalse(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, the network capabilities will only be treated
- // as restricted when there is no any unrestricted capability.
- nc.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- }
-
private void assertNoTransport(NetworkCapabilities nc) {
for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
assertFalse(nc.hasTransport(i));
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index f5a4234..db18500 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -37,6 +37,7 @@
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<!-- Reading DeviceConfig flags -->
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<application android:debuggable="true">
<uses-library android:name="android.test.runner"/>
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 10b2f1e..daf4e61 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,7 +18,12 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_PACKAGE_REPLACED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
@@ -31,6 +36,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
@@ -575,6 +581,7 @@
final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
.getSystemService(UserManager.class);
doReturn(value).when(umMock).isManagedProfile();
+ doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
}
@Override
@@ -715,6 +722,9 @@
private int mProbesSucceeded;
private String mNmValidationRedirectUrl = null;
private boolean mNmProvNotificationRequested = false;
+ private Runnable mCreatedCallback;
+ private Runnable mUnwantedCallback;
+ private Runnable mDisconnectedCallback;
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
// Contains the redirectUrl from networkStatus(). Before reading, wait for
@@ -769,6 +779,24 @@
mRedirectUrl = redirectUrl;
mNetworkStatusReceived.open();
}
+
+ @Override
+ public void onNetworkCreated() {
+ super.onNetworkCreated();
+ if (mCreatedCallback != null) mCreatedCallback.run();
+ }
+
+ @Override
+ public void onNetworkUnwanted() {
+ super.onNetworkUnwanted();
+ if (mUnwantedCallback != null) mUnwantedCallback.run();
+ }
+
+ @Override
+ public void onNetworkDestroyed() {
+ super.onNetworkDestroyed();
+ if (mDisconnectedCallback != null) mDisconnectedCallback.run();
+ }
};
assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
@@ -970,6 +998,18 @@
p.timestampMillis = DATA_STALL_TIMESTAMP;
mNmCallbacks.notifyDataStallSuspected(p);
}
+
+ public void setCreatedCallback(Runnable r) {
+ mCreatedCallback = r;
+ }
+
+ public void setUnwantedCallback(Runnable r) {
+ mUnwantedCallback = r;
+ }
+
+ public void setDisconnectedCallback(Runnable r) {
+ mDisconnectedCallback = r;
+ }
}
/**
@@ -1373,10 +1413,21 @@
}
private void mockUidNetworkingBlocked() {
- doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
+ doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
}
+ private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
+ final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
+ if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
+ return true;
+ }
+ if (meteredNetwork) {
+ return blockedReasons != BLOCKED_REASON_NONE;
+ }
+ return false;
+ }
+
private void setBlockedReasonChanged(int blockedReasons) {
mBlockedReasons = blockedReasons;
mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
@@ -2438,8 +2489,7 @@
public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
doNetworkCallbacksSanitizationTest(true /* sanitized */);
}
@@ -2447,7 +2497,7 @@
public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_GRANTED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
doNetworkCallbacksSanitizationTest(false /* sanitized */);
}
@@ -2455,7 +2505,7 @@
public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
doNetworkCallbacksSanitizationTest(false /* sanitized */);
}
@@ -2746,10 +2796,14 @@
}
private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- final String myPackageName = mContext.getPackageName();
- when(mPackageManager.getPackageInfo(eq(myPackageName), eq(GET_PERMISSIONS)))
+ grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
+ }
+
+ private void grantUsingBackgroundNetworksPermissionForUid(
+ final int uid, final String packageName) throws Exception {
+ when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
.thenReturn(buildPackageInfo(true, uid));
- mService.mPermissionMonitor.onPackageAdded(myPackageName, uid);
+ mService.mPermissionMonitor.onPackageAdded(packageName, uid);
}
@Test
@@ -2799,6 +2853,94 @@
}
@Test
+ public void testNetworkAgentCallbacks() throws Exception {
+ // Keeps track of the order of events that happen in this test.
+ final LinkedBlockingQueue<String> eventOrder = new LinkedBlockingQueue<>();
+
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+ // Expectations for state when various callbacks fire. These expectations run on the handler
+ // thread and not on the test thread because they need to prevent the handler thread from
+ // advancing while they examine state.
+
+ // 1. When onCreated fires, netd has been told to create the network.
+ mWiFiNetworkAgent.setCreatedCallback(() -> {
+ eventOrder.offer("onNetworkCreated");
+ wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
+ assertNotNull(wifiNetwork.get());
+ try {
+ verify(mMockNetd).networkCreatePhysical(wifiNetwork.get().getNetId(),
+ INetd.PERMISSION_NONE);
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ });
+
+ // 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
+ // check that it is fired at some point after disconnect.
+ mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
+
+ // 3. While the teardown timer is running, connectivity APIs report the network is gone, but
+ // netd has not yet been told to destroy it.
+ final Runnable duringTeardown = () -> {
+ eventOrder.offer("timePasses");
+ assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ try {
+ verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ };
+
+ // 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
+ // and netd has been told to destroy it.
+ mWiFiNetworkAgent.setDisconnectedCallback(() -> {
+ eventOrder.offer("onNetworkDisconnected");
+ assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ try {
+ verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ });
+
+ // Connect a network, and file a request for it after it has come up, to ensure the nascent
+ // timer is cleared and the test does not have to wait for it. Filing the request after the
+ // network has come up is necessary because ConnectivityService does not appear to clear the
+ // nascent timer if the first request satisfied by the network was filed before the network
+ // connected.
+ // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
+ mWiFiNetworkAgent.connectWithoutInternet();
+ waitForIdle();
+ mCm.requestNetwork(request, callback);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Set teardown delay and make sure CS has processed it.
+ mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMs(300);
+ waitForIdle();
+
+ // Post the duringTeardown lambda to the handler so it fires while teardown is in progress.
+ // The delay must be long enough it will run after the unregisterNetworkCallback has torn
+ // down the network and started the teardown timer, and short enough that the lambda is
+ // scheduled to run before the teardown timer.
+ final Handler h = new Handler(mCsHandlerThread.getLooper());
+ h.postDelayed(duringTeardown, 150);
+
+ // Disconnect the network and check that events happened in the right order.
+ mCm.unregisterNetworkCallback(callback);
+ assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ mCm.unregisterNetworkCallback(callback);
+ }
+
+ @Test
public void testExplicitlySelected() throws Exception {
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -3439,8 +3581,7 @@
@Test
public void testCaptivePortalApi() throws Exception {
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3474,8 +3615,7 @@
private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
// Grant NETWORK_SETTINGS permission to be able to receive LinkProperties change callbacks
// with sensitive (captive portal) data
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3909,8 +4049,7 @@
@Test
public void testRegisterDefaultNetworkCallback() throws Exception {
// NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -4069,8 +4208,7 @@
() -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler));
callback.assertNoCallback();
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mCm.registerSystemDefaultNetworkCallback(callback, handler);
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCm.unregisterNetworkCallback(callback);
@@ -5391,10 +5529,11 @@
}
@Test
- public void testNetworkCallbackMaximum() {
+ public void testNetworkCallbackMaximum() throws Exception {
final int MAX_REQUESTS = 100;
final int CALLBACKS = 89;
final int INTENTS = 11;
+ final int SYSTEM_ONLY_MAX_REQUESTS = 250;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
@@ -5443,6 +5582,33 @@
new Intent("d"), FLAG_IMMUTABLE))
);
+ // The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
+ final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+ ArrayList<NetworkCallback> systemRegistered = new ArrayList<>();
+ for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) {
+ NetworkCallback cb = new NetworkCallback();
+ if (i % 2 == 0) {
+ mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, cb, handler);
+ } else {
+ mCm.registerNetworkCallback(networkRequest, cb);
+ }
+ systemRegistered.add(cb);
+ }
+ waitForIdle();
+
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(1001042, new NetworkCallback(),
+ handler));
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerNetworkCallback(networkRequest, new NetworkCallback()));
+
+ for (NetworkCallback callback : systemRegistered) {
+ mCm.unregisterNetworkCallback(callback);
+ }
+ waitForIdle(); // Wait for requests to be unregistered before giving up the permission.
+ });
+
for (Object o : registered) {
if (o instanceof NetworkCallback) {
mCm.unregisterNetworkCallback((NetworkCallback)o);
@@ -5469,6 +5635,30 @@
waitForIdle();
for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ waitForIdle();
+
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ waitForIdle();
+
+ withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, networkCallback,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ });
+ waitForIdle();
+
+ for (int i = 0; i < MAX_REQUESTS; i++) {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
mCm.requestNetwork(networkRequest, pendingIntent);
@@ -6461,8 +6651,7 @@
@Test
public void testVpnNetworkActive() throws Exception {
// NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final int uid = Process.myUid();
@@ -6954,8 +7143,7 @@
@Test
public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
// NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7041,8 +7229,7 @@
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
// Necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7530,8 +7717,7 @@
Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback callback = new TestNetworkCallback();
final NetworkRequest request = new NetworkRequest.Builder()
@@ -7767,8 +7953,7 @@
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
// For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -7957,12 +8142,12 @@
assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+ b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
b1.expectBroadcast();
callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
- b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
mMockVpn.expectStopVpnRunnerPrivileged();
callback.expectCallback(CallbackEntry.LOST, mMockVpn);
b2.expectBroadcast();
@@ -8898,8 +9083,7 @@
private void denyAllLocationPrivilegedPermissions() {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
@@ -9155,7 +9339,7 @@
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
throws Exception {
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
@@ -10078,6 +10262,12 @@
.thenReturn(applicationInfo);
}
+ private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+ throws Exception {
+ when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException(packageName));
+ }
+
private void mockHasSystemFeature(@NonNull final String featureName,
@NonNull final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName)))
@@ -10474,8 +10664,7 @@
private void registerDefaultNetworkCallbacks() {
// Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
mProfileDefaultNetworkCallback = new TestNetworkCallback();
@@ -10485,8 +10674,7 @@
registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
TEST_WORK_PROFILE_APP_UID);
// TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
}
private void unregisterDefaultNetworkCallbacks() {
@@ -10536,15 +10724,23 @@
@NonNull final UidRangeParcel[] uidRanges,
@NonNull final String testPackageName)
throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
// These tests work off a single UID therefore using 'start' is valid.
mockGetApplicationInfo(testPackageName, uidRanges[0].start);
+ setOemNetworkPreference(networkPrefToSetup, testPackageName);
+ }
+
+ private void setOemNetworkPreference(final int networkPrefToSetup,
+ @NonNull final String... testPackageNames)
+ throws Exception {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
// Build OemNetworkPreferences object
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(testPackageName, networkPrefToSetup)
- .build();
+ final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
+ for (final String packageName : testPackageNames) {
+ builder.addNetworkPreference(packageName, networkPrefToSetup);
+ }
+ final OemNetworkPreferences pref = builder.build();
// Act on ConnectivityService.setOemNetworkPreference()
final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
@@ -10641,7 +10837,7 @@
defaultNetworkCallback.assertNoCallback();
final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ withPermission(NETWORK_SETTINGS, () ->
mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
new Handler(ConnectivityThread.getInstanceLooper())));
@@ -10689,7 +10885,7 @@
defaultNetworkCallback.assertNoCallback();
final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ withPermission(NETWORK_SETTINGS, () ->
mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
new Handler(ConnectivityThread.getInstanceLooper())));
@@ -10731,7 +10927,7 @@
defaultNetworkCallback.assertNoCallback();
final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ withPermission(NETWORK_SETTINGS, () ->
mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
new Handler(ConnectivityThread.getInstanceLooper())));
@@ -11143,8 +11339,7 @@
// Arrange PackageManager mocks
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
final UidRangeParcel[] uidRangesSingleUser =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
@@ -11191,6 +11386,84 @@
false /* shouldDestroyNetwork */);
}
+ @Test
+ public void testMultilayerForPackageChangesEvaluatesCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final String packageScheme = "package:";
+
+ // Arrange PackageManager mocks
+ final String packageToInstall = "package.to.install";
+ final int packageToInstallUid = 81387;
+ final UidRangeParcel[] uidRangesSinglePackage =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
+
+ // Verify the starting state. No networks should be connected.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly add the expected values for installed packages.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to recognize the package to be installed
+ mockGetApplicationInfo(packageToInstall, packageToInstallUid);
+ final UidRangeParcel[] uidRangesAllPackages =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
+
+ // Send a broadcast indicating a package was installed.
+ final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
+ addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(addedIntent);
+
+ // Test the single package is removed and the combined packages are added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to no longer recognize the package to be installed
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+
+ // Send a broadcast indicating a package was removed.
+ final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
+ removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(removedIntent);
+
+ // Test the combined packages are removed and the single package is added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to change the installed package's uid
+ final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
+ final UidRangeParcel[] uidRangesReplacedPackage =
+ toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
+
+ // Send a broadcast indicating a package was replaced.
+ final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
+ replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
+ processBroadcast(replacedIntent);
+
+ // Test the original uid is removed and is replaced with the new uid.
+ verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+ }
+
/**
* Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
@@ -12013,4 +12286,68 @@
mCm.setProfileNetworkPreference(testHandle,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
+
+ @Test
+ public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(Collections.singleton(Process.myUid()));
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertTrue(result.getSubIds().isEmpty());
+ }
+
+ @Test
+ public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+
+ final Set<Integer> subIds = Collections.singleton(Process.myUid());
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(subIds);
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertEquals(subIds, result.getSubIds());
+ }
+
+ private NetworkRequest getRequestWithSubIds() {
+ return new NetworkRequest.Builder()
+ .setSubIds(Collections.singleton(Process.myUid()))
+ .build();
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+ final NetworkCallback networkCallback1 = new NetworkCallback();
+ final NetworkCallback networkCallback2 = new NetworkCallback();
+
+ mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
+ mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
+ mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
+
+ mCm.unregisterNetworkCallback(networkCallback1);
+ mCm.releaseNetworkRequest(pendingIntent);
+ mCm.unregisterNetworkCallback(networkCallback2);
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+
+ final Class<SecurityException> expected = SecurityException.class;
+ assertThrows(
+ expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
+ assertThrows(
+ expected,
+ () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 8c5d1d6..8b072c4 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -22,7 +22,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -56,6 +58,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -80,6 +83,12 @@
IpConnectivityMetrics mService;
NetdEventListenerService mNetdListener;
+ private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
@Before
public void setUp() {
@@ -263,14 +272,6 @@
// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
ApfStats apfStats = new ApfStats.Builder()
.setDurationMs(45000)
.setReceivedRas(10)
@@ -584,11 +585,21 @@
return buffer.toString();
}
- void connectEvent(int netid, int error, int latencyMs, String ipAddr) throws Exception {
- mNetdListener.onConnectEvent(netid, error, latencyMs, ipAddr, 80, 1);
+ private void setCapabilities(int netId) {
+ final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+ networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+ netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+ }
+
+ void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
+ setCapabilities(netId);
+ mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
}
void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+ setCapabilities(netId);
mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 8ccea1a..50aaaee 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -23,8 +23,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -42,6 +43,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
@@ -61,18 +63,16 @@
NetdEventListenerService mService;
ConnectivityManager mCm;
+ private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
@Before
public void setUp() {
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
mCm = mock(ConnectivityManager.class);
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
mService = new NetdEventListenerService(mCm);
}
@@ -470,7 +470,16 @@
assertEquals(want, got);
}
+ private void setCapabilities(int netId) {
+ final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+ networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+ netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+ }
+
Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
+ setCapabilities(netId);
return new Thread(() -> {
try {
mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
@@ -481,6 +490,7 @@
}
void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+ setCapabilities(netId);
mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}